commit 63d8054ba995629b3ce25b7522c55d536431b475 Author: zhangshengli <1810377322@163.com> Date: Wed Jul 10 17:47:46 2024 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ruoyi-vue-pro-master/.gitee/ISSUE_TEMPLATE.zh-CN.md b/ruoyi-vue-pro-master/.gitee/ISSUE_TEMPLATE.zh-CN.md new file mode 100644 index 0000000..06e3de7 --- /dev/null +++ b/ruoyi-vue-pro-master/.gitee/ISSUE_TEMPLATE.zh-CN.md @@ -0,0 +1,25 @@ +碰到问题,请在 搜索是否存在相似的 issue。 + +不按照模板提交的 issue,会被系统自动删除。 + +### 基本信息 + +- ruoyi-vue-pro 版本: +- 操作系统: +- 数据库: + +### 你猜测可能的原因 + +(必填)我花费了 2-4 小时自查,发现可能的原因是:xxxxxx + +### 复现步骤 + +第一步, + +第二步, + +第三步, + +### 报错信息 + +带上必要的截图 diff --git a/ruoyi-vue-pro-master/.github/ISSUE_TEMPLATE/question.md b/ruoyi-vue-pro-master/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..6ed00a3 --- /dev/null +++ b/ruoyi-vue-pro-master/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,34 @@ +--- +name: 问题反馈 +about: 请详细描述,以便更高快的获得到解决 +title: '' +labels: '' +assignees: '' + +--- + +碰到问题,请在 搜索是否存在相似的 issue。 + +不按照模板提交的 issue,会被系统自动删除。 + +### 基本信息 + +- ruoyi-vue-pro 版本: +- 操作系统: +- 数据库: + +### 你猜测可能的原因 + +(必填)我花费了 2-4 小时自查,发现可能的原因是:xxxxxx + +### 复现步骤 + +第一步, + +第二步, + +第三步, + +### 报错信息 + +带上必要的截图 diff --git a/ruoyi-vue-pro-master/.github/workflows/maven.yml b/ruoyi-vue-pro-master/.github/workflows/maven.yml new file mode 100644 index 0000000..7c76592 --- /dev/null +++ b/ruoyi-vue-pro-master/.github/workflows/maven.yml @@ -0,0 +1,30 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: [ master ] + # pull_request: + # branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + java: [ '8', '11', '17' ] + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.Java }} + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml -Dmaven.test.skip=true diff --git a/ruoyi-vue-pro-master/.github/workflows/yudao-ui-admin.yml b/ruoyi-vue-pro-master/.github/workflows/yudao-ui-admin.yml new file mode 100644 index 0000000..a42a8f6 --- /dev/null +++ b/ruoyi-vue-pro-master/.github/workflows/yudao-ui-admin.yml @@ -0,0 +1,51 @@ +name: yudao-ui-admin CI + +# 在master分支发生push事件时触发。 +on: + push: + branches: [ master ] + # pull_request: + # branches: [ master ] +env: # 设置环境变量 + TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间) + WORK_DIR: yudao-ui-admin #工作目录 + +defaults: + run: + shell: bash + working-directory: yudao-ui-admin + +jobs: + build: # 自定义名称 + runs-on: ubuntu-latest # 运行在虚拟机环境ubuntu-latest + + strategy: + matrix: + node_version: [14.x, 16.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - name: Checkout # 步骤1 + uses: actions/checkout@v2 # 使用的动作。格式:userName/repoName。作用:检出仓库,获取源码。 官方actions库:https://github.com/actions + + - name: Install pnpm + uses: pnpm/action-setup@v2.0.1 + with: + version: 6.15.1 + + - name: Set node version to ${{ matrix.node_version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node_version }} + cache: "yarn" + cache-dependency-path: yudao-ui-admin/yarn.lock + + - name: Install deps + run: node --version && yarn --version && yarn install + + - name: Build + run: yarn build:prod + + # 查看 workflow 的文档来获取更多信息 + # @see https://github.com/crazy-max/ghaction-github-pages + diff --git a/ruoyi-vue-pro-master/.gitignore b/ruoyi-vue-pro-master/.gitignore new file mode 100644 index 0000000..09ec363 --- /dev/null +++ b/ruoyi-vue-pro-master/.gitignore @@ -0,0 +1,53 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +.flattened-pom.xml + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml + +### JRebel ### +rebel.xml + +application-my.yaml + +/yudao-ui-app/unpackage/ diff --git a/ruoyi-vue-pro-master/.image/Java监控.jpg b/ruoyi-vue-pro-master/.image/Java监控.jpg new file mode 100644 index 0000000..6ad522a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/Java监控.jpg differ diff --git a/ruoyi-vue-pro-master/.image/MySQL.jpg b/ruoyi-vue-pro-master/.image/MySQL.jpg new file mode 100644 index 0000000..64a1940 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/MySQL.jpg differ diff --git a/ruoyi-vue-pro-master/.image/OA请假-列表.jpg b/ruoyi-vue-pro-master/.image/OA请假-列表.jpg new file mode 100644 index 0000000..787bb73 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/OA请假-列表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/OA请假-发起.jpg b/ruoyi-vue-pro-master/.image/OA请假-发起.jpg new file mode 100644 index 0000000..1a7342d Binary files /dev/null and b/ruoyi-vue-pro-master/.image/OA请假-发起.jpg differ diff --git a/ruoyi-vue-pro-master/.image/OA请假-详情.jpg b/ruoyi-vue-pro-master/.image/OA请假-详情.jpg new file mode 100644 index 0000000..a83e7c1 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/OA请假-详情.jpg differ diff --git a/ruoyi-vue-pro-master/.image/Redis.jpg b/ruoyi-vue-pro-master/.image/Redis.jpg new file mode 100644 index 0000000..9569352 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/Redis.jpg differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/01.png b/ruoyi-vue-pro-master/.image/admin-uniapp/01.png new file mode 100644 index 0000000..0f65d99 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/01.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/02.png b/ruoyi-vue-pro-master/.image/admin-uniapp/02.png new file mode 100644 index 0000000..05ec781 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/02.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/03.png b/ruoyi-vue-pro-master/.image/admin-uniapp/03.png new file mode 100644 index 0000000..f400c68 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/03.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/04.png b/ruoyi-vue-pro-master/.image/admin-uniapp/04.png new file mode 100644 index 0000000..d5d5ea0 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/04.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/05.png b/ruoyi-vue-pro-master/.image/admin-uniapp/05.png new file mode 100644 index 0000000..1de6d8a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/05.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/06.png b/ruoyi-vue-pro-master/.image/admin-uniapp/06.png new file mode 100644 index 0000000..400ae90 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/06.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/07.png b/ruoyi-vue-pro-master/.image/admin-uniapp/07.png new file mode 100644 index 0000000..2ed8c0f Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/07.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/08.png b/ruoyi-vue-pro-master/.image/admin-uniapp/08.png new file mode 100644 index 0000000..090e64a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/08.png differ diff --git a/ruoyi-vue-pro-master/.image/admin-uniapp/09.png b/ruoyi-vue-pro-master/.image/admin-uniapp/09.png new file mode 100644 index 0000000..f2032c8 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/admin-uniapp/09.png differ diff --git a/ruoyi-vue-pro-master/.image/common/ai-feature.png b/ruoyi-vue-pro-master/.image/common/ai-feature.png new file mode 100644 index 0000000..b4a55f5 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/ai-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/bpm-feature.png b/ruoyi-vue-pro-master/.image/common/bpm-feature.png new file mode 100644 index 0000000..23787fb Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/bpm-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/crm-feature.png b/ruoyi-vue-pro-master/.image/common/crm-feature.png new file mode 100644 index 0000000..e1c9670 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/crm-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/erp-feature.png b/ruoyi-vue-pro-master/.image/common/erp-feature.png new file mode 100644 index 0000000..d30b30e Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/erp-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/infra-feature.png b/ruoyi-vue-pro-master/.image/common/infra-feature.png new file mode 100644 index 0000000..f5cef50 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/infra-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/mall-feature.png b/ruoyi-vue-pro-master/.image/common/mall-feature.png new file mode 100644 index 0000000..cca05c0 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/mall-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/mall-preview.png b/ruoyi-vue-pro-master/.image/common/mall-preview.png new file mode 100644 index 0000000..e164cd2 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/mall-preview.png differ diff --git a/ruoyi-vue-pro-master/.image/common/project-vs.png b/ruoyi-vue-pro-master/.image/common/project-vs.png new file mode 100644 index 0000000..561e092 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/project-vs.png differ diff --git a/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-architecture.png b/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-architecture.png new file mode 100644 index 0000000..7bd7d59 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-architecture.png differ diff --git a/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-biz.png b/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-biz.png new file mode 100644 index 0000000..24a385a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/ruoyi-vue-pro-biz.png differ diff --git a/ruoyi-vue-pro-master/.image/common/system-feature.png b/ruoyi-vue-pro-master/.image/common/system-feature.png new file mode 100644 index 0000000..366087c Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/system-feature.png differ diff --git a/ruoyi-vue-pro-master/.image/common/yudao-cloud-architecture.png b/ruoyi-vue-pro-master/.image/common/yudao-cloud-architecture.png new file mode 100644 index 0000000..59416d8 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/yudao-cloud-architecture.png differ diff --git a/ruoyi-vue-pro-master/.image/common/yudao-roadmap.png b/ruoyi-vue-pro-master/.image/common/yudao-roadmap.png new file mode 100644 index 0000000..f4becc9 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/common/yudao-roadmap.png differ diff --git a/ruoyi-vue-pro-master/.image/个人中心.jpg b/ruoyi-vue-pro-master/.image/个人中心.jpg new file mode 100644 index 0000000..ce57f6e Binary files /dev/null and b/ruoyi-vue-pro-master/.image/个人中心.jpg differ diff --git a/ruoyi-vue-pro-master/.image/代码生成.jpg b/ruoyi-vue-pro-master/.image/代码生成.jpg new file mode 100644 index 0000000..751603e Binary files /dev/null and b/ruoyi-vue-pro-master/.image/代码生成.jpg differ diff --git a/ruoyi-vue-pro-master/.image/令牌管理.jpg b/ruoyi-vue-pro-master/.image/令牌管理.jpg new file mode 100644 index 0000000..04abf4d Binary files /dev/null and b/ruoyi-vue-pro-master/.image/令牌管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/任务列表-审批.jpg b/ruoyi-vue-pro-master/.image/任务列表-审批.jpg new file mode 100644 index 0000000..cba312a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/任务列表-审批.jpg differ diff --git a/ruoyi-vue-pro-master/.image/任务列表-已办.jpg b/ruoyi-vue-pro-master/.image/任务列表-已办.jpg new file mode 100644 index 0000000..7a8d0fb Binary files /dev/null and b/ruoyi-vue-pro-master/.image/任务列表-已办.jpg differ diff --git a/ruoyi-vue-pro-master/.image/任务列表-待办.jpg b/ruoyi-vue-pro-master/.image/任务列表-待办.jpg new file mode 100644 index 0000000..a90323f Binary files /dev/null and b/ruoyi-vue-pro-master/.image/任务列表-待办.jpg differ diff --git a/ruoyi-vue-pro-master/.image/任务日志.jpg b/ruoyi-vue-pro-master/.image/任务日志.jpg new file mode 100644 index 0000000..599e50a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/任务日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/商户信息.jpg b/ruoyi-vue-pro-master/.image/商户信息.jpg new file mode 100644 index 0000000..483eace Binary files /dev/null and b/ruoyi-vue-pro-master/.image/商户信息.jpg differ diff --git a/ruoyi-vue-pro-master/.image/在线用户.jpg b/ruoyi-vue-pro-master/.image/在线用户.jpg new file mode 100644 index 0000000..b183009 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/在线用户.jpg differ diff --git a/ruoyi-vue-pro-master/.image/大屏设计器-列表.jpg b/ruoyi-vue-pro-master/.image/大屏设计器-列表.jpg new file mode 100644 index 0000000..9a45c3b Binary files /dev/null and b/ruoyi-vue-pro-master/.image/大屏设计器-列表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/大屏设计器-编辑.jpg b/ruoyi-vue-pro-master/.image/大屏设计器-编辑.jpg new file mode 100644 index 0000000..63298a0 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/大屏设计器-编辑.jpg differ diff --git a/ruoyi-vue-pro-master/.image/大屏设计器-预览.jpg b/ruoyi-vue-pro-master/.image/大屏设计器-预览.jpg new file mode 100644 index 0000000..501d9ea Binary files /dev/null and b/ruoyi-vue-pro-master/.image/大屏设计器-预览.jpg differ diff --git a/ruoyi-vue-pro-master/.image/字典数据.jpg b/ruoyi-vue-pro-master/.image/字典数据.jpg new file mode 100644 index 0000000..8298c89 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/字典数据.jpg differ diff --git a/ruoyi-vue-pro-master/.image/字典类型.jpg b/ruoyi-vue-pro-master/.image/字典类型.jpg new file mode 100644 index 0000000..6613392 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/字典类型.jpg differ diff --git a/ruoyi-vue-pro-master/.image/定时任务.jpg b/ruoyi-vue-pro-master/.image/定时任务.jpg new file mode 100644 index 0000000..d5bbd85 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/定时任务.jpg differ diff --git a/ruoyi-vue-pro-master/.image/岗位管理.jpg b/ruoyi-vue-pro-master/.image/岗位管理.jpg new file mode 100644 index 0000000..42b64d2 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/岗位管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/应用信息-列表.jpg b/ruoyi-vue-pro-master/.image/应用信息-列表.jpg new file mode 100644 index 0000000..da419a2 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/应用信息-列表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/应用信息-编辑.jpg b/ruoyi-vue-pro-master/.image/应用信息-编辑.jpg new file mode 100644 index 0000000..913cfbc Binary files /dev/null and b/ruoyi-vue-pro-master/.image/应用信息-编辑.jpg differ diff --git a/ruoyi-vue-pro-master/.image/应用管理.jpg b/ruoyi-vue-pro-master/.image/应用管理.jpg new file mode 100644 index 0000000..6e7789f Binary files /dev/null and b/ruoyi-vue-pro-master/.image/应用管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/我的流程-列表.jpg b/ruoyi-vue-pro-master/.image/我的流程-列表.jpg new file mode 100644 index 0000000..223d17a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/我的流程-列表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/我的流程-发起.jpg b/ruoyi-vue-pro-master/.image/我的流程-发起.jpg new file mode 100644 index 0000000..7a83306 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/我的流程-发起.jpg differ diff --git a/ruoyi-vue-pro-master/.image/我的流程-详情.jpg b/ruoyi-vue-pro-master/.image/我的流程-详情.jpg new file mode 100644 index 0000000..6a01541 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/我的流程-详情.jpg differ diff --git a/ruoyi-vue-pro-master/.image/报表设计器-图形报表.jpg b/ruoyi-vue-pro-master/.image/报表设计器-图形报表.jpg new file mode 100644 index 0000000..681b318 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/报表设计器-图形报表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/报表设计器-打印设计.jpg b/ruoyi-vue-pro-master/.image/报表设计器-打印设计.jpg new file mode 100644 index 0000000..bb86da6 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/报表设计器-打印设计.jpg differ diff --git a/ruoyi-vue-pro-master/.image/报表设计器-数据报表.jpg b/ruoyi-vue-pro-master/.image/报表设计器-数据报表.jpg new file mode 100644 index 0000000..9ca5b9b Binary files /dev/null and b/ruoyi-vue-pro-master/.image/报表设计器-数据报表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/操作日志.jpg b/ruoyi-vue-pro-master/.image/操作日志.jpg new file mode 100644 index 0000000..4a0611a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/操作日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/支付订单.jpg b/ruoyi-vue-pro-master/.image/支付订单.jpg new file mode 100644 index 0000000..0a56dd7 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/支付订单.jpg differ diff --git a/ruoyi-vue-pro-master/.image/敏感词.jpg b/ruoyi-vue-pro-master/.image/敏感词.jpg new file mode 100644 index 0000000..92a5397 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/敏感词.jpg differ diff --git a/ruoyi-vue-pro-master/.image/数据库文档.jpg b/ruoyi-vue-pro-master/.image/数据库文档.jpg new file mode 100644 index 0000000..a4339d9 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/数据库文档.jpg differ diff --git a/ruoyi-vue-pro-master/.image/文件管理.jpg b/ruoyi-vue-pro-master/.image/文件管理.jpg new file mode 100644 index 0000000..054b19f Binary files /dev/null and b/ruoyi-vue-pro-master/.image/文件管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/文件管理2.jpg b/ruoyi-vue-pro-master/.image/文件管理2.jpg new file mode 100644 index 0000000..b12e5c3 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/文件管理2.jpg differ diff --git a/ruoyi-vue-pro-master/.image/文件配置.jpg b/ruoyi-vue-pro-master/.image/文件配置.jpg new file mode 100644 index 0000000..e618049 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/文件配置.jpg differ diff --git a/ruoyi-vue-pro-master/.image/日志中心.jpg b/ruoyi-vue-pro-master/.image/日志中心.jpg new file mode 100644 index 0000000..27c1c6c Binary files /dev/null and b/ruoyi-vue-pro-master/.image/日志中心.jpg differ diff --git a/ruoyi-vue-pro-master/.image/流程模型-列表.jpg b/ruoyi-vue-pro-master/.image/流程模型-列表.jpg new file mode 100644 index 0000000..ffdc584 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/流程模型-列表.jpg differ diff --git a/ruoyi-vue-pro-master/.image/流程模型-定义.jpg b/ruoyi-vue-pro-master/.image/流程模型-定义.jpg new file mode 100644 index 0000000..18b316c Binary files /dev/null and b/ruoyi-vue-pro-master/.image/流程模型-定义.jpg differ diff --git a/ruoyi-vue-pro-master/.image/流程模型-设计.jpg b/ruoyi-vue-pro-master/.image/流程模型-设计.jpg new file mode 100644 index 0000000..9614969 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/流程模型-设计.jpg differ diff --git a/ruoyi-vue-pro-master/.image/流程表单.jpg b/ruoyi-vue-pro-master/.image/流程表单.jpg new file mode 100644 index 0000000..60669c1 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/流程表单.jpg differ diff --git a/ruoyi-vue-pro-master/.image/生成效果.jpg b/ruoyi-vue-pro-master/.image/生成效果.jpg new file mode 100644 index 0000000..98ff2cc Binary files /dev/null and b/ruoyi-vue-pro-master/.image/生成效果.jpg differ diff --git a/ruoyi-vue-pro-master/.image/用户分组.jpg b/ruoyi-vue-pro-master/.image/用户分组.jpg new file mode 100644 index 0000000..39af1cd Binary files /dev/null and b/ruoyi-vue-pro-master/.image/用户分组.jpg differ diff --git a/ruoyi-vue-pro-master/.image/用户管理.jpg b/ruoyi-vue-pro-master/.image/用户管理.jpg new file mode 100644 index 0000000..844604a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/用户管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/登录.jpg b/ruoyi-vue-pro-master/.image/登录.jpg new file mode 100644 index 0000000..b782b98 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/登录.jpg differ diff --git a/ruoyi-vue-pro-master/.image/登录日志.jpg b/ruoyi-vue-pro-master/.image/登录日志.jpg new file mode 100644 index 0000000..25662d9 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/登录日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/短信日志.jpg b/ruoyi-vue-pro-master/.image/短信日志.jpg new file mode 100644 index 0000000..ada8e56 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/短信日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/短信模板.jpg b/ruoyi-vue-pro-master/.image/短信模板.jpg new file mode 100644 index 0000000..09381cc Binary files /dev/null and b/ruoyi-vue-pro-master/.image/短信模板.jpg differ diff --git a/ruoyi-vue-pro-master/.image/短信渠道.jpg b/ruoyi-vue-pro-master/.image/短信渠道.jpg new file mode 100644 index 0000000..df3a5c3 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/短信渠道.jpg differ diff --git a/ruoyi-vue-pro-master/.image/租户套餐.png b/ruoyi-vue-pro-master/.image/租户套餐.png new file mode 100644 index 0000000..9663167 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/租户套餐.png differ diff --git a/ruoyi-vue-pro-master/.image/租户管理.jpg b/ruoyi-vue-pro-master/.image/租户管理.jpg new file mode 100644 index 0000000..647416a Binary files /dev/null and b/ruoyi-vue-pro-master/.image/租户管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/系统接口.jpg b/ruoyi-vue-pro-master/.image/系统接口.jpg new file mode 100644 index 0000000..6d39d42 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/系统接口.jpg differ diff --git a/ruoyi-vue-pro-master/.image/菜单管理.jpg b/ruoyi-vue-pro-master/.image/菜单管理.jpg new file mode 100644 index 0000000..ad3b797 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/菜单管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/表单构建.jpg b/ruoyi-vue-pro-master/.image/表单构建.jpg new file mode 100644 index 0000000..81f0374 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/表单构建.jpg differ diff --git a/ruoyi-vue-pro-master/.image/角色管理.jpg b/ruoyi-vue-pro-master/.image/角色管理.jpg new file mode 100644 index 0000000..eed776e Binary files /dev/null and b/ruoyi-vue-pro-master/.image/角色管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/访问日志.jpg b/ruoyi-vue-pro-master/.image/访问日志.jpg new file mode 100644 index 0000000..ef301aa Binary files /dev/null and b/ruoyi-vue-pro-master/.image/访问日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/退款订单.jpg b/ruoyi-vue-pro-master/.image/退款订单.jpg new file mode 100644 index 0000000..2c6c6c9 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/退款订单.jpg differ diff --git a/ruoyi-vue-pro-master/.image/通知公告.jpg b/ruoyi-vue-pro-master/.image/通知公告.jpg new file mode 100644 index 0000000..97bb42f Binary files /dev/null and b/ruoyi-vue-pro-master/.image/通知公告.jpg differ diff --git a/ruoyi-vue-pro-master/.image/部门管理.jpg b/ruoyi-vue-pro-master/.image/部门管理.jpg new file mode 100644 index 0000000..6eab233 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/部门管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/配置管理.jpg b/ruoyi-vue-pro-master/.image/配置管理.jpg new file mode 100644 index 0000000..0abaec9 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/配置管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/链路追踪.jpg b/ruoyi-vue-pro-master/.image/链路追踪.jpg new file mode 100644 index 0000000..12f7aa8 Binary files /dev/null and b/ruoyi-vue-pro-master/.image/链路追踪.jpg differ diff --git a/ruoyi-vue-pro-master/.image/错误日志.jpg b/ruoyi-vue-pro-master/.image/错误日志.jpg new file mode 100644 index 0000000..eb615ea Binary files /dev/null and b/ruoyi-vue-pro-master/.image/错误日志.jpg differ diff --git a/ruoyi-vue-pro-master/.image/错误码管理.jpg b/ruoyi-vue-pro-master/.image/错误码管理.jpg new file mode 100644 index 0000000..ea91dde Binary files /dev/null and b/ruoyi-vue-pro-master/.image/错误码管理.jpg differ diff --git a/ruoyi-vue-pro-master/.image/首页.jpg b/ruoyi-vue-pro-master/.image/首页.jpg new file mode 100644 index 0000000..10a7fde Binary files /dev/null and b/ruoyi-vue-pro-master/.image/首页.jpg differ diff --git a/ruoyi-vue-pro-master/LICENSE b/ruoyi-vue-pro-master/LICENSE new file mode 100644 index 0000000..bd9da62 --- /dev/null +++ b/ruoyi-vue-pro-master/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2021 ruoyi-vue-pro + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/ruoyi-vue-pro-master/README.md b/ruoyi-vue-pro-master/README.md new file mode 100644 index 0000000..cd8e578 --- /dev/null +++ b/ruoyi-vue-pro-master/README.md @@ -0,0 +1,362 @@ +

+ Downloads + Downloads + +

+ +**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!** + +**「我喜欢写代码,乐此不疲」** +**「我喜欢做开源,以此为乐」** + +我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。 + +如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 + +## 🐶 新手必读 + +* 演示地址【Vue3 + element-plus】: +* 演示地址【Vue3 + vben(ant-design-vue)】: +* 演示地址【Vue2 + element-ui】: +* 启动文档: +* 视频教程: + +## 🐰 版本说明 + +| 版本 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.2 | +|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------| +| 【完整版】[ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 分支 | +| 【精简版】[yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 分支 | + +* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能 +* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP 等功能 + +可参考 [《迁移文档》](https://doc.iocoder.cn/migrate-module/) ,只需要 5-10 分钟,即可将【完整版】按需迁移到【精简版】 + +## 🐯 平台简介 + +**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 + +> 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。 +> +> 😜 给项目点点 Star 吧,这对我们真的很重要! + +![架构图](/.image/common/ruoyi-vue-pro-architecture.png) + +* Java 后端:`master` 分支为 JDK 8 + Spring Boot 2.7,`master-jdk17` 分支为 JDK 17/21 + Spring Boot 3.2 +* 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本 +* 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5! +* 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson +* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等 +* 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等 +* 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录 +* 支持加载动态权限菜单,按钮级别权限控制,Redis 缓存提升性能 +* 支持 SaaS 多租户,可自定义每个租户的权限,提供透明化的多租户底层封装 +* 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式 +* 高效率开发,使用代码生成器可以一键生成 Java、Vue 前后端代码、SQL 脚本、接口文档,支持单表、树表、主子表 +* 实时通信,采用 Spring WebSocket 实现,内置 Token 身份校验,支持 WebSocket 集群 +* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款 +* 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务 +* 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏 + +## 🐳 项目关系 + +![架构演进](/.image/common/yudao-roadmap.png) + +三个项目的功能对比,可见社区共同整理的 [国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) 表格。 + +### 后端项目 + +| 项目 | Star | 简介 | +|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------| +| [ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [![Gitee star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/ruoyi-vue-pro) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Stars)](https://github.com/YunaiV/ruoyi-vue-pro) | 基于 Spring Boot 多模块架构 | +| [yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [![Gitee star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Stars)](https://github.com/YunaiV/yudao-cloud) | 基于 Spring Cloud 微服务架构 | +| [Spring-Boot-Labs](https://gitee.com/yudaocode/SpringBoot-Labs) | [![Gitee star](https://gitee.com/yudaocode/SpringBoot-Labs/badge/star.svg?theme=white)](https://gitee.com/zhijiantianya/yudao-cloud) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/SpringBoot-Labs.svg?style=social&label=Stars)](https://github.com/yudaocode/SpringBoot-Labs) | 系统学习 Spring Boot & Cloud 专栏 | + +### 前端项目 + +| 项目 | Star | 简介 | +|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| +| [yudao-ui-admin-vue3](https://gitee.com/yudaocode/yudao-ui-admin-vue3) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue3/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue3) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue3.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue3) | 基于 Vue3 + element-plus 实现的管理后台 | +| [yudao-ui-admin-vben](https://gitee.com/yudaocode/yudao-ui-admin-vben) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vben/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vben) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vben.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vben) | 基于 Vue3 + vben(ant-design-vue) 实现的管理后台 | +| [yudao-mall-uniapp](https://gitee.com/yudaocode/yudao-mall-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-mall-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-mall-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-mall-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-mall-uniapp) | 基于 uni-app 实现的商城小程序 | +| [yudao-ui-admin-vue2](https://gitee.com/yudaocode/yudao-ui-admin-vue2) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-vue2/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-vue2) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-vue2.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-vue2) | 基于 Vue2 + element-ui 实现的管理后台 | +| [yudao-ui-admin-uniapp](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-admin-uniapp/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-admin-uniapp) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-admin-uniapp.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-admin-uniapp) | 基于 Vue2 + element-ui 实现的管理后台 | +| [yudao-ui-go-view](https://gitee.com/yudaocode/yudao-ui-go-view) | [![Gitee star](https://gitee.com/yudaocode/yudao-ui-go-view/badge/star.svg?theme=white)](https://gitee.com/yudaocode/yudao-ui-go-view) [![GitHub stars](https://img.shields.io/github/stars/yudaocode/yudao-ui-go-view.svg?style=social&label=Stars)](https://github.com/yudaocode/yudao-ui-go-view) | 基于 Vue3 + naive-ui 实现的大屏报表 | + +## 😎 开源协议 + +**为什么推荐使用本项目?** + +① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。 + +② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。[国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn) + +![开源项目对比](/.image/common/project-vs.png) + +③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,113770 行 Java 代码,42462 行代码注释。 + +## 🤝 项目外包 + +我们也是接外包滴,如果你有项目想要外包,可以微信联系【**Aix9975**】。 + +团队包含专业的项目经理、架构师、前端工程师、后端工程师、测试工程师、运维工程师,可以提供全流程的外包服务。 + +项目可以是商城、SCRM 系统、OA 系统、物流系统、ERP 系统、CMS 系统、HIS 系统、支付系统、IM 聊天、微信公众号、微信小程序等等。 + +## 🐼 内置功能 + +系统内置多种多种业务功能,可以用于快速你的业务系统: + +![功能分层](/.image/common/ruoyi-vue-pro-biz.png) + +* 通用模块(必选):系统功能、基础设施 +* 通用模块(可选):工作流程、支付系统、数据报表、会员中心 +* 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型 + +> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。 +> +> * 额外新增的功能,我们使用 🚀 标记。 +> * 重新实现的功能,我们使用 ⭐️ 标记。 + +🙂 所有功能,都通过 **单元测试** 保证高质量。 + +### 系统功能 + +| | 功能 | 描述 | +|-----|-------|---------------------------------| +| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 | +| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 | +| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | +| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 | +| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 | +| | 岗位管理 | 配置系统用户所属担任职务 | +| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 | +| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 | +| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | +| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 | +| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 | +| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 | +| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 | +| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 | +| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 | +| | 通知公告 | 系统通知公告信息发布维护 | +| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 | +| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | +| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | + +![功能图](/.image/common/system-feature.png) + +### 工作流程 + +| | 功能 | 描述 | +|-----|-------|----------------------------------------| +| 🚀 | 流程模型 | 配置工作流的流程模型,支持文件导入与在线设计流程图,提供 7 种任务分配规则 | +| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 | +| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 | +| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 | +| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转发、委派、退回等操作 | +| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 | +| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 | + +![功能图](/.image/common/bpm-feature.png) + +### 支付系统 + +| | 功能 | 描述 | +|-----|------|---------------------------| +| 🚀 | 应用信息 | 配置商户的应用信息,对接支付宝、微信等多个支付渠道 | +| 🚀 | 支付订单 | 查看用户发起的支付宝、微信等的【支付】订单 | +| 🚀 | 退款订单 | 查看用户发起的支付宝、微信等的【退款】订单 | +| 🚀 | 回调通知 | 查看支付回调业务的【支付】【退款】的通知结果 | +| 🚀 | 接入示例 | 提供接入支付系统的【支付】【退款】的功能实战 | + +### 基础设施 + +| | 功能 | 描述 | +|-----|-----------|----------------------------------------------| +| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 | +| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 | +| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 | +| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 | +| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 | +| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 | +| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 | +| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 | +| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 | +| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 | +| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 | +| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 | +| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 | +| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 | +| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 | +| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 | +| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | +| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | + +![功能图](/.image/common/infra-feature.png) + +### 数据报表 + +| | 功能 | 描述 | +|-----|-------|--------------------| +| 🚀 | 报表设计器 | 支持数据报表、图形报表、打印设计等 | +| 🚀 | 大屏设计器 | 拖拽生成数据大屏,内置几十种图表组件 | + +### 微信公众号 + +| | 功能 | 描述 | +|-----|--------|-------------------------------| +| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 | +| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 | +| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 | +| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 | +| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 | +| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 | +| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 | +| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 | +| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 | +| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 | + +### 商城系统 + +![功能图](/.image/common/mall-feature.png) + +![功能图](/.image/common/mall-preview.png) + +演示地址: + +### 会员中心 + +| | 功能 | 描述 | +|-----|------|----------------------------------| +| 🚀 | 会员管理 | 会员是 C 端的消费者,该功能用于会员的搜索与管理 | +| 🚀 | 会员标签 | 对会员的标签进行创建、查询、修改、删除等操作 | +| 🚀 | 会员等级 | 对会员的等级、成长值进行管理,可用于订单折扣等会员权益 | +| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 | +| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 | + +### ERP 系统 + +![功能图](/.image/common/erp-feature.png) + +演示地址: + +### CRM 系统 + +![功能图](/.image/common/crm-feature.png) + +演示地址: + +### AI 大模型 + +![功能图](/.image/common/ai-feature.png) + +演示地址: + +## 🐨 技术栈 + +### 模块 + +| 项目 | 说明 | +|-----------------------|--------------------| +| `yudao-dependencies` | Maven 依赖版本管理 | +| `yudao-framework` | Java 框架拓展 | +| `yudao-server` | 管理后台 + 用户 APP 的服务端 | +| `yudao-module-system` | 系统功能的 Module 模块 | +| `yudao-module-member` | 会员中心的 Module 模块 | +| `yudao-module-infra` | 基础设施的 Module 模块 | +| `yudao-module-bpm` | 工作流程的 Module 模块 | +| `yudao-module-pay` | 支付系统的 Module 模块 | +| `yudao-module-mall` | 商城系统的 Module 模块 | +| `yudao-module-erp` | ERP 系统的 Module 模块 | +| `yudao-module-crm` | CRM 系统的 Module 模块 | +| `yudao-module-ai` | AI 大模型的 Module 模块 | +| `yudao-module-mp` | 微信公众号的 Module 模块 | +| `yudao-module-report` | 大屏报表 Module 模块 | + +### 框架 + +| 框架 | 说明 | 版本 | 学习指南 | +|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------| +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.7.18 | [文档](https://github.com/YunaiV/SpringBoot-Labs) | +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | | +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.19 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | +| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | +| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | | +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | +| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.24 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | +| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.11 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | +| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | +| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.8.0 | [文档](https://doc.iocoder.cn/bpm/) | +| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | +| [Springdoc](https://springdoc.org/) | Swagger 文档 | 1.6.15 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | +| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.10 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | +| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | | +| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.5.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | +| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.30 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | +| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | +| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.8.0 | - | + +## 🐷 演示图 + +### 系统功能 + +| 模块 | biu | biu | biu | +|----------|-----------------------------|---------------------------|--------------------------| +| 登录 & 首页 | ![登录](/.image/登录.jpg) | ![首页](/.image/首页.jpg) | ![个人中心](/.image/个人中心.jpg) | +| 用户 & 应用 | ![用户管理](/.image/用户管理.jpg) | ![令牌管理](/.image/令牌管理.jpg) | ![应用管理](/.image/应用管理.jpg) | +| 租户 & 套餐 | ![租户管理](/.image/租户管理.jpg) | ![租户套餐](/.image/租户套餐.png) | - | +| 部门 & 岗位 | ![部门管理](/.image/部门管理.jpg) | ![岗位管理](/.image/岗位管理.jpg) | - | +| 菜单 & 角色 | ![菜单管理](/.image/菜单管理.jpg) | ![角色管理](/.image/角色管理.jpg) | - | +| 审计日志 | ![操作日志](/.image/操作日志.jpg) | ![登录日志](/.image/登录日志.jpg) | - | +| 短信 | ![短信渠道](/.image/短信渠道.jpg) | ![短信模板](/.image/短信模板.jpg) | ![短信日志](/.image/短信日志.jpg) | +| 字典 & 敏感词 | ![字典类型](/.image/字典类型.jpg) | ![字典数据](/.image/字典数据.jpg) | ![敏感词](/.image/敏感词.jpg) | +| 错误码 & 通知 | ![错误码管理](/.image/错误码管理.jpg) | ![通知公告](/.image/通知公告.jpg) | - | + +### 工作流程 + +| 模块 | biu | biu | biu | +|---------|---------------------------------|---------------------------------|---------------------------------| +| 流程模型 | ![流程模型-列表](/.image/流程模型-列表.jpg) | ![流程模型-设计](/.image/流程模型-设计.jpg) | ![流程模型-定义](/.image/流程模型-定义.jpg) | +| 表单 & 分组 | ![流程表单](/.image/流程表单.jpg) | ![用户分组](/.image/用户分组.jpg) | - | +| 我的流程 | ![我的流程-列表](/.image/我的流程-列表.jpg) | ![我的流程-发起](/.image/我的流程-发起.jpg) | ![我的流程-详情](/.image/我的流程-详情.jpg) | +| 待办 & 已办 | ![任务列表-审批](/.image/任务列表-审批.jpg) | ![任务列表-待办](/.image/任务列表-待办.jpg) | ![任务列表-已办](/.image/任务列表-已办.jpg) | +| OA 请假 | ![OA请假-列表](/.image/OA请假-列表.jpg) | ![OA请假-发起](/.image/OA请假-发起.jpg) | ![OA请假-详情](/.image/OA请假-详情.jpg) | + +### 基础设施 + +| 模块 | biu | biu | biu | +|---------------|-------------------------------|-----------------------------|---------------------------| +| 代码生成 | ![代码生成](/.image/代码生成.jpg) | ![生成效果](/.image/生成效果.jpg) | - | +| 文档 | ![系统接口](/.image/系统接口.jpg) | ![数据库文档](/.image/数据库文档.jpg) | - | +| 文件 & 配置 | ![文件配置](/.image/文件配置.jpg) | ![文件管理](/.image/文件管理2.jpg) | ![配置管理](/.image/配置管理.jpg) | +| 定时任务 | ![定时任务](/.image/定时任务.jpg) | ![任务日志](/.image/任务日志.jpg) | - | +| API 日志 | ![访问日志](/.image/访问日志.jpg) | ![错误日志](/.image/错误日志.jpg) | - | +| MySQL & Redis | ![MySQL](/.image/MySQL.jpg) | ![Redis](/.image/Redis.jpg) | - | +| 监控平台 | ![Java监控](/.image/Java监控.jpg) | ![链路追踪](/.image/链路追踪.jpg) | ![日志中心](/.image/日志中心.jpg) | + +### 支付系统 + +| 模块 | biu | biu | biu | +|---------|---------------------------|---------------------------------|---------------------------------| +| 商家 & 应用 | ![商户信息](/.image/商户信息.jpg) | ![应用信息-列表](/.image/应用信息-列表.jpg) | ![应用信息-编辑](/.image/应用信息-编辑.jpg) | +| 支付 & 退款 | ![支付订单](/.image/支付订单.jpg) | ![退款订单](/.image/退款订单.jpg) | --- | +### 数据报表 + +| 模块 | biu | biu | biu | +|-------|---------------------------------|---------------------------------|---------------------------------------| +| 报表设计器 | ![数据报表](/.image/报表设计器-数据报表.jpg) | ![图形报表](/.image/报表设计器-图形报表.jpg) | ![报表设计器-打印设计](/.image/报表设计器-打印设计.jpg) | +| 大屏设计器 | ![大屏列表](/.image/大屏设计器-列表.jpg) | ![大屏预览](/.image/大屏设计器-预览.jpg) | ![大屏编辑](/.image/大屏设计器-编辑.jpg) | + +### 移动端(管理后台) + +| biu | biu | biu | +|----------------------------------|----------------------------------|----------------------------------| +| ![](/.image/admin-uniapp/01.png) | ![](/.image/admin-uniapp/02.png) | ![](/.image/admin-uniapp/03.png) | +| ![](/.image/admin-uniapp/04.png) | ![](/.image/admin-uniapp/05.png) | ![](/.image/admin-uniapp/06.png) | +| ![](/.image/admin-uniapp/07.png) | ![](/.image/admin-uniapp/08.png) | ![](/.image/admin-uniapp/09.png) | + +目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。 diff --git a/ruoyi-vue-pro-master/lombok.config b/ruoyi-vue-pro-master/lombok.config new file mode 100644 index 0000000..a8e8ce6 --- /dev/null +++ b/ruoyi-vue-pro-master/lombok.config @@ -0,0 +1,4 @@ +config.stopBubbling = true +lombok.tostring.callsuper=CALL +lombok.equalsandhashcode.callsuper=CALL +lombok.accessors.chain=true diff --git a/ruoyi-vue-pro-master/pom.xml b/ruoyi-vue-pro-master/pom.xml new file mode 100644 index 0000000..3f19cfe --- /dev/null +++ b/ruoyi-vue-pro-master/pom.xml @@ -0,0 +1,147 @@ + + + 4.0.0 + cn.iocoder.boot + yudao + ${revision} + pom + + yudao-dependencies + yudao-framework + + yudao-server + + yudao-module-system + yudao-module-infra + + + + + + + + + + + ${project.artifactId} + 芋道项目基础脚手架 + https://github.com/YunaiV/ruoyi-vue-pro + + + 2.1.0-jdk8-snapshot + + 1.8 + ${java.version} + ${java.version} + 3.0.0-M5 + 3.8.1 + 1.5.0 + + 1.18.30 + 2.7.18 + 1.5.5.Final + UTF-8 + + + + + + cn.iocoder.boot + yudao-dependencies + ${revision} + pom + import + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + org.codehaus.mojo + flatten-maven-plugin + + + + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + resolveCiFriendliesOnly + true + + + + + flatten + + flatten + process-resources + + + + clean + + flatten.clean + clean + + + + + + + + + + huaweicloud + huawei + https://mirrors.huaweicloud.com/repository/maven/ + + + aliyunmaven + aliyun + https://maven.aliyun.com/repository/public + + + + diff --git a/ruoyi-vue-pro-master/script/docker/Docker-HOWTO.md b/ruoyi-vue-pro-master/script/docker/Docker-HOWTO.md new file mode 100644 index 0000000..7a62a68 --- /dev/null +++ b/ruoyi-vue-pro-master/script/docker/Docker-HOWTO.md @@ -0,0 +1,49 @@ +# Docker Build & Up + +目标: 快速部署体验系统,帮助了解系统之间的依赖关系。 +依赖:docker compose v2,删除`name: yudao-system`,降低`version`版本为`3.3`以下,支持`docker-compose`。 + +## 功能文件列表 + +```text +. +├── Docker-HOWTO.md +├── docker-compose.yml +├── docker.env <-- 提供docker-compose环境变量配置 +├── yudao-server +│ └── Dockerfile +└── yudao-ui-admin + ├── .dockerignore + ├── Dockerfile + └── nginx.conf <-- 提供基础配置,gzip压缩、api转发 +``` + +## 构建 jar 包 + +```shell +# 创建maven缓存volume +docker volume create --name yudao-maven-repo + +docker run -it --rm --name yudao-maven \ + -v yudao-maven-repo:/root/.m2 \ + -v $PWD:/usr/src/mymaven \ + -w /usr/src/mymaven \ + maven mvn clean install package '-Dmaven.test.skip=true' +``` + +## 构建启动服务 + +```shell +docker compose --env-file docker.env up -d +``` + +首次运行会自动构建容器。可以通过`docker compose build [service]`来手动构建所有或某个docker镜像 + +`--env-file docker.env`为可选参数,只是展示了通过`.env`文件配置容器启动的环境变量,`docker-compose.yml`本身已经提供足够的默认参数来正常运行系统。 + +## 服务器的宿主机端口映射 + +- admin ui: http://localhost:8080 +- api server: http://localhost:48080 +- mysql: root/123456, port: 3306 +- redis: port: 6379 diff --git a/ruoyi-vue-pro-master/script/docker/docker-compose.yml b/ruoyi-vue-pro-master/script/docker/docker-compose.yml new file mode 100644 index 0000000..e440d96 --- /dev/null +++ b/ruoyi-vue-pro-master/script/docker/docker-compose.yml @@ -0,0 +1,84 @@ +version: "3.4" + +name: yudao-system + +services: + mysql: + container_name: yudao-mysql + image: mysql:8 + restart: unless-stopped + tty: true + ports: + - "3306:3306" + environment: + MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456} + volumes: + - mysql:/var/lib/mysql/ + - ./sql/mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro + + redis: + container_name: yudao-redis + image: redis:6-alpine + restart: unless-stopped + ports: + - "6379:6379" + volumes: + - redis:/data + + server: + container_name: yudao-server + build: + context: ./yudao-server/ + image: yudao-server + restart: unless-stopped + ports: + - "48080:48080" + environment: + # https://github.com/polovyivan/docker-pass-configs-to-container + SPRING_PROFILES_ACTIVE: local + JAVA_OPTS: + ${JAVA_OPTS:- + -Xms512m + -Xmx512m + -Djava.security.egd=file:/dev/./urandom + } + ARGS: + --spring.datasource.dynamic.datasource.master.url=${MASTER_DATASOURCE_URL:-jdbc:mysql://yudao-mysql:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true} + --spring.datasource.dynamic.datasource.master.username=${MASTER_DATASOURCE_USERNAME:-root} + --spring.datasource.dynamic.datasource.master.password=${MASTER_DATASOURCE_PASSWORD:-123456} + --spring.datasource.dynamic.datasource.slave.url=${SLAVE_DATASOURCE_URL:-jdbc:mysql://yudao-mysql:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true} + --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root} + --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456} + --spring.redis.host=${REDIS_HOST:-yudao-redis} + depends_on: + - mysql + - redis + + admin: + container_name: yudao-admin + build: + context: ./yudao-ui-admin + args: + NODE_ENV: + ENV=${NODE_ENV:-production} + PUBLIC_PATH=${PUBLIC_PATH:-/} + VUE_APP_TITLE=${VUE_APP_TITLE:-芋道管理系统} + VUE_APP_BASE_API=${VUE_APP_BASE_API:-/prod-api} + VUE_APP_APP_NAME=${VUE_APP_APP_NAME:-/} + VUE_APP_TENANT_ENABLE=${VUE_APP_TENANT_ENABLE:-true} + VUE_APP_CAPTCHA_ENABLE=${VUE_APP_CAPTCHA_ENABLE:-true} + VUE_APP_DOC_ENABLE=${VUE_APP_DOC_ENABLE:-true} + VUE_APP_BAIDU_CODE=${VUE_APP_BAIDU_CODE:-fadc1bd5db1a1d6f581df60a1807f8ab} + image: yudao-admin + restart: unless-stopped + ports: + - "8080:80" + depends_on: + - server + +volumes: + mysql: + driver: local + redis: + driver: local diff --git a/ruoyi-vue-pro-master/script/docker/docker.env b/ruoyi-vue-pro-master/script/docker/docker.env new file mode 100644 index 0000000..0bf6e99 --- /dev/null +++ b/ruoyi-vue-pro-master/script/docker/docker.env @@ -0,0 +1,25 @@ +## mysql +MYSQL_DATABASE=ruoyi-vue-pro +MYSQL_ROOT_PASSWORD=123456 + +## server +JAVA_OPTS=-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom + +MASTER_DATASOURCE_URL=jdbc:mysql://yudao-mysql:3306/${MYSQL_DATABASE}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true +MASTER_DATASOURCE_USERNAME=root +MASTER_DATASOURCE_PASSWORD=${MYSQL_ROOT_PASSWORD} +SLAVE_DATASOURCE_URL=${MASTER_DATASOURCE_URL} +SLAVE_DATASOURCE_USERNAME=${MASTER_DATASOURCE_USERNAME} +SLAVE_DATASOURCE_PASSWORD=${MASTER_DATASOURCE_PASSWORD} +REDIS_HOST=yudao-redis + +## admin +NODE_ENV=production +PUBLIC_PATH=/ +VUE_APP_TITLE=芋道管理系统 +VUE_APP_BASE_API=/prod-api +VUE_APP_APP_NAME=/ +VUE_APP_TENANT_ENABLE=true +VUE_APP_CAPTCHA_ENABLE=true +VUE_APP_DOC_ENABLE=true +VUE_APP_BAIDU_CODE=fadc1bd5db1a1d6f581df60a1807f8ab diff --git a/ruoyi-vue-pro-master/script/idea/http-client.env.json b/ruoyi-vue-pro-master/script/idea/http-client.env.json new file mode 100644 index 0000000..4a4cb52 --- /dev/null +++ b/ruoyi-vue-pro-master/script/idea/http-client.env.json @@ -0,0 +1,20 @@ +{ + "local": { + "baseUrl": "http://127.0.0.1:48080/admin-api", + "token": "test1", + "adminTenentId": "1", + + "appApi": "http://127.0.0.1:48080/app-api", + "appToken": "test247", + "appTenentId": "1" + }, + "gateway": { + "baseUrl": "http://127.0.0.1:8888/admin-api", + "token": "test1", + "adminTenentId": "1", + + "appApi": "http://127.0.0.1:8888/app-api", + "appToken": "test1", + "appTenantId": "1" + } +} diff --git a/ruoyi-vue-pro-master/script/jenkins/Jenkinsfile b/ruoyi-vue-pro-master/script/jenkins/Jenkinsfile new file mode 100644 index 0000000..91842b3 --- /dev/null +++ b/ruoyi-vue-pro-master/script/jenkins/Jenkinsfile @@ -0,0 +1,60 @@ +#!groovy +pipeline { + + agent any + + parameters { + string(name: 'TAG_NAME', defaultValue: '', description: '') + } + + environment { + // DockerHub 凭证 ID(登录您的 DockerHub) + DOCKER_CREDENTIAL_ID = 'dockerhub-id' + // GitHub 凭证 ID (推送 tag 到 GitHub 仓库) + GITHUB_CREDENTIAL_ID = 'github-id' + // kubeconfig 凭证 ID (访问接入正在运行的 Kubernetes 集群) + KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig' + // 镜像的推送 + REGISTRY = 'docker.io' + // DockerHub 账号名 + DOCKERHUB_NAMESPACE = 'docker_username' + // GitHub 账号名 + GITHUB_ACCOUNT = 'https://gitee.com/zhijiantianya/ruoyi-vue-pro' + // 应用名称 + APP_NAME = 'yudao-server' + // 应用部署路径 + APP_DEPLOY_BASE_DIR = '/media/pi/KINGTON/data/work/projects/' + } + + stages { + stage('检出') { + steps { + git url: "https://gitee.com/will-we/ruoyi-vue-pro.git", + branch: "devops" + } + } + + stage('构建') { + steps { + // TODO 解决多环境链接、密码不同配置临时方案 + sh 'if [ ! -d "' + "${env.HOME}" + '/resources" ];then\n' + + ' echo "配置文件不存在无需修改"\n' + + 'else\n' + + ' cp -rf ' + "${env.HOME}" + '/resources/*.yaml ' + "${env.APP_NAME}" + '/src/main/resources\n' + + ' echo "配置文件替换"\n' + + 'fi' + sh 'mvn clean package -Dmaven.test.skip=true' + } + } + + stage('部署') { + steps { + sh 'cp -f ' + ' bin/deploy.sh ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + sh 'cp -f ' + "${env.APP_NAME}" + '/target/*.jar ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" +'/build/' + archiveArtifacts "${env.APP_NAME}" + '/target/*.jar' + sh 'chmod +x ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh' + sh 'bash ' + "${env.APP_DEPLOY_BASE_DIR}" + "${env.APP_NAME}" + '/deploy.sh' + } + } + } +} diff --git a/ruoyi-vue-pro-master/script/shell/deploy.sh b/ruoyi-vue-pro-master/script/shell/deploy.sh new file mode 100644 index 0000000..b635a70 --- /dev/null +++ b/ruoyi-vue-pro-master/script/shell/deploy.sh @@ -0,0 +1,160 @@ +#!/bin/bash +set -e + +DATE=$(date +%Y%m%d%H%M) +# 基础路径 +BASE_PATH=/work/projects/yudao-server +# 编译后 jar 的地址。部署时,Jenkins 会上传 jar 包到该目录下 +SOURCE_PATH=$BASE_PATH/build +# 服务名称。同时约定部署服务的 jar 包名字也为它。 +SERVER_NAME=yudao-server +# 环境 +PROFILES_ACTIVE=development +# 健康检查 URL +HEALTH_CHECK_URL=http://127.0.0.1:48080/actuator/health/ + +# heapError 存放路径 +HEAP_ERROR_PATH=$BASE_PATH/heapError +# JVM 参数 +JAVA_OPS="-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HEAP_ERROR_PATH" + +# SkyWalking Agent 配置 +#export SW_AGENT_NAME=$SERVER_NAME +#export SW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.84:11800 +#export SW_GRPC_LOG_SERVER_HOST=192.168.0.84 +#export SW_AGENT_TRACE_IGNORE_PATH="Redisson/PING,/actuator/**,/admin/**" +#export JAVA_AGENT=-javaagent:/work/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar + +# 备份 +function backup() { + # 如果不存在,则无需备份 + if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then + echo "[backup] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过备份" + # 如果存在,则备份到 backup 目录下,使用时间作为后缀 + else + echo "[backup] 开始备份 $SERVER_NAME ..." + cp $BASE_PATH/$SERVER_NAME.jar $BASE_PATH/backup/$SERVER_NAME-$DATE.jar + echo "[backup] 备份 $SERVER_NAME 完成" + fi +} + +# 最新构建代码 移动到项目环境 +function transfer() { + echo "[transfer] 开始转移 $SERVER_NAME.jar" + + # 删除原 jar 包 + if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then + echo "[transfer] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过删除" + else + echo "[transfer] 移除 $BASE_PATH/$SERVER_NAME.jar 完成" + rm $BASE_PATH/$SERVER_NAME.jar + fi + + # 复制新 jar 包 + echo "[transfer] 从 $SOURCE_PATH 中获取 $SERVER_NAME.jar 并迁移至 $BASE_PATH ...." + cp $SOURCE_PATH/$SERVER_NAME.jar $BASE_PATH + + echo "[transfer] 转移 $SERVER_NAME.jar 完成" +} + +# 停止:优雅关闭之前已经启动的服务 +function stop() { + echo "[stop] 开始停止 $BASE_PATH/$SERVER_NAME" + PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}') + # 如果 Java 服务启动中,则进行关闭 + if [ -n "$PID" ]; then + # 正常关闭 + echo "[stop] $BASE_PATH/$SERVER_NAME 运行中,开始 kill [$PID]" + kill -15 $PID + # 等待最大 120 秒,直到关闭完成。 + for ((i = 0; i < 120; i++)) + do + sleep 1 + PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}') + if [ -n "$PID" ]; then + echo -e ".\c" + else + echo "[stop] 停止 $BASE_PATH/$SERVER_NAME 成功" + break + fi + done + + # 如果正常关闭失败,那么进行强制 kill -9 进行关闭 + if [ -n "$PID" ]; then + echo "[stop] $BASE_PATH/$SERVER_NAME 失败,强制 kill -9 $PID" + kill -9 $PID + fi + # 如果 Java 服务未启动,则无需关闭 + else + echo "[stop] $BASE_PATH/$SERVER_NAME 未启动,无需停止" + fi +} + +# 启动:启动后端项目 +function start() { + # 开启启动前,打印启动参数 + echo "[start] 开始启动 $BASE_PATH/$SERVER_NAME" + echo "[start] JAVA_OPS: $JAVA_OPS" + echo "[start] JAVA_AGENT: $JAVA_AGENT" + echo "[start] PROFILES: $PROFILES_ACTIVE" + + # 开始启动 + BUILD_ID=dontKillMe nohup java -server $JAVA_OPS $JAVA_AGENT -jar $BASE_PATH/$SERVER_NAME.jar --spring.profiles.active=$PROFILES_ACTIVE & + echo "[start] 启动 $BASE_PATH/$SERVER_NAME 完成" +} + +# 健康检查:自动判断后端项目是否正常启动 +function healthCheck() { + # 如果配置健康检查,则进行健康检查 + if [ -n "$HEALTH_CHECK_URL" ]; then + # 健康检查最大 120 秒,直到健康检查通过 + echo "[healthCheck] 开始通过 $HEALTH_CHECK_URL 地址,进行健康检查"; + for ((i = 0; i < 120; i++)) + do + # 请求健康检查地址,只获取状态码。 + result=`curl -I -m 10 -o /dev/null -s -w %{http_code} $HEALTH_CHECK_URL || echo "000"` + # 如果状态码为 200,则说明健康检查通过 + if [ "$result" == "200" ]; then + echo "[healthCheck] 健康检查通过"; + break + # 如果状态码非 200,则说明未通过。sleep 1 秒后,继续重试 + else + echo -e ".\c" + sleep 1 + fi + done + + # 健康检查未通过,则异常退出 shell 脚本,不继续部署。 + if [ ! "$result" == "200" ]; then + echo "[healthCheck] 健康检查不通过,可能部署失败。查看日志,自行判断是否启动成功"; + tail -n 10 nohup.out + exit 1; + # 健康检查通过,打印最后 10 行日志,可能部署的人想看下日志。 + else + tail -n 10 nohup.out + fi + # 如果未配置健康检查,则 sleep 120 秒,人工看日志是否部署成功。 + else + echo "[healthCheck] HEALTH_CHECK_URL 未配置,开始 sleep 120 秒"; + sleep 120 + echo "[healthCheck] sleep 120 秒完成,查看日志,自行判断是否启动成功"; + tail -n 50 nohup.out + fi +} + +# 部署 +function deploy() { + cd $BASE_PATH + # 备份原 jar + backup + # 停止 Java 服务 + stop + # 部署新 jar + transfer + # 启动 Java 服务 + start + # 健康检查 + healthCheck +} + +deploy diff --git a/ruoyi-vue-pro-master/sql/db2/README.md b/ruoyi-vue-pro-master/sql/db2/README.md new file mode 100644 index 0000000..5b60d1e --- /dev/null +++ b/ruoyi-vue-pro-master/sql/db2/README.md @@ -0,0 +1,3 @@ +暂未适配 IBM DB2 数据库,如果你有需要,可以微信联系 wangwenbin-server 一起建设。 + +你需要把表结构与数据导入到 DM 数据库,我来测试与适配代码。 diff --git a/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/database/core/DmDatabase.java b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/database/core/DmDatabase.java new file mode 100644 index 0000000..fbc4c6b --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/database/core/DmDatabase.java @@ -0,0 +1,598 @@ +package liquibase.database.core; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import liquibase.CatalogAndSchema; +import liquibase.Scope; +import liquibase.database.AbstractJdbcDatabase; +import liquibase.database.DatabaseConnection; +import liquibase.database.OfflineConnection; +import liquibase.database.jvm.JdbcConnection; +import liquibase.exception.DatabaseException; +import liquibase.exception.UnexpectedLiquibaseException; +import liquibase.exception.ValidationErrors; +import liquibase.executor.ExecutorService; +import liquibase.statement.DatabaseFunction; +import liquibase.statement.SequenceCurrentValueFunction; +import liquibase.statement.SequenceNextValueFunction; +import liquibase.statement.core.RawCallStatement; +import liquibase.statement.core.RawSqlStatement; +import liquibase.structure.DatabaseObject; +import liquibase.structure.core.Catalog; +import liquibase.structure.core.Index; +import liquibase.structure.core.PrimaryKey; +import liquibase.structure.core.Schema; +import liquibase.util.JdbcUtils; +import liquibase.util.StringUtil; + +public class DmDatabase extends AbstractJdbcDatabase { + private static final String PRODUCT_NAME = "DM DBMS"; + + @Override + protected String getDefaultDatabaseProductName() { + return PRODUCT_NAME; + } + + /** + * Is this AbstractDatabase subclass the correct one to use for the given connection. + * + * @param conn + */ + @Override + public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException { + return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName()); + } + + /** + * If this database understands the given url, return the default driver class name. Otherwise return null. + * + * @param url + */ + @Override + public String getDefaultDriver(String url) { + if(url.startsWith("jdbc:dm")) { + return "dm.jdbc.driver.DmDriver"; + } + + return null; + } + + /** + * Returns an all-lower-case short name of the product. Used for end-user selecting of database type + * such as the DBMS precondition. + */ + @Override + public String getShortName() { + return "dm"; + } + + @Override + public Integer getDefaultPort() { + return 5236; + } + + /** + * Returns whether this database support initially deferrable columns. + */ + @Override + public boolean supportsInitiallyDeferrableColumns() { + return true; + } + + @Override + public boolean supportsTablespaces() { + return true; + } + + @Override + public int getPriority() { + return PRIORITY_DEFAULT; + } + + private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*"); + + protected final int SHORT_IDENTIFIERS_LENGTH = 30; + protected final int LONG_IDENTIFIERS_LEGNTH = 128; + public static final int ORACLE_12C_MAJOR_VERSION = 12; + + private Set reservedWords = new HashSet<>(); + private Set userDefinedTypes; + private Map savedSessionNlsSettings; + + private Boolean canAccessDbaRecycleBin; + private Integer databaseMajorVersion; + private Integer databaseMinorVersion; + + /** + * Default constructor for an object that represents the Oracle Database DBMS. + */ + public DmDatabase() { + super.unquotedObjectsAreUppercased = true; + //noinspection HardCodedStringLiteral + super.setCurrentDateTimeFunction("SYSTIMESTAMP"); + // Setting list of Oracle's native functions + //noinspection HardCodedStringLiteral + dateFunctions.add(new DatabaseFunction("SYSDATE")); + //noinspection HardCodedStringLiteral + dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP")); + //noinspection HardCodedStringLiteral + dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP")); + //noinspection HardCodedStringLiteral + super.sequenceNextValueFunction = "%s.nextval"; + //noinspection HardCodedStringLiteral + super.sequenceCurrentValueFunction = "%s.currval"; + } + + private void tryProxySession(final String url, final Connection con) { + Matcher m = PROXY_USER.matcher(url); + if (m.matches()) { + Properties props = new Properties(); + props.put("PROXY_USER_NAME", m.group(1)); + try { + Method method = con.getClass().getMethod("openProxySession", int.class, Properties.class); + method.setAccessible(true); + method.invoke(con, 1, props); + } catch (Exception e) { + Scope.getCurrentScope().getLog(getClass()).info("Could not open proxy session on OracleDatabase: " + e.getCause().getMessage()); + } + } + } + + @Override + public int getDatabaseMajorVersion() throws DatabaseException { + if (databaseMajorVersion == null) { + return super.getDatabaseMajorVersion(); + } else { + return databaseMajorVersion; + } + } + + @Override + public int getDatabaseMinorVersion() throws DatabaseException { + if (databaseMinorVersion == null) { + return super.getDatabaseMinorVersion(); + } else { + return databaseMinorVersion; + } + } + + @Override + public String getJdbcCatalogName(CatalogAndSchema schema) { + return null; + } + + @Override + public String getJdbcSchemaName(CatalogAndSchema schema) { + return correctObjectName((schema.getCatalogName() == null) ? schema.getSchemaName() : schema.getCatalogName(), Schema.class); + } + + @Override + protected String getAutoIncrementClause(final String generationType, final Boolean defaultOnNull) { + if (StringUtil.isEmpty(generationType)) { + return super.getAutoIncrementClause(); + } + + String autoIncrementClause = "GENERATED %s AS IDENTITY"; // %s -- [ ALWAYS | BY DEFAULT [ ON NULL ] ] + String generationStrategy = generationType; + if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) { + generationStrategy += " ON NULL"; + } + return String.format(autoIncrementClause, generationStrategy); + } + + @Override + public String generatePrimaryKeyName(String tableName) { + if (tableName.length() > 27) { + //noinspection HardCodedStringLiteral + return "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27); + } else { + //noinspection HardCodedStringLiteral + return "PK_" + tableName.toUpperCase(Locale.US); + } + } + + @Override + public boolean isReservedWord(String objectName) { + return reservedWords.contains(objectName.toUpperCase()); + } + + @Override + public boolean supportsSequences() { + return true; + } + + /** + * Oracle supports catalogs in liquibase terms + * + * @return false + */ + @Override + public boolean supportsSchemas() { + return false; + } + + @Override + protected String getConnectionCatalogName() throws DatabaseException { + if (getConnection() instanceof OfflineConnection) { + return getConnection().getCatalog(); + } + try { + //noinspection HardCodedStringLiteral + return Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class); + } catch (Exception e) { + //noinspection HardCodedStringLiteral + Scope.getCurrentScope().getLog(getClass()).info("Error getting default schema", e); + } + return null; + } + + @Override + public String getDefaultCatalogName() {//NOPMD + return (super.getDefaultCatalogName() == null) ? null : super.getDefaultCatalogName().toUpperCase(Locale.US); + } + + /** + *

Returns an Oracle date literal with the same value as a string formatted using ISO 8601.

+ * + *

Convert an ISO8601 date string to one of the following results: + * to_date('1995-05-23', 'YYYY-MM-DD') + * to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')

+ *

+ * Implementation restriction:
+ * Currently, only the following subsets of ISO8601 are supported:
+ *

    + *
  • YYYY-MM-DD
  • + *
  • YYYY-MM-DDThh:mm:ss
  • + *
+ */ + @Override + public String getDateLiteral(String isoDate) { + String normalLiteral = super.getDateLiteral(isoDate); + + if (isDateOnly(isoDate)) { + return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD')"; + } else if (isTimeOnly(isoDate)) { + return "TO_DATE(" + normalLiteral + ", 'HH24:MI:SS')"; + } else if (isTimestamp(isoDate)) { + return "TO_TIMESTAMP(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS.FF')"; + } else if (isDateTime(isoDate)) { + int seppos = normalLiteral.lastIndexOf('.'); + if (seppos != -1) { + normalLiteral = normalLiteral.substring(0, seppos) + "'"; + } + return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS')"; + } + return "UNSUPPORTED:" + isoDate; + } + + @Override + public boolean isSystemObject(DatabaseObject example) { + if (example == null) { + return false; + } + + if (this.isLiquibaseObject(example)) { + return false; + } + + if (example instanceof Schema) { + //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral + if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) { + return true; + } + //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral + if ("SYSTEM".equals(example.getSchema().getCatalogName()) || "SYS".equals(example.getSchema().getCatalogName()) || "CTXSYS".equals(example.getSchema().getCatalogName()) || "XDB".equals(example.getSchema().getCatalogName())) { + return true; + } + } else if (isSystemObject(example.getSchema())) { + return true; + } + if (example instanceof Catalog) { + //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral + if (("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName()))) { + return true; + } + } else if (example.getName() != null) { + //noinspection HardCodedStringLiteral + if (example.getName().startsWith("BIN$")) { //oracle deleted table + boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin(); + if (!filteredInOriginalQuery) { + filteredInOriginalQuery = StringUtil.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName()); + } + + if (filteredInOriginalQuery) { + return !((example instanceof PrimaryKey) || (example instanceof Index) || (example instanceof + liquibase.statement.UniqueConstraint)); + } else { + return true; + } + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("AQ$")) { //oracle AQ tables + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("DR$")) { //oracle index tables + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("SYS_IOT_OVER")) { //oracle system table + return true; + } else //noinspection HardCodedStringLiteral,HardCodedStringLiteral + if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) { + // CORE-1768 - Oracle creates these for spatial indices and will remove them when the index is removed. + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("MLOG$_")) { //Created by materliaized view logs for every table that is part of a materialized view. Not available for DDL operations. + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("RUPD$_")) { //Created by materialized view log tables using primary keys. Not available for DDL operations. + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("WM$_")) { //Workspace Manager backup tables. + return true; + } else //noinspection HardCodedStringLiteral + if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) { //This table contains the name of the Java object, the date it was loaded, and has a BLOB column to store the Java object. + return true; + } else //noinspection HardCodedStringLiteral + if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) { //This is a hash table that tracks the loading of Java objects into a schema. + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("ISEQ$$_")) { //System-generated sequence + return true; + } else //noinspection HardCodedStringLiteral + if (example.getName().startsWith("USLOG$")) { //for update materialized view + return true; + } else if (example.getName().startsWith("SYS_FBA")) { //for Flashback tables + return true; + } + } + + return super.isSystemObject(example); + } + + @Override + public boolean supportsAutoIncrement() { + // Oracle supports Identity beginning with version 12c + boolean isAutoIncrementSupported = false; + + try { + if (getDatabaseMajorVersion() >= 12) { + isAutoIncrementSupported = true; + } + + // Returning true will generate create table command with 'IDENTITY' clause, example: + // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) GENERATED BY DEFAULT AS IDENTITY NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey)); + + // While returning false will continue to generate create table command without 'IDENTITY' clause, example: + // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey)); + + } catch (DatabaseException ex) { + isAutoIncrementSupported = false; + } + + return isAutoIncrementSupported; + } + + +// public Set findUniqueConstraints(String schema) throws DatabaseException { +// Set returnSet = new HashSet(); +// +// List maps = new Executor(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME")); +// +// UniqueConstraint constraint = null; +// for (Map map : maps) { +// if (constraint == null || !constraint.getName().equals(constraint.getName())) { +// returnSet.add(constraint); +// Table table = new Table((String) map.get("TABLE_NAME")); +// constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table); +// } +// } +// if (constraint != null) { +// returnSet.add(constraint); +// } +// +// return returnSet; +// } + + @Override + public boolean supportsRestrictForeignKeys() { + return false; + } + + @Override + public int getDataTypeMaxParameters(String dataTypeName) { + //noinspection HardCodedStringLiteral + if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) { + return 0; + } + //noinspection HardCodedStringLiteral + if ("BINARY_DOUBLE".equals(dataTypeName.toUpperCase())) { + return 0; + } + return super.getDataTypeMaxParameters(dataTypeName); + } + + public String getSystemTableWhereClause(String tableNameColumn) { + List clauses = new ArrayList(Arrays.asList("BIN$", + "AQ$", + "DR$", + "SYS_IOT_OVER", + "MLOG$_", + "RUPD$_", + "WM$_", + "ISEQ$$_", + "USLOG$", + "SYS_FBA")); + + for (int i = 0;i getUserDefinedTypes() { + if (userDefinedTypes == null) { + userDefinedTypes = new HashSet<>(); + if ((getConnection() != null) && !(getConnection() instanceof OfflineConnection)) { + try { + try { + //noinspection HardCodedStringLiteral + userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class)); + } catch (DatabaseException e) { //fall back to USER_TYPES if the user cannot see ALL_TYPES + //noinspection HardCodedStringLiteral + userDefinedTypes.addAll(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class)); + } + } catch (DatabaseException e) { + //ignore error + } + } + } + + return userDefinedTypes; + } + + @Override + public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) { + //noinspection HardCodedStringLiteral + if ((databaseFunction != null) && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) { + return databaseFunction.toString(); + } + if ((databaseFunction instanceof SequenceNextValueFunction) || (databaseFunction instanceof + SequenceCurrentValueFunction)) { + String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction); + // replace "myschema.my_seq".nextval with "myschema"."my_seq".nextval + return quotedSeq.replaceFirst("\"([^\\.\"]+)\\.([^\\.\"]+)\"", "\"$1\".\"$2\""); + + } + + return super.generateDatabaseFunctionValue(databaseFunction); + } + + @Override + public ValidationErrors validate() { + ValidationErrors errors = super.validate(); + DatabaseConnection connection = getConnection(); + if ((connection == null) || (connection instanceof OfflineConnection)) { + //noinspection HardCodedStringLiteral + Scope.getCurrentScope().getLog(getClass()).info("Cannot validate offline database"); + return errors; + } + + if (!canAccessDbaRecycleBin()) { + errors.addWarning(getDbaRecycleBinWarning()); + } + + return errors; + + } + + public String getDbaRecycleBinWarning() { + //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral, + // HardCodedStringLiteral + //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral + return "Liquibase needs to access the DBA_RECYCLEBIN table so we can automatically handle the case where " + + "constraints are deleted and restored. Since Oracle doesn't properly restore the original table names " + + "referenced in the constraint, we use the information from the DBA_RECYCLEBIN to automatically correct this" + + " issue.\n" + + "\n" + + "The user you used to connect to the database (" + getConnection().getConnectionUserName() + + ") needs to have \"SELECT ON SYS.DBA_RECYCLEBIN\" permissions set before we can perform this operation. " + + "Please run the following SQL to set the appropriate permissions, and try running the command again.\n" + + "\n" + + " GRANT SELECT ON SYS.DBA_RECYCLEBIN TO " + getConnection().getConnectionUserName() + ";"; + } + + public boolean canAccessDbaRecycleBin() { + if (canAccessDbaRecycleBin == null) { + DatabaseConnection connection = getConnection(); + if ((connection == null) || (connection instanceof OfflineConnection)) { + return false; + } + + Statement statement = null; + try { + statement = ((JdbcConnection) connection).createStatement(); + @SuppressWarnings("HardCodedStringLiteral") ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1"); + resultSet.close(); //don't need to do anything with the result set, just make sure statement ran. + this.canAccessDbaRecycleBin = true; + } catch (Exception e) { + //noinspection HardCodedStringLiteral + if ((e instanceof SQLException) && e.getMessage().startsWith("ORA-00942")) { //ORA-00942: table or view does not exist + this.canAccessDbaRecycleBin = false; + } else { + //noinspection HardCodedStringLiteral + Scope.getCurrentScope().getLog(getClass()).warning("Cannot check dba_recyclebin access", e); + this.canAccessDbaRecycleBin = false; + } + } finally { + JdbcUtils.close(null, statement); + } + } + + return canAccessDbaRecycleBin; + } + + @Override + public boolean supportsNotNullConstraintNames() { + return true; + } + + /** + * Tests if the given String would be a valid identifier in Oracle DBMS. In Oracle, a valid identifier has + * the following form (case-insensitive comparison): + * 1st character: A-Z + * 2..n characters: A-Z0-9$_# + * The maximum length of an identifier differs by Oracle version and object type. + */ + public boolean isValidOracleIdentifier(String identifier, Class type) { + if ((identifier == null) || (identifier.length() < 1)) + return false; + + if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$")) + return false; + + /* + * @todo It seems we currently do not have a class for tablespace identifiers, and all other classes + * we do know seem to be supported as 12cR2 long identifiers, so: + */ + return (identifier.length() <= LONG_IDENTIFIERS_LEGNTH); + } + + /** + * Returns the maximum number of bytes (NOT: characters) for an identifier. For Oracle <=12c Release 20, this + * is 30 bytes, and starting from 12cR2, up to 128 (except for tablespaces, PDB names and some other rather rare + * object types). + * + * @return the maximum length of an object identifier, in bytes + */ + public int getIdentifierMaximumLength() { + try { + if (getDatabaseMajorVersion() < ORACLE_12C_MAJOR_VERSION) { + return SHORT_IDENTIFIERS_LENGTH; + } else if ((getDatabaseMajorVersion() == ORACLE_12C_MAJOR_VERSION) && (getDatabaseMinorVersion() <= 1)) { + return SHORT_IDENTIFIERS_LENGTH; + } else { + return LONG_IDENTIFIERS_LEGNTH; + } + } catch (DatabaseException ex) { + throw new UnexpectedLiquibaseException("Cannot determine the Oracle database version number", ex); + } + + } +} diff --git a/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/datatype/core/BooleanType.java b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/datatype/core/BooleanType.java new file mode 100644 index 0000000..cda2492 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/liquibase/datatype/core/BooleanType.java @@ -0,0 +1,165 @@ +package liquibase.datatype.core; + +import liquibase.change.core.LoadDataChange; +import liquibase.database.Database; +import liquibase.database.core.*; +import liquibase.datatype.DataTypeInfo; +import liquibase.datatype.DatabaseDataType; +import liquibase.datatype.LiquibaseDataType; +import liquibase.exception.UnexpectedLiquibaseException; +import liquibase.statement.DatabaseFunction; +import liquibase.util.StringUtil; + +import java.util.Locale; +import java.util.regex.Pattern; + +@DataTypeInfo(name = "boolean", aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit", "bool"}, minParameters = 0, maxParameters = 0, priority = LiquibaseDataType.PRIORITY_DEFAULT) +public class BooleanType extends LiquibaseDataType { + + @Override + public DatabaseDataType toDatabaseDataType(Database database) { + String originalDefinition = StringUtil.trimToEmpty(getRawDefinition()); + if ((database instanceof Firebird3Database)) { + return new DatabaseDataType("BOOLEAN"); + } + + if ((database instanceof Db2zDatabase) || (database instanceof FirebirdDatabase)) { + return new DatabaseDataType("SMALLINT"); + } else if (database instanceof MSSQLDatabase) { + return new DatabaseDataType(database.escapeDataTypeName("bit")); + } else if (database instanceof MySQLDatabase) { + if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) { + return new DatabaseDataType("BIT", getParameters()); + } + return new DatabaseDataType("BIT", 1); + } else if (database instanceof OracleDatabase) { + return new DatabaseDataType("NUMBER", 1); + } else if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase)) { + return new DatabaseDataType("BIT"); + } else if (database instanceof DerbyDatabase) { + if (((DerbyDatabase) database).supportsBooleanDataType()) { + return new DatabaseDataType("BOOLEAN"); + } else { + return new DatabaseDataType("SMALLINT"); + } + } else if (database instanceof DB2Database) { + if (((DB2Database) database).supportsBooleanDataType()) + return new DatabaseDataType("BOOLEAN"); + else + return new DatabaseDataType("SMALLINT"); + } else if (database instanceof HsqlDatabase) { + return new DatabaseDataType("BOOLEAN"); + } else if (database instanceof PostgresDatabase) { + if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) { + return new DatabaseDataType("BIT", getParameters()); + } + } else if (database instanceof DmDatabase) { // dhb52: DM Support + return new DatabaseDataType("bit"); + } + + return super.toDatabaseDataType(database); + } + + @Override + public String objectToSql(Object value, Database database) { + if ((value == null) || "null".equals(value.toString().toLowerCase(Locale.US))) { + return null; + } + + String returnValue; + if (value instanceof String) { + value = ((String) value).replaceAll("'", ""); + if ("true".equals(((String) value).toLowerCase(Locale.US)) || "1".equals(value) || "b'1'".equals(((String) value).toLowerCase(Locale.US)) || "t".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getTrueBooleanValue(database).toLowerCase(Locale.US))) { + returnValue = this.getTrueBooleanValue(database); + } else if ("false".equals(((String) value).toLowerCase(Locale.US)) || "0".equals(value) || "b'0'".equals( + ((String) value).toLowerCase(Locale.US)) || "f".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getFalseBooleanValue(database).toLowerCase(Locale.US))) { + returnValue = this.getFalseBooleanValue(database); + } else if (database instanceof PostgresDatabase && Pattern.matches("b?([01])\\1*(::bit|::\"bit\")?", (String) value)) { + returnValue = "b'" + + value.toString() + .replace("b", "") + .replace("\"", "") + .replace("::it", "") + + "'::\"bit\""; + } else { + throw new UnexpectedLiquibaseException("Unknown boolean value: " + value); + } + } else if (value instanceof Long) { + if (Long.valueOf(1).equals(value)) { + returnValue = this.getTrueBooleanValue(database); + } else { + returnValue = this.getFalseBooleanValue(database); + } + } else if (value instanceof Number) { + if (value.equals(1) || "1".equals(value.toString()) || "1.0".equals(value.toString())) { + returnValue = this.getTrueBooleanValue(database); + } else { + returnValue = this.getFalseBooleanValue(database); + } + } else if (value instanceof DatabaseFunction) { + return value.toString(); + } else if (value instanceof Boolean) { + if (((Boolean) value)) { + returnValue = this.getTrueBooleanValue(database); + } else { + returnValue = this.getFalseBooleanValue(database); + } + } else { + throw new UnexpectedLiquibaseException("Cannot convert type " + value.getClass() + " to a boolean value"); + } + + return returnValue; + } + + protected boolean isNumericBoolean(Database database) { + if (database instanceof Firebird3Database) { + return false; + } + if (database instanceof DerbyDatabase) { + return !((DerbyDatabase) database).supportsBooleanDataType(); + } else if (database instanceof DB2Database) { + return !((DB2Database) database).supportsBooleanDataType(); + } + return (database instanceof Db2zDatabase) + || (database instanceof FirebirdDatabase) + || (database instanceof MSSQLDatabase) + || (database instanceof MySQLDatabase) + || (database instanceof OracleDatabase) + || (database instanceof SQLiteDatabase) + || (database instanceof SybaseASADatabase) + || (database instanceof SybaseDatabase) + || (database instanceof DmDatabase); // dhb52: DM Support + } + + /** + * The database-specific value to use for "false" "boolean" columns. + */ + public String getFalseBooleanValue(Database database) { + if (isNumericBoolean(database)) { + return "0"; + } + if (database instanceof InformixDatabase) { + return "'f'"; + } + return "FALSE"; + } + + /** + * The database-specific value to use for "true" "boolean" columns. + */ + public String getTrueBooleanValue(Database database) { + if (isNumericBoolean(database)) { + return "1"; + } + if (database instanceof InformixDatabase) { + return "'t'"; + } + return "TRUE"; + } + + @Override + public LoadDataChange.LOAD_DATA_TYPE getLoadTypeName() { + return LoadDataChange.LOAD_DATA_TYPE.BOOLEAN; + } + +} diff --git a/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java new file mode 100644 index 0000000..33c52d5 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java @@ -0,0 +1,2068 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.common.engine.impl; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; + +import javax.naming.InitialContext; +import javax.sql.DataSource; + +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.builder.xml.XMLConfigBuilder; +import org.apache.ibatis.builder.xml.XMLMapperBuilder; +import org.apache.ibatis.datasource.pooled.PooledDataSource; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory; +import org.apache.ibatis.transaction.TransactionFactory; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.apache.ibatis.transaction.managed.ManagedTransactionFactory; +import org.apache.ibatis.type.ArrayTypeHandler; +import org.apache.ibatis.type.BigDecimalTypeHandler; +import org.apache.ibatis.type.BlobInputStreamTypeHandler; +import org.apache.ibatis.type.BlobTypeHandler; +import org.apache.ibatis.type.BooleanTypeHandler; +import org.apache.ibatis.type.ByteTypeHandler; +import org.apache.ibatis.type.ClobTypeHandler; +import org.apache.ibatis.type.DateOnlyTypeHandler; +import org.apache.ibatis.type.DateTypeHandler; +import org.apache.ibatis.type.DoubleTypeHandler; +import org.apache.ibatis.type.FloatTypeHandler; +import org.apache.ibatis.type.IntegerTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.LongTypeHandler; +import org.apache.ibatis.type.NClobTypeHandler; +import org.apache.ibatis.type.NStringTypeHandler; +import org.apache.ibatis.type.ShortTypeHandler; +import org.apache.ibatis.type.SqlxmlTypeHandler; +import org.apache.ibatis.type.StringTypeHandler; +import org.apache.ibatis.type.TimeOnlyTypeHandler; +import org.apache.ibatis.type.TypeHandlerRegistry; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher; +import org.flowable.common.engine.api.delegate.event.FlowableEventListener; +import org.flowable.common.engine.api.engine.EngineLifecycleListener; +import org.flowable.common.engine.impl.agenda.AgendaOperationRunner; +import org.flowable.common.engine.impl.cfg.CommandExecutorImpl; +import org.flowable.common.engine.impl.cfg.IdGenerator; +import org.flowable.common.engine.impl.cfg.TransactionContextFactory; +import org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContextFactory; +import org.flowable.common.engine.impl.db.CommonDbSchemaManager; +import org.flowable.common.engine.impl.db.DbSqlSessionFactory; +import org.flowable.common.engine.impl.db.LogSqlExecutionTimePlugin; +import org.flowable.common.engine.impl.db.MybatisTypeAliasConfigurator; +import org.flowable.common.engine.impl.db.MybatisTypeHandlerConfigurator; +import org.flowable.common.engine.impl.db.SchemaManager; +import org.flowable.common.engine.impl.event.EventDispatchAction; +import org.flowable.common.engine.impl.event.FlowableEventDispatcherImpl; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandConfig; +import org.flowable.common.engine.impl.interceptor.CommandContextFactory; +import org.flowable.common.engine.impl.interceptor.CommandContextInterceptor; +import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.flowable.common.engine.impl.interceptor.CommandInterceptor; +import org.flowable.common.engine.impl.interceptor.CrDbRetryInterceptor; +import org.flowable.common.engine.impl.interceptor.DefaultCommandInvoker; +import org.flowable.common.engine.impl.interceptor.LogInterceptor; +import org.flowable.common.engine.impl.interceptor.SessionFactory; +import org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor; +import org.flowable.common.engine.impl.lock.LockManager; +import org.flowable.common.engine.impl.lock.LockManagerImpl; +import org.flowable.common.engine.impl.logging.LoggingListener; +import org.flowable.common.engine.impl.logging.LoggingSession; +import org.flowable.common.engine.impl.logging.LoggingSessionFactory; +import org.flowable.common.engine.impl.persistence.GenericManagerFactory; +import org.flowable.common.engine.impl.persistence.StrongUuidGenerator; +import org.flowable.common.engine.impl.persistence.cache.EntityCache; +import org.flowable.common.engine.impl.persistence.cache.EntityCacheImpl; +import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntityManager; +import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntityManagerImpl; +import org.flowable.common.engine.impl.persistence.entity.Entity; +import org.flowable.common.engine.impl.persistence.entity.PropertyEntityManager; +import org.flowable.common.engine.impl.persistence.entity.PropertyEntityManagerImpl; +import org.flowable.common.engine.impl.persistence.entity.TableDataManager; +import org.flowable.common.engine.impl.persistence.entity.TableDataManagerImpl; +import org.flowable.common.engine.impl.persistence.entity.data.ByteArrayDataManager; +import org.flowable.common.engine.impl.persistence.entity.data.PropertyDataManager; +import org.flowable.common.engine.impl.persistence.entity.data.impl.MybatisByteArrayDataManager; +import org.flowable.common.engine.impl.persistence.entity.data.impl.MybatisPropertyDataManager; +import org.flowable.common.engine.impl.runtime.Clock; +import org.flowable.common.engine.impl.service.CommonEngineServiceImpl; +import org.flowable.common.engine.impl.util.DefaultClockImpl; +import org.flowable.common.engine.impl.util.IoUtil; +import org.flowable.common.engine.impl.util.ReflectUtil; +import org.flowable.eventregistry.api.EventRegistryEventConsumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +public abstract class AbstractEngineConfiguration { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + /** The tenant id indicating 'no tenant' */ + public static final String NO_TENANT_ID = ""; + + /** + * Checks the version of the DB schema against the library when the form engine is being created and throws an exception if the versions don't match. + */ + public static final String DB_SCHEMA_UPDATE_FALSE = "false"; + public static final String DB_SCHEMA_UPDATE_CREATE = "create"; + public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop"; + + /** + * Creates the schema when the form engine is being created and drops the schema when the form engine is being closed. + */ + public static final String DB_SCHEMA_UPDATE_DROP_CREATE = "drop-create"; + + /** + * Upon building of the process engine, a check is performed and an update of the schema is performed if it is necessary. + */ + public static final String DB_SCHEMA_UPDATE_TRUE = "true"; + + protected boolean forceCloseMybatisConnectionPool = true; + + protected String databaseType; + protected String jdbcDriver = "org.h2.Driver"; + protected String jdbcUrl = "jdbc:h2:tcp://localhost/~/flowable"; + protected String jdbcUsername = "sa"; + protected String jdbcPassword = ""; + protected String dataSourceJndiName; + protected int jdbcMaxActiveConnections = 16; + protected int jdbcMaxIdleConnections = 8; + protected int jdbcMaxCheckoutTime; + protected int jdbcMaxWaitTime; + protected boolean jdbcPingEnabled; + protected String jdbcPingQuery; + protected int jdbcPingConnectionNotUsedFor; + protected int jdbcDefaultTransactionIsolationLevel; + protected DataSource dataSource; + protected SchemaManager commonSchemaManager; + protected SchemaManager schemaManager; + protected Command schemaManagementCmd; + + protected String databaseSchemaUpdate = DB_SCHEMA_UPDATE_FALSE; + + /** + * Whether to use a lock when performing the database schema create or update operations. + */ + protected boolean useLockForDatabaseSchemaUpdate = false; + + protected String xmlEncoding = "UTF-8"; + + // COMMAND EXECUTORS /////////////////////////////////////////////// + + protected CommandExecutor commandExecutor; + protected Collection defaultCommandInterceptors; + protected CommandConfig defaultCommandConfig; + protected CommandConfig schemaCommandConfig; + protected CommandContextFactory commandContextFactory; + protected CommandInterceptor commandInvoker; + + protected AgendaOperationRunner agendaOperationRunner = (commandContext, runnable) -> runnable.run(); + + protected List customPreCommandInterceptors; + protected List customPostCommandInterceptors; + protected List commandInterceptors; + + protected Map engineConfigurations = new HashMap<>(); + protected Map serviceConfigurations = new HashMap<>(); + + protected ClassLoader classLoader; + /** + * Either use Class.forName or ClassLoader.loadClass for class loading. See http://forums.activiti.org/content/reflectutilloadclass-and-custom- classloader + */ + protected boolean useClassForNameClassLoading = true; + + protected List engineLifecycleListeners; + + // Event Registry ////////////////////////////////////////////////// + protected Map eventRegistryEventConsumers = new HashMap<>(); + + // MYBATIS SQL SESSION FACTORY ///////////////////////////////////// + + protected boolean isDbHistoryUsed = true; + protected DbSqlSessionFactory dbSqlSessionFactory; + protected SqlSessionFactory sqlSessionFactory; + protected TransactionFactory transactionFactory; + protected TransactionContextFactory transactionContextFactory; + + /** + * If set to true, enables bulk insert (grouping sql inserts together). Default true. + * For some databases (eg DB2+z/OS) needs to be set to false. + */ + protected boolean isBulkInsertEnabled = true; + + /** + * Some databases have a limit of how many parameters one sql insert can have (eg SQL Server, 2000 params (!= insert statements) ). Tweak this parameter in case of exceptions indicating too much + * is being put into one bulk insert, or make it higher if your database can cope with it and there are inserts with a huge amount of data. + *

+ * By default: 100 (55 for mssql server as it has a hard limit of 2000 parameters in a statement) + */ + protected int maxNrOfStatementsInBulkInsert = 100; + + public int DEFAULT_MAX_NR_OF_STATEMENTS_BULK_INSERT_SQL_SERVER = 55; // currently Execution has most params (35). 2000 / 35 = 57. + + protected String mybatisMappingFile; + protected Set> customMybatisMappers; + protected Set customMybatisXMLMappers; + protected List customMybatisInterceptors; + + protected Set dependentEngineMyBatisXmlMappers; + protected List dependentEngineMybatisTypeAliasConfigs; + protected List dependentEngineMybatisTypeHandlerConfigs; + + // SESSION FACTORIES /////////////////////////////////////////////// + protected List customSessionFactories; + protected Map, SessionFactory> sessionFactories; + + protected boolean enableEventDispatcher = true; + protected FlowableEventDispatcher eventDispatcher; + protected List eventListeners; + protected Map> typedEventListeners; + protected List additionalEventDispatchActions; + + protected LoggingListener loggingListener; + + protected boolean transactionsExternallyManaged; + + /** + * Flag that can be set to configure or not a relational database is used. This is useful for custom implementations that do not use relational databases at all. + * + * If true (default), the {@link AbstractEngineConfiguration#getDatabaseSchemaUpdate()} value will be used to determine what needs to happen wrt the database schema. + * + * If false, no validation or schema creation will be done. That means that the database schema must have been created 'manually' before but the engine does not validate whether the schema is + * correct. The {@link AbstractEngineConfiguration#getDatabaseSchemaUpdate()} value will not be used. + */ + protected boolean usingRelationalDatabase = true; + + /** + * Flag that can be set to configure whether or not a schema is used. This is useful for custom implementations that do not use relational databases at all. + * Setting {@link #usingRelationalDatabase} to true will automatically imply using a schema. + */ + protected boolean usingSchemaMgmt = true; + + /** + * Allows configuring a database table prefix which is used for all runtime operations of the process engine. For example, if you specify a prefix named 'PRE1.', Flowable will query for executions + * in a table named 'PRE1.ACT_RU_EXECUTION_'. + * + *

+ * NOTE: the prefix is not respected by automatic database schema management. If you use {@link AbstractEngineConfiguration#DB_SCHEMA_UPDATE_CREATE_DROP} or + * {@link AbstractEngineConfiguration#DB_SCHEMA_UPDATE_TRUE}, Flowable will create the database tables using the default names, regardless of the prefix configured here. + */ + protected String databaseTablePrefix = ""; + + /** + * Escape character for doing wildcard searches. + * + * This will be added at then end of queries that include for example a LIKE clause. For example: SELECT * FROM table WHERE column LIKE '%\%%' ESCAPE '\'; + */ + protected String databaseWildcardEscapeCharacter; + + /** + * database catalog to use + */ + protected String databaseCatalog = ""; + + /** + * In some situations you want to set the schema to use for table checks / generation if the database metadata doesn't return that correctly, see https://jira.codehaus.org/browse/ACT-1220, + * https://jira.codehaus.org/browse/ACT-1062 + */ + protected String databaseSchema; + + /** + * Set to true in case the defined databaseTablePrefix is a schema-name, instead of an actual table name prefix. This is relevant for checking if Flowable-tables exist, the databaseTablePrefix + * will not be used here - since the schema is taken into account already, adding a prefix for the table-check will result in wrong table-names. + */ + protected boolean tablePrefixIsSchema; + + /** + * Set to true if the latest version of a definition should be retrieved, ignoring a possible parent deployment id value + */ + protected boolean alwaysLookupLatestDefinitionVersion; + + /** + * Set to true if by default lookups should fallback to the default tenant (an empty string by default or a defined tenant value) + */ + protected boolean fallbackToDefaultTenant; + + /** + * Default tenant provider that is executed when looking up definitions, in case the global or local fallback to default tenant value is true + */ + protected DefaultTenantProvider defaultTenantProvider = (tenantId, scope, scopeKey) -> NO_TENANT_ID; + + /** + * Enables the MyBatis plugin that logs the execution time of sql statements. + */ + protected boolean enableLogSqlExecutionTime; + + protected Properties databaseTypeMappings = getDefaultDatabaseTypeMappings(); + + /** + * Duration between the checks when acquiring a lock. + */ + protected Duration lockPollRate = Duration.ofSeconds(10); + + /** + * Duration to wait for the DB Schema lock before giving up. + */ + protected Duration schemaLockWaitTime = Duration.ofMinutes(5); + + // DATA MANAGERS ////////////////////////////////////////////////////////////////// + + protected PropertyDataManager propertyDataManager; + protected ByteArrayDataManager byteArrayDataManager; + protected TableDataManager tableDataManager; + + // ENTITY MANAGERS //////////////////////////////////////////////////////////////// + + protected PropertyEntityManager propertyEntityManager; + protected ByteArrayEntityManager byteArrayEntityManager; + + protected List customPreDeployers; + protected List customPostDeployers; + protected List deployers; + + // CONFIGURATORS //////////////////////////////////////////////////////////// + + protected boolean enableConfiguratorServiceLoader = true; // Enabled by default. In certain environments this should be set to false (eg osgi) + protected List configurators; // The injected configurators + protected List allConfigurators; // Including auto-discovered configurators + protected EngineConfigurator idmEngineConfigurator; + protected EngineConfigurator eventRegistryConfigurator; + + public static final String PRODUCT_NAME_POSTGRES = "PostgreSQL"; + public static final String PRODUCT_NAME_CRDB = "CockroachDB"; + + public static final String DATABASE_TYPE_H2 = "h2"; + public static final String DATABASE_TYPE_HSQL = "hsql"; + public static final String DATABASE_TYPE_MYSQL = "mysql"; + public static final String DATABASE_TYPE_ORACLE = "oracle"; + public static final String DATABASE_TYPE_POSTGRES = "postgres"; + public static final String DATABASE_TYPE_MSSQL = "mssql"; + public static final String DATABASE_TYPE_DB2 = "db2"; + public static final String DATABASE_TYPE_COCKROACHDB = "cockroachdb"; + + public static Properties getDefaultDatabaseTypeMappings() { + Properties databaseTypeMappings = new Properties(); + databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2); + databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL); + databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL); + databaseTypeMappings.setProperty("MariaDB", DATABASE_TYPE_MYSQL); + databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE); + databaseTypeMappings.setProperty(PRODUCT_NAME_POSTGRES, DATABASE_TYPE_POSTGRES); + databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL); + databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXPPC64LE", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty(PRODUCT_NAME_CRDB, DATABASE_TYPE_COCKROACHDB); + databaseTypeMappings.setProperty("DM DBMS", DATABASE_TYPE_ORACLE); // dhb52: DM support + return databaseTypeMappings; + } + + protected Map beans; + + protected IdGenerator idGenerator; + protected boolean usePrefixId; + + protected Clock clock; + protected ObjectMapper objectMapper; + + // Variables + + public static final int DEFAULT_GENERIC_MAX_LENGTH_STRING = 4000; + public static final int DEFAULT_ORACLE_MAX_LENGTH_STRING = 2000; + + /** + * Define a max length for storing String variable types in the database. Mainly used for the Oracle NVARCHAR2 limit of 2000 characters + */ + protected int maxLengthStringVariableType = -1; + + protected void initEngineConfigurations() { + addEngineConfiguration(getEngineCfgKey(), getEngineScopeType(), this); + } + + // DataSource + // /////////////////////////////////////////////////////////////// + + protected void initDataSource() { + if (dataSource == null) { + if (dataSourceJndiName != null) { + try { + dataSource = (DataSource) new InitialContext().lookup(dataSourceJndiName); + } catch (Exception e) { + throw new FlowableException("couldn't lookup datasource from " + dataSourceJndiName + ": " + e.getMessage(), e); + } + + } else if (jdbcUrl != null) { + if ((jdbcDriver == null) || (jdbcUsername == null)) { + throw new FlowableException("DataSource or JDBC properties have to be specified in a process engine configuration"); + } + + logger.debug("initializing datasource to db: {}", jdbcUrl); + + if (logger.isInfoEnabled()) { + logger.info("Configuring Datasource with following properties (omitted password for security)"); + logger.info("datasource driver : {}", jdbcDriver); + logger.info("datasource url : {}", jdbcUrl); + logger.info("datasource user name : {}", jdbcUsername); + } + + PooledDataSource pooledDataSource = new PooledDataSource(this.getClass().getClassLoader(), jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword); + + if (jdbcMaxActiveConnections > 0) { + pooledDataSource.setPoolMaximumActiveConnections(jdbcMaxActiveConnections); + } + if (jdbcMaxIdleConnections > 0) { + pooledDataSource.setPoolMaximumIdleConnections(jdbcMaxIdleConnections); + } + if (jdbcMaxCheckoutTime > 0) { + pooledDataSource.setPoolMaximumCheckoutTime(jdbcMaxCheckoutTime); + } + if (jdbcMaxWaitTime > 0) { + pooledDataSource.setPoolTimeToWait(jdbcMaxWaitTime); + } + if (jdbcPingEnabled) { + pooledDataSource.setPoolPingEnabled(true); + if (jdbcPingQuery != null) { + pooledDataSource.setPoolPingQuery(jdbcPingQuery); + } + pooledDataSource.setPoolPingConnectionsNotUsedFor(jdbcPingConnectionNotUsedFor); + } + if (jdbcDefaultTransactionIsolationLevel > 0) { + pooledDataSource.setDefaultTransactionIsolationLevel(jdbcDefaultTransactionIsolationLevel); + } + dataSource = pooledDataSource; + } + } + + if (databaseType == null) { + initDatabaseType(); + } + } + + public void initDatabaseType() { + Connection connection = null; + try { + connection = dataSource.getConnection(); + DatabaseMetaData databaseMetaData = connection.getMetaData(); + String databaseProductName = databaseMetaData.getDatabaseProductName(); + logger.debug("database product name: '{}'", databaseProductName); + + // CRDB does not expose the version through the jdbc driver, so we need to fetch it through version(). + if (PRODUCT_NAME_POSTGRES.equalsIgnoreCase(databaseProductName)) { + try (PreparedStatement preparedStatement = connection.prepareStatement("select version() as version;"); + ResultSet resultSet = preparedStatement.executeQuery()) { + String version = null; + if (resultSet.next()) { + version = resultSet.getString("version"); + } + + if (StringUtils.isNotEmpty(version) && version.toLowerCase().startsWith(PRODUCT_NAME_CRDB.toLowerCase())) { + databaseProductName = PRODUCT_NAME_CRDB; + logger.info("CockroachDB version '{}' detected", version); + } + } + } + + databaseType = databaseTypeMappings.getProperty(databaseProductName); + if (databaseType == null) { + throw new FlowableException("couldn't deduct database type from database product name '" + databaseProductName + "'"); + } + logger.debug("using database type: {}", databaseType); + + } catch (SQLException e) { + throw new RuntimeException("Exception while initializing Database connection", e); + } finally { + try { + if (connection != null) { + connection.close(); + } + } catch (SQLException e) { + logger.error("Exception while closing the Database connection", e); + } + } + + // Special care for MSSQL, as it has a hard limit of 2000 params per statement (incl bulk statement). + // Especially with executions, with 100 as default, this limit is passed. + if (DATABASE_TYPE_MSSQL.equals(databaseType)) { + maxNrOfStatementsInBulkInsert = DEFAULT_MAX_NR_OF_STATEMENTS_BULK_INSERT_SQL_SERVER; + } + } + + public void initSchemaManager() { + if (this.commonSchemaManager == null) { + this.commonSchemaManager = new CommonDbSchemaManager(); + } + } + + // session factories //////////////////////////////////////////////////////// + + public void addSessionFactory(SessionFactory sessionFactory) { + sessionFactories.put(sessionFactory.getSessionType(), sessionFactory); + } + + public void initCommandContextFactory() { + if (commandContextFactory == null) { + commandContextFactory = new CommandContextFactory(); + } + } + + public void initTransactionContextFactory() { + if (transactionContextFactory == null) { + transactionContextFactory = new StandaloneMybatisTransactionContextFactory(); + } + } + + public void initCommandExecutors() { + initDefaultCommandConfig(); + initSchemaCommandConfig(); + initCommandInvoker(); + initCommandInterceptors(); + initCommandExecutor(); + } + + + public void initDefaultCommandConfig() { + if (defaultCommandConfig == null) { + defaultCommandConfig = new CommandConfig(); + } + } + + public void initSchemaCommandConfig() { + if (schemaCommandConfig == null) { + schemaCommandConfig = new CommandConfig(); + } + } + + public void initCommandInvoker() { + if (commandInvoker == null) { + commandInvoker = new DefaultCommandInvoker(); + } + } + + public void initCommandInterceptors() { + if (commandInterceptors == null) { + commandInterceptors = new ArrayList<>(); + if (customPreCommandInterceptors != null) { + commandInterceptors.addAll(customPreCommandInterceptors); + } + commandInterceptors.addAll(getDefaultCommandInterceptors()); + if (customPostCommandInterceptors != null) { + commandInterceptors.addAll(customPostCommandInterceptors); + } + commandInterceptors.add(commandInvoker); + } + } + + public Collection getDefaultCommandInterceptors() { + if (defaultCommandInterceptors == null) { + List interceptors = new ArrayList<>(); + interceptors.add(new LogInterceptor()); + + if (DATABASE_TYPE_COCKROACHDB.equals(databaseType)) { + interceptors.add(new CrDbRetryInterceptor()); + } + + CommandInterceptor transactionInterceptor = createTransactionInterceptor(); + if (transactionInterceptor != null) { + interceptors.add(transactionInterceptor); + } + + if (commandContextFactory != null) { + String engineCfgKey = getEngineCfgKey(); + CommandContextInterceptor commandContextInterceptor = new CommandContextInterceptor(commandContextFactory, + classLoader, useClassForNameClassLoading, clock, objectMapper); + engineConfigurations.put(engineCfgKey, this); + commandContextInterceptor.setEngineCfgKey(engineCfgKey); + commandContextInterceptor.setEngineConfigurations(engineConfigurations); + interceptors.add(commandContextInterceptor); + } + + if (transactionContextFactory != null) { + interceptors.add(new TransactionContextInterceptor(transactionContextFactory)); + } + + List additionalCommandInterceptors = getAdditionalDefaultCommandInterceptors(); + if (additionalCommandInterceptors != null) { + interceptors.addAll(additionalCommandInterceptors); + } + + defaultCommandInterceptors = interceptors; + } + return defaultCommandInterceptors; + } + + public abstract String getEngineCfgKey(); + + public abstract String getEngineScopeType(); + + public List getAdditionalDefaultCommandInterceptors() { + return null; + } + + public void initCommandExecutor() { + if (commandExecutor == null) { + CommandInterceptor first = initInterceptorChain(commandInterceptors); + commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first); + } + } + + public CommandInterceptor initInterceptorChain(List chain) { + if (chain == null || chain.isEmpty()) { + throw new FlowableException("invalid command interceptor chain configuration: " + chain); + } + for (int i = 0; i < chain.size() - 1; i++) { + chain.get(i).setNext(chain.get(i + 1)); + } + return chain.get(0); + } + + public abstract CommandInterceptor createTransactionInterceptor(); + + + public void initBeans() { + if (beans == null) { + beans = new HashMap<>(); + } + } + + // id generator + // ///////////////////////////////////////////////////////////// + + public void initIdGenerator() { + if (idGenerator == null) { + idGenerator = new StrongUuidGenerator(); + } + } + + public void initObjectMapper() { + if (objectMapper == null) { + objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + } + } + + public void initClock() { + if (clock == null) { + clock = new DefaultClockImpl(); + } + } + + // Data managers /////////////////////////////////////////////////////////// + + public void initDataManagers() { + if (propertyDataManager == null) { + propertyDataManager = new MybatisPropertyDataManager(idGenerator); + } + + if (byteArrayDataManager == null) { + byteArrayDataManager = new MybatisByteArrayDataManager(idGenerator); + } + } + + // Entity managers ////////////////////////////////////////////////////////// + + public void initEntityManagers() { + if (propertyEntityManager == null) { + propertyEntityManager = new PropertyEntityManagerImpl(this, propertyDataManager); + } + + if (byteArrayEntityManager == null) { + byteArrayEntityManager = new ByteArrayEntityManagerImpl(byteArrayDataManager, getEngineCfgKey(), this::getEventDispatcher); + } + + if (tableDataManager == null) { + tableDataManager = new TableDataManagerImpl(this); + } + } + + // services + // ///////////////////////////////////////////////////////////////// + + protected void initService(Object service) { + if (service instanceof CommonEngineServiceImpl) { + ((CommonEngineServiceImpl) service).setCommandExecutor(commandExecutor); + } + } + + // myBatis SqlSessionFactory + // //////////////////////////////////////////////// + + public void initSessionFactories() { + if (sessionFactories == null) { + sessionFactories = new HashMap<>(); + + if (usingRelationalDatabase) { + initDbSqlSessionFactory(); + } + + addSessionFactory(new GenericManagerFactory(EntityCache.class, EntityCacheImpl.class)); + + if (isLoggingSessionEnabled()) { + if (!sessionFactories.containsKey(LoggingSession.class)) { + LoggingSessionFactory loggingSessionFactory = new LoggingSessionFactory(); + loggingSessionFactory.setLoggingListener(loggingListener); + loggingSessionFactory.setObjectMapper(objectMapper); + sessionFactories.put(LoggingSession.class, loggingSessionFactory); + } + } + + commandContextFactory.setSessionFactories(sessionFactories); + + } else { + if (usingRelationalDatabase) { + initDbSqlSessionFactoryEntitySettings(); + } + } + + if (customSessionFactories != null) { + for (SessionFactory sessionFactory : customSessionFactories) { + addSessionFactory(sessionFactory); + } + } + } + + public void initDbSqlSessionFactory() { + if (dbSqlSessionFactory == null) { + dbSqlSessionFactory = createDbSqlSessionFactory(); + } + dbSqlSessionFactory.setDatabaseType(databaseType); + dbSqlSessionFactory.setSqlSessionFactory(sqlSessionFactory); + dbSqlSessionFactory.setDbHistoryUsed(isDbHistoryUsed); + dbSqlSessionFactory.setDatabaseTablePrefix(databaseTablePrefix); + dbSqlSessionFactory.setTablePrefixIsSchema(tablePrefixIsSchema); + dbSqlSessionFactory.setDatabaseCatalog(databaseCatalog); + dbSqlSessionFactory.setDatabaseSchema(databaseSchema); + dbSqlSessionFactory.setMaxNrOfStatementsInBulkInsert(maxNrOfStatementsInBulkInsert); + + initDbSqlSessionFactoryEntitySettings(); + + addSessionFactory(dbSqlSessionFactory); + } + + public DbSqlSessionFactory createDbSqlSessionFactory() { + return new DbSqlSessionFactory(usePrefixId); + } + + protected abstract void initDbSqlSessionFactoryEntitySettings(); + + protected void defaultInitDbSqlSessionFactoryEntitySettings(List> insertOrder, List> deleteOrder) { + if (insertOrder != null) { + for (Class clazz : insertOrder) { + dbSqlSessionFactory.getInsertionOrder().add(clazz); + + if (isBulkInsertEnabled) { + dbSqlSessionFactory.getBulkInserteableEntityClasses().add(clazz); + } + } + } + + if (deleteOrder != null) { + for (Class clazz : deleteOrder) { + dbSqlSessionFactory.getDeletionOrder().add(clazz); + } + } + } + + public void initTransactionFactory() { + if (transactionFactory == null) { + if (transactionsExternallyManaged) { + transactionFactory = new ManagedTransactionFactory(); + Properties properties = new Properties(); + properties.put("closeConnection", "false"); + this.transactionFactory.setProperties(properties); + } else { + transactionFactory = new JdbcTransactionFactory(); + } + } + } + + public void initSqlSessionFactory() { + if (sqlSessionFactory == null) { + InputStream inputStream = null; + try { + inputStream = getMyBatisXmlConfigurationStream(); + + Environment environment = new Environment("default", transactionFactory, dataSource); + Reader reader = new InputStreamReader(inputStream); + Properties properties = new Properties(); + properties.put("prefix", databaseTablePrefix); + + String wildcardEscapeClause = ""; + if ((databaseWildcardEscapeCharacter != null) && (databaseWildcardEscapeCharacter.length() != 0)) { + wildcardEscapeClause = " escape '" + databaseWildcardEscapeCharacter + "'"; + } + properties.put("wildcardEscapeClause", wildcardEscapeClause); + + // set default properties + properties.put("limitBefore", ""); + properties.put("limitAfter", ""); + properties.put("limitBetween", ""); + properties.put("limitBeforeNativeQuery", ""); + properties.put("limitAfterNativeQuery", ""); + properties.put("blobType", "BLOB"); + properties.put("boolValue", "TRUE"); + + if (databaseType != null) { + properties.load(getResourceAsStream(pathToEngineDbProperties())); + } + + Configuration configuration = initMybatisConfiguration(environment, reader, properties); + sqlSessionFactory = new DefaultSqlSessionFactory(configuration); + + } catch (Exception e) { + throw new FlowableException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e); + } finally { + IoUtil.closeSilently(inputStream); + } + } else { + // This is needed when the SQL Session Factory is created by another engine. + // When custom XML Mappers are registered with this engine they need to be loaded in the configuration as well + applyCustomMybatisCustomizations(sqlSessionFactory.getConfiguration()); + } + } + + public String pathToEngineDbProperties() { + return "org/flowable/common/db/properties/" + databaseType + ".properties"; + } + + public Configuration initMybatisConfiguration(Environment environment, Reader reader, Properties properties) { + XMLConfigBuilder parser = new XMLConfigBuilder(reader, "", properties); + Configuration configuration = parser.getConfiguration(); + + if (databaseType != null) { + configuration.setDatabaseId(databaseType); + } + + configuration.setEnvironment(environment); + + initMybatisTypeHandlers(configuration); + initCustomMybatisInterceptors(configuration); + if (isEnableLogSqlExecutionTime()) { + initMyBatisLogSqlExecutionTimePlugin(configuration); + } + + configuration = parseMybatisConfiguration(parser); + return configuration; + } + + public void initCustomMybatisMappers(Configuration configuration) { + if (getCustomMybatisMappers() != null) { + for (Class clazz : getCustomMybatisMappers()) { + if (!configuration.hasMapper(clazz)) { + configuration.addMapper(clazz); + } + } + } + } + + public void initMybatisTypeHandlers(Configuration configuration) { + // When mapping into Map there is currently a problem with MyBatis. + // It will return objects which are driver specific. + // Therefore we are registering the mappings between Object.class and the specific jdbc type here. + // see https://github.com/mybatis/mybatis-3/issues/2216 for more info + TypeHandlerRegistry handlerRegistry = configuration.getTypeHandlerRegistry(); + + handlerRegistry.register(Object.class, JdbcType.BOOLEAN, new BooleanTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.BIT, new BooleanTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.TINYINT, new ByteTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.SMALLINT, new ShortTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.INTEGER, new IntegerTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.FLOAT, new FloatTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.DOUBLE, new DoubleTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.CHAR, new StringTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.CLOB, new ClobTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.VARCHAR, new StringTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.LONGVARCHAR, new StringTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.NVARCHAR, new NStringTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.NCHAR, new NStringTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.NCLOB, new NClobTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.BIGINT, new LongTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.REAL, new BigDecimalTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.DECIMAL, new BigDecimalTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.NUMERIC, new BigDecimalTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.BLOB, new BlobInputStreamTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.LONGVARBINARY, new BlobTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.DATE, new DateOnlyTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.TIME, new TimeOnlyTypeHandler()); + handlerRegistry.register(Object.class, JdbcType.TIMESTAMP, new DateTypeHandler()); + + handlerRegistry.register(Object.class, JdbcType.SQLXML, new SqlxmlTypeHandler()); + } + + public void initCustomMybatisInterceptors(Configuration configuration) { + if (customMybatisInterceptors!=null){ + for (Interceptor interceptor :customMybatisInterceptors){ + configuration.addInterceptor(interceptor); + } + } + } + + public void initMyBatisLogSqlExecutionTimePlugin(Configuration configuration) { + configuration.addInterceptor(new LogSqlExecutionTimePlugin()); + } + + public Configuration parseMybatisConfiguration(XMLConfigBuilder parser) { + Configuration configuration = parser.parse(); + + applyCustomMybatisCustomizations(configuration); + return configuration; + } + + protected void applyCustomMybatisCustomizations(Configuration configuration) { + initCustomMybatisMappers(configuration); + + if (dependentEngineMybatisTypeAliasConfigs != null) { + for (MybatisTypeAliasConfigurator typeAliasConfig : dependentEngineMybatisTypeAliasConfigs) { + typeAliasConfig.configure(configuration.getTypeAliasRegistry()); + } + } + if (dependentEngineMybatisTypeHandlerConfigs != null) { + for (MybatisTypeHandlerConfigurator typeHandlerConfig : dependentEngineMybatisTypeHandlerConfigs) { + typeHandlerConfig.configure(configuration.getTypeHandlerRegistry()); + } + } + + parseDependentEngineMybatisXMLMappers(configuration); + parseCustomMybatisXMLMappers(configuration); + } + + public void parseCustomMybatisXMLMappers(Configuration configuration) { + if (getCustomMybatisXMLMappers() != null) { + for (String resource : getCustomMybatisXMLMappers()) { + parseMybatisXmlMapping(configuration, resource); + } + } + } + + public void parseDependentEngineMybatisXMLMappers(Configuration configuration) { + if (getDependentEngineMyBatisXmlMappers() != null) { + for (String resource : getDependentEngineMyBatisXmlMappers()) { + parseMybatisXmlMapping(configuration, resource); + } + } + } + + protected void parseMybatisXmlMapping(Configuration configuration, String resource) { + // see XMLConfigBuilder.mapperElement() + XMLMapperBuilder mapperParser = new XMLMapperBuilder(getResourceAsStream(resource), configuration, resource, configuration.getSqlFragments()); + mapperParser.parse(); + } + + protected InputStream getResourceAsStream(String resource) { + ClassLoader classLoader = getClassLoader(); + if (classLoader != null) { + return getClassLoader().getResourceAsStream(resource); + } else { + return this.getClass().getClassLoader().getResourceAsStream(resource); + } + } + + public void setMybatisMappingFile(String file) { + this.mybatisMappingFile = file; + } + + public String getMybatisMappingFile() { + return mybatisMappingFile; + } + + public abstract InputStream getMyBatisXmlConfigurationStream(); + + public void initConfigurators() { + + allConfigurators = new ArrayList<>(); + allConfigurators.addAll(getEngineSpecificEngineConfigurators()); + + // Configurators that are explicitly added to the config + if (configurators != null) { + allConfigurators.addAll(configurators); + } + + // Auto discovery through ServiceLoader + if (enableConfiguratorServiceLoader) { + ClassLoader classLoader = getClassLoader(); + if (classLoader == null) { + classLoader = ReflectUtil.getClassLoader(); + } + + ServiceLoader configuratorServiceLoader = ServiceLoader.load(EngineConfigurator.class, classLoader); + int nrOfServiceLoadedConfigurators = 0; + for (EngineConfigurator configurator : configuratorServiceLoader) { + allConfigurators.add(configurator); + nrOfServiceLoadedConfigurators++; + } + + if (nrOfServiceLoadedConfigurators > 0) { + logger.info("Found {} auto-discoverable Process Engine Configurator{}", nrOfServiceLoadedConfigurators, nrOfServiceLoadedConfigurators > 1 ? "s" : ""); + } + + if (!allConfigurators.isEmpty()) { + + // Order them according to the priorities (useful for dependent + // configurator) + allConfigurators.sort(new Comparator() { + + @Override + public int compare(EngineConfigurator configurator1, EngineConfigurator configurator2) { + int priority1 = configurator1.getPriority(); + int priority2 = configurator2.getPriority(); + + if (priority1 < priority2) { + return -1; + } else if (priority1 > priority2) { + return 1; + } + return 0; + } + }); + + // Execute the configurators + logger.info("Found {} Engine Configurators in total:", allConfigurators.size()); + for (EngineConfigurator configurator : allConfigurators) { + logger.info("{} (priority:{})", configurator.getClass(), configurator.getPriority()); + } + + } + + } + } + + public void close() { + if (forceCloseMybatisConnectionPool && dataSource instanceof PooledDataSource) { + /* + * When the datasource is created by a Flowable engine (i.e. it's an instance of PooledDataSource), + * the connection pool needs to be closed when closing the engine. + * Note that calling forceCloseAll() multiple times (as is the case when running with multiple engine) is ok. + */ + ((PooledDataSource) dataSource).forceCloseAll(); + } + } + + protected List getEngineSpecificEngineConfigurators() { + // meant to be overridden if needed + return Collections.emptyList(); + } + + public void configuratorsBeforeInit() { + for (EngineConfigurator configurator : allConfigurators) { + logger.info("Executing beforeInit() of {} (priority:{})", configurator.getClass(), configurator.getPriority()); + configurator.beforeInit(this); + } + } + + public void configuratorsAfterInit() { + for (EngineConfigurator configurator : allConfigurators) { + logger.info("Executing configure() of {} (priority:{})", configurator.getClass(), configurator.getPriority()); + configurator.configure(this); + } + } + + public LockManager getLockManager(String lockName) { + return new LockManagerImpl(commandExecutor, lockName, getLockPollRate(), getEngineCfgKey()); + } + + // getters and setters + // ////////////////////////////////////////////////////// + + public abstract String getEngineName(); + + public ClassLoader getClassLoader() { + return classLoader; + } + + public AbstractEngineConfiguration setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + return this; + } + + public boolean isUseClassForNameClassLoading() { + return useClassForNameClassLoading; + } + + public AbstractEngineConfiguration setUseClassForNameClassLoading(boolean useClassForNameClassLoading) { + this.useClassForNameClassLoading = useClassForNameClassLoading; + return this; + } + + public void addEngineLifecycleListener(EngineLifecycleListener engineLifecycleListener) { + if (this.engineLifecycleListeners == null) { + this.engineLifecycleListeners = new ArrayList<>(); + } + this.engineLifecycleListeners.add(engineLifecycleListener); + } + + public List getEngineLifecycleListeners() { + return engineLifecycleListeners; + } + + public AbstractEngineConfiguration setEngineLifecycleListeners(List engineLifecycleListeners) { + this.engineLifecycleListeners = engineLifecycleListeners; + return this; + } + + public String getDatabaseType() { + return databaseType; + } + + public AbstractEngineConfiguration setDatabaseType(String databaseType) { + this.databaseType = databaseType; + return this; + } + + public DataSource getDataSource() { + return dataSource; + } + + public AbstractEngineConfiguration setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + return this; + } + + public SchemaManager getSchemaManager() { + return schemaManager; + } + + public AbstractEngineConfiguration setSchemaManager(SchemaManager schemaManager) { + this.schemaManager = schemaManager; + return this; + } + + public SchemaManager getCommonSchemaManager() { + return commonSchemaManager; + } + + public AbstractEngineConfiguration setCommonSchemaManager(SchemaManager commonSchemaManager) { + this.commonSchemaManager = commonSchemaManager; + return this; + } + + public Command getSchemaManagementCmd() { + return schemaManagementCmd; + } + + public AbstractEngineConfiguration setSchemaManagementCmd(Command schemaManagementCmd) { + this.schemaManagementCmd = schemaManagementCmd; + return this; + } + + public String getJdbcDriver() { + return jdbcDriver; + } + + public AbstractEngineConfiguration setJdbcDriver(String jdbcDriver) { + this.jdbcDriver = jdbcDriver; + return this; + } + + public String getJdbcUrl() { + return jdbcUrl; + } + + public AbstractEngineConfiguration setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + return this; + } + + public String getJdbcUsername() { + return jdbcUsername; + } + + public AbstractEngineConfiguration setJdbcUsername(String jdbcUsername) { + this.jdbcUsername = jdbcUsername; + return this; + } + + public String getJdbcPassword() { + return jdbcPassword; + } + + public AbstractEngineConfiguration setJdbcPassword(String jdbcPassword) { + this.jdbcPassword = jdbcPassword; + return this; + } + + public int getJdbcMaxActiveConnections() { + return jdbcMaxActiveConnections; + } + + public AbstractEngineConfiguration setJdbcMaxActiveConnections(int jdbcMaxActiveConnections) { + this.jdbcMaxActiveConnections = jdbcMaxActiveConnections; + return this; + } + + public int getJdbcMaxIdleConnections() { + return jdbcMaxIdleConnections; + } + + public AbstractEngineConfiguration setJdbcMaxIdleConnections(int jdbcMaxIdleConnections) { + this.jdbcMaxIdleConnections = jdbcMaxIdleConnections; + return this; + } + + public int getJdbcMaxCheckoutTime() { + return jdbcMaxCheckoutTime; + } + + public AbstractEngineConfiguration setJdbcMaxCheckoutTime(int jdbcMaxCheckoutTime) { + this.jdbcMaxCheckoutTime = jdbcMaxCheckoutTime; + return this; + } + + public int getJdbcMaxWaitTime() { + return jdbcMaxWaitTime; + } + + public AbstractEngineConfiguration setJdbcMaxWaitTime(int jdbcMaxWaitTime) { + this.jdbcMaxWaitTime = jdbcMaxWaitTime; + return this; + } + + public boolean isJdbcPingEnabled() { + return jdbcPingEnabled; + } + + public AbstractEngineConfiguration setJdbcPingEnabled(boolean jdbcPingEnabled) { + this.jdbcPingEnabled = jdbcPingEnabled; + return this; + } + + public int getJdbcPingConnectionNotUsedFor() { + return jdbcPingConnectionNotUsedFor; + } + + public AbstractEngineConfiguration setJdbcPingConnectionNotUsedFor(int jdbcPingConnectionNotUsedFor) { + this.jdbcPingConnectionNotUsedFor = jdbcPingConnectionNotUsedFor; + return this; + } + + public int getJdbcDefaultTransactionIsolationLevel() { + return jdbcDefaultTransactionIsolationLevel; + } + + public AbstractEngineConfiguration setJdbcDefaultTransactionIsolationLevel(int jdbcDefaultTransactionIsolationLevel) { + this.jdbcDefaultTransactionIsolationLevel = jdbcDefaultTransactionIsolationLevel; + return this; + } + + public String getJdbcPingQuery() { + return jdbcPingQuery; + } + + public AbstractEngineConfiguration setJdbcPingQuery(String jdbcPingQuery) { + this.jdbcPingQuery = jdbcPingQuery; + return this; + } + + public String getDataSourceJndiName() { + return dataSourceJndiName; + } + + public AbstractEngineConfiguration setDataSourceJndiName(String dataSourceJndiName) { + this.dataSourceJndiName = dataSourceJndiName; + return this; + } + + public CommandConfig getSchemaCommandConfig() { + return schemaCommandConfig; + } + + public AbstractEngineConfiguration setSchemaCommandConfig(CommandConfig schemaCommandConfig) { + this.schemaCommandConfig = schemaCommandConfig; + return this; + } + + public boolean isTransactionsExternallyManaged() { + return transactionsExternallyManaged; + } + + public AbstractEngineConfiguration setTransactionsExternallyManaged(boolean transactionsExternallyManaged) { + this.transactionsExternallyManaged = transactionsExternallyManaged; + return this; + } + + public Map getBeans() { + return beans; + } + + public AbstractEngineConfiguration setBeans(Map beans) { + this.beans = beans; + return this; + } + + public IdGenerator getIdGenerator() { + return idGenerator; + } + + public AbstractEngineConfiguration setIdGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + return this; + } + + public boolean isUsePrefixId() { + return usePrefixId; + } + + public AbstractEngineConfiguration setUsePrefixId(boolean usePrefixId) { + this.usePrefixId = usePrefixId; + return this; + } + + public String getXmlEncoding() { + return xmlEncoding; + } + + public AbstractEngineConfiguration setXmlEncoding(String xmlEncoding) { + this.xmlEncoding = xmlEncoding; + return this; + } + + public CommandConfig getDefaultCommandConfig() { + return defaultCommandConfig; + } + + public AbstractEngineConfiguration setDefaultCommandConfig(CommandConfig defaultCommandConfig) { + this.defaultCommandConfig = defaultCommandConfig; + return this; + } + + public CommandExecutor getCommandExecutor() { + return commandExecutor; + } + + public AbstractEngineConfiguration setCommandExecutor(CommandExecutor commandExecutor) { + this.commandExecutor = commandExecutor; + return this; + } + + public CommandContextFactory getCommandContextFactory() { + return commandContextFactory; + } + + public AbstractEngineConfiguration setCommandContextFactory(CommandContextFactory commandContextFactory) { + this.commandContextFactory = commandContextFactory; + return this; + } + + public CommandInterceptor getCommandInvoker() { + return commandInvoker; + } + + public AbstractEngineConfiguration setCommandInvoker(CommandInterceptor commandInvoker) { + this.commandInvoker = commandInvoker; + return this; + } + + public AgendaOperationRunner getAgendaOperationRunner() { + return agendaOperationRunner; + } + + public AbstractEngineConfiguration setAgendaOperationRunner(AgendaOperationRunner agendaOperationRunner) { + this.agendaOperationRunner = agendaOperationRunner; + return this; + } + + public List getCustomPreCommandInterceptors() { + return customPreCommandInterceptors; + } + + public AbstractEngineConfiguration setCustomPreCommandInterceptors(List customPreCommandInterceptors) { + this.customPreCommandInterceptors = customPreCommandInterceptors; + return this; + } + + public List getCustomPostCommandInterceptors() { + return customPostCommandInterceptors; + } + + public AbstractEngineConfiguration setCustomPostCommandInterceptors(List customPostCommandInterceptors) { + this.customPostCommandInterceptors = customPostCommandInterceptors; + return this; + } + + public List getCommandInterceptors() { + return commandInterceptors; + } + + public AbstractEngineConfiguration setCommandInterceptors(List commandInterceptors) { + this.commandInterceptors = commandInterceptors; + return this; + } + + public Map getEngineConfigurations() { + return engineConfigurations; + } + + public AbstractEngineConfiguration setEngineConfigurations(Map engineConfigurations) { + this.engineConfigurations = engineConfigurations; + return this; + } + + public void addEngineConfiguration(String key, String scopeType, AbstractEngineConfiguration engineConfiguration) { + if (engineConfigurations == null) { + engineConfigurations = new HashMap<>(); + } + engineConfigurations.put(key, engineConfiguration); + engineConfigurations.put(scopeType, engineConfiguration); + } + + public Map getServiceConfigurations() { + return serviceConfigurations; + } + + public AbstractEngineConfiguration setServiceConfigurations(Map serviceConfigurations) { + this.serviceConfigurations = serviceConfigurations; + return this; + } + + public void addServiceConfiguration(String key, AbstractServiceConfiguration serviceConfiguration) { + if (serviceConfigurations == null) { + serviceConfigurations = new HashMap<>(); + } + serviceConfigurations.put(key, serviceConfiguration); + } + + public Map getEventRegistryEventConsumers() { + return eventRegistryEventConsumers; + } + + public AbstractEngineConfiguration setEventRegistryEventConsumers(Map eventRegistryEventConsumers) { + this.eventRegistryEventConsumers = eventRegistryEventConsumers; + return this; + } + + public void addEventRegistryEventConsumer(String key, EventRegistryEventConsumer eventRegistryEventConsumer) { + if (eventRegistryEventConsumers == null) { + eventRegistryEventConsumers = new HashMap<>(); + } + eventRegistryEventConsumers.put(key, eventRegistryEventConsumer); + } + + public AbstractEngineConfiguration setDefaultCommandInterceptors(Collection defaultCommandInterceptors) { + this.defaultCommandInterceptors = defaultCommandInterceptors; + return this; + } + + public SqlSessionFactory getSqlSessionFactory() { + return sqlSessionFactory; + } + + public AbstractEngineConfiguration setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { + this.sqlSessionFactory = sqlSessionFactory; + return this; + } + + public boolean isDbHistoryUsed() { + return isDbHistoryUsed; + } + + public AbstractEngineConfiguration setDbHistoryUsed(boolean isDbHistoryUsed) { + this.isDbHistoryUsed = isDbHistoryUsed; + return this; + } + + public DbSqlSessionFactory getDbSqlSessionFactory() { + return dbSqlSessionFactory; + } + + public AbstractEngineConfiguration setDbSqlSessionFactory(DbSqlSessionFactory dbSqlSessionFactory) { + this.dbSqlSessionFactory = dbSqlSessionFactory; + return this; + } + + public TransactionFactory getTransactionFactory() { + return transactionFactory; + } + + public AbstractEngineConfiguration setTransactionFactory(TransactionFactory transactionFactory) { + this.transactionFactory = transactionFactory; + return this; + } + + public TransactionContextFactory getTransactionContextFactory() { + return transactionContextFactory; + } + + public AbstractEngineConfiguration setTransactionContextFactory(TransactionContextFactory transactionContextFactory) { + this.transactionContextFactory = transactionContextFactory; + return this; + } + + public int getMaxNrOfStatementsInBulkInsert() { + return maxNrOfStatementsInBulkInsert; + } + + public AbstractEngineConfiguration setMaxNrOfStatementsInBulkInsert(int maxNrOfStatementsInBulkInsert) { + this.maxNrOfStatementsInBulkInsert = maxNrOfStatementsInBulkInsert; + return this; + } + + public boolean isBulkInsertEnabled() { + return isBulkInsertEnabled; + } + + public AbstractEngineConfiguration setBulkInsertEnabled(boolean isBulkInsertEnabled) { + this.isBulkInsertEnabled = isBulkInsertEnabled; + return this; + } + + public Set> getCustomMybatisMappers() { + return customMybatisMappers; + } + + public AbstractEngineConfiguration setCustomMybatisMappers(Set> customMybatisMappers) { + this.customMybatisMappers = customMybatisMappers; + return this; + } + + public Set getCustomMybatisXMLMappers() { + return customMybatisXMLMappers; + } + + public AbstractEngineConfiguration setCustomMybatisXMLMappers(Set customMybatisXMLMappers) { + this.customMybatisXMLMappers = customMybatisXMLMappers; + return this; + } + + public Set getDependentEngineMyBatisXmlMappers() { + return dependentEngineMyBatisXmlMappers; + } + + public AbstractEngineConfiguration setCustomMybatisInterceptors(List customMybatisInterceptors) { + this.customMybatisInterceptors = customMybatisInterceptors; + return this; + } + + public List getCustomMybatisInterceptors() { + return customMybatisInterceptors; + } + + public AbstractEngineConfiguration setDependentEngineMyBatisXmlMappers(Set dependentEngineMyBatisXmlMappers) { + this.dependentEngineMyBatisXmlMappers = dependentEngineMyBatisXmlMappers; + return this; + } + + public List getDependentEngineMybatisTypeAliasConfigs() { + return dependentEngineMybatisTypeAliasConfigs; + } + + public AbstractEngineConfiguration setDependentEngineMybatisTypeAliasConfigs(List dependentEngineMybatisTypeAliasConfigs) { + this.dependentEngineMybatisTypeAliasConfigs = dependentEngineMybatisTypeAliasConfigs; + return this; + } + + public List getDependentEngineMybatisTypeHandlerConfigs() { + return dependentEngineMybatisTypeHandlerConfigs; + } + + public AbstractEngineConfiguration setDependentEngineMybatisTypeHandlerConfigs(List dependentEngineMybatisTypeHandlerConfigs) { + this.dependentEngineMybatisTypeHandlerConfigs = dependentEngineMybatisTypeHandlerConfigs; + return this; + } + + public List getCustomSessionFactories() { + return customSessionFactories; + } + + public AbstractEngineConfiguration addCustomSessionFactory(SessionFactory sessionFactory) { + if (customSessionFactories == null) { + customSessionFactories = new ArrayList<>(); + } + customSessionFactories.add(sessionFactory); + return this; + } + + public AbstractEngineConfiguration setCustomSessionFactories(List customSessionFactories) { + this.customSessionFactories = customSessionFactories; + return this; + } + + public boolean isUsingRelationalDatabase() { + return usingRelationalDatabase; + } + + public AbstractEngineConfiguration setUsingRelationalDatabase(boolean usingRelationalDatabase) { + this.usingRelationalDatabase = usingRelationalDatabase; + return this; + } + + public boolean isUsingSchemaMgmt() { + return usingSchemaMgmt; + } + + public AbstractEngineConfiguration setUsingSchemaMgmt(boolean usingSchema) { + this.usingSchemaMgmt = usingSchema; + return this; + } + + public String getDatabaseTablePrefix() { + return databaseTablePrefix; + } + + public AbstractEngineConfiguration setDatabaseTablePrefix(String databaseTablePrefix) { + this.databaseTablePrefix = databaseTablePrefix; + return this; + } + + public String getDatabaseWildcardEscapeCharacter() { + return databaseWildcardEscapeCharacter; + } + + public AbstractEngineConfiguration setDatabaseWildcardEscapeCharacter(String databaseWildcardEscapeCharacter) { + this.databaseWildcardEscapeCharacter = databaseWildcardEscapeCharacter; + return this; + } + + public String getDatabaseCatalog() { + return databaseCatalog; + } + + public AbstractEngineConfiguration setDatabaseCatalog(String databaseCatalog) { + this.databaseCatalog = databaseCatalog; + return this; + } + + public String getDatabaseSchema() { + return databaseSchema; + } + + public AbstractEngineConfiguration setDatabaseSchema(String databaseSchema) { + this.databaseSchema = databaseSchema; + return this; + } + + public boolean isTablePrefixIsSchema() { + return tablePrefixIsSchema; + } + + public AbstractEngineConfiguration setTablePrefixIsSchema(boolean tablePrefixIsSchema) { + this.tablePrefixIsSchema = tablePrefixIsSchema; + return this; + } + + public boolean isAlwaysLookupLatestDefinitionVersion() { + return alwaysLookupLatestDefinitionVersion; + } + + public AbstractEngineConfiguration setAlwaysLookupLatestDefinitionVersion(boolean alwaysLookupLatestDefinitionVersion) { + this.alwaysLookupLatestDefinitionVersion = alwaysLookupLatestDefinitionVersion; + return this; + } + + public boolean isFallbackToDefaultTenant() { + return fallbackToDefaultTenant; + } + + public AbstractEngineConfiguration setFallbackToDefaultTenant(boolean fallbackToDefaultTenant) { + this.fallbackToDefaultTenant = fallbackToDefaultTenant; + return this; + } + + /** + * @return name of the default tenant + * @deprecated use {@link AbstractEngineConfiguration#getDefaultTenantProvider()} instead + */ + @Deprecated + public String getDefaultTenantValue() { + return getDefaultTenantProvider().getDefaultTenant(null, null, null); + } + + public AbstractEngineConfiguration setDefaultTenantValue(String defaultTenantValue) { + this.defaultTenantProvider = (tenantId, scope, scopeKey) -> defaultTenantValue; + return this; + } + + public DefaultTenantProvider getDefaultTenantProvider() { + return defaultTenantProvider; + } + + public AbstractEngineConfiguration setDefaultTenantProvider(DefaultTenantProvider defaultTenantProvider) { + this.defaultTenantProvider = defaultTenantProvider; + return this; + } + + public boolean isEnableLogSqlExecutionTime() { + return enableLogSqlExecutionTime; + } + + public void setEnableLogSqlExecutionTime(boolean enableLogSqlExecutionTime) { + this.enableLogSqlExecutionTime = enableLogSqlExecutionTime; + } + + public Map, SessionFactory> getSessionFactories() { + return sessionFactories; + } + + public AbstractEngineConfiguration setSessionFactories(Map, SessionFactory> sessionFactories) { + this.sessionFactories = sessionFactories; + return this; + } + + public String getDatabaseSchemaUpdate() { + return databaseSchemaUpdate; + } + + public AbstractEngineConfiguration setDatabaseSchemaUpdate(String databaseSchemaUpdate) { + this.databaseSchemaUpdate = databaseSchemaUpdate; + return this; + } + + public boolean isUseLockForDatabaseSchemaUpdate() { + return useLockForDatabaseSchemaUpdate; + } + + public AbstractEngineConfiguration setUseLockForDatabaseSchemaUpdate(boolean useLockForDatabaseSchemaUpdate) { + this.useLockForDatabaseSchemaUpdate = useLockForDatabaseSchemaUpdate; + return this; + } + + public boolean isEnableEventDispatcher() { + return enableEventDispatcher; + } + + public AbstractEngineConfiguration setEnableEventDispatcher(boolean enableEventDispatcher) { + this.enableEventDispatcher = enableEventDispatcher; + return this; + } + + public FlowableEventDispatcher getEventDispatcher() { + return eventDispatcher; + } + + public AbstractEngineConfiguration setEventDispatcher(FlowableEventDispatcher eventDispatcher) { + this.eventDispatcher = eventDispatcher; + return this; + } + + public List getEventListeners() { + return eventListeners; + } + + public AbstractEngineConfiguration setEventListeners(List eventListeners) { + this.eventListeners = eventListeners; + return this; + } + + public Map> getTypedEventListeners() { + return typedEventListeners; + } + + public AbstractEngineConfiguration setTypedEventListeners(Map> typedEventListeners) { + this.typedEventListeners = typedEventListeners; + return this; + } + + public List getAdditionalEventDispatchActions() { + return additionalEventDispatchActions; + } + + public AbstractEngineConfiguration setAdditionalEventDispatchActions(List additionalEventDispatchActions) { + this.additionalEventDispatchActions = additionalEventDispatchActions; + return this; + } + + public void initEventDispatcher() { + if (this.eventDispatcher == null) { + this.eventDispatcher = new FlowableEventDispatcherImpl(); + } + + initAdditionalEventDispatchActions(); + + this.eventDispatcher.setEnabled(enableEventDispatcher); + + initEventListeners(); + initTypedEventListeners(); + } + + protected void initEventListeners() { + if (eventListeners != null) { + for (FlowableEventListener listenerToAdd : eventListeners) { + this.eventDispatcher.addEventListener(listenerToAdd); + } + } + } + + protected void initAdditionalEventDispatchActions() { + if (this.additionalEventDispatchActions == null) { + this.additionalEventDispatchActions = new ArrayList<>(); + } + } + + protected void initTypedEventListeners() { + if (typedEventListeners != null) { + for (Map.Entry> listenersToAdd : typedEventListeners.entrySet()) { + // Extract types from the given string + FlowableEngineEventType[] types = FlowableEngineEventType.getTypesFromString(listenersToAdd.getKey()); + + for (FlowableEventListener listenerToAdd : listenersToAdd.getValue()) { + this.eventDispatcher.addEventListener(listenerToAdd, types); + } + } + } + } + + public boolean isLoggingSessionEnabled() { + return loggingListener != null; + } + + public LoggingListener getLoggingListener() { + return loggingListener; + } + + public void setLoggingListener(LoggingListener loggingListener) { + this.loggingListener = loggingListener; + } + + public Clock getClock() { + return clock; + } + + public AbstractEngineConfiguration setClock(Clock clock) { + this.clock = clock; + return this; + } + + public ObjectMapper getObjectMapper() { + return objectMapper; + } + + public AbstractEngineConfiguration setObjectMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + return this; + } + + public int getMaxLengthString() { + if (maxLengthStringVariableType == -1) { + if ("oracle".equalsIgnoreCase(databaseType)) { + return DEFAULT_ORACLE_MAX_LENGTH_STRING; + } else { + return DEFAULT_GENERIC_MAX_LENGTH_STRING; + } + } else { + return maxLengthStringVariableType; + } + } + + public int getMaxLengthStringVariableType() { + return maxLengthStringVariableType; + } + + public AbstractEngineConfiguration setMaxLengthStringVariableType(int maxLengthStringVariableType) { + this.maxLengthStringVariableType = maxLengthStringVariableType; + return this; + } + + public PropertyDataManager getPropertyDataManager() { + return propertyDataManager; + } + + public Duration getLockPollRate() { + return lockPollRate; + } + + public AbstractEngineConfiguration setLockPollRate(Duration lockPollRate) { + this.lockPollRate = lockPollRate; + return this; + } + + public Duration getSchemaLockWaitTime() { + return schemaLockWaitTime; + } + + public void setSchemaLockWaitTime(Duration schemaLockWaitTime) { + this.schemaLockWaitTime = schemaLockWaitTime; + } + + public AbstractEngineConfiguration setPropertyDataManager(PropertyDataManager propertyDataManager) { + this.propertyDataManager = propertyDataManager; + return this; + } + + public PropertyEntityManager getPropertyEntityManager() { + return propertyEntityManager; + } + + public AbstractEngineConfiguration setPropertyEntityManager(PropertyEntityManager propertyEntityManager) { + this.propertyEntityManager = propertyEntityManager; + return this; + } + + public ByteArrayDataManager getByteArrayDataManager() { + return byteArrayDataManager; + } + + public AbstractEngineConfiguration setByteArrayDataManager(ByteArrayDataManager byteArrayDataManager) { + this.byteArrayDataManager = byteArrayDataManager; + return this; + } + + public ByteArrayEntityManager getByteArrayEntityManager() { + return byteArrayEntityManager; + } + + public AbstractEngineConfiguration setByteArrayEntityManager(ByteArrayEntityManager byteArrayEntityManager) { + this.byteArrayEntityManager = byteArrayEntityManager; + return this; + } + + public TableDataManager getTableDataManager() { + return tableDataManager; + } + + public AbstractEngineConfiguration setTableDataManager(TableDataManager tableDataManager) { + this.tableDataManager = tableDataManager; + return this; + } + + public List getDeployers() { + return deployers; + } + + public AbstractEngineConfiguration setDeployers(List deployers) { + this.deployers = deployers; + return this; + } + + public List getCustomPreDeployers() { + return customPreDeployers; + } + + public AbstractEngineConfiguration setCustomPreDeployers(List customPreDeployers) { + this.customPreDeployers = customPreDeployers; + return this; + } + + public List getCustomPostDeployers() { + return customPostDeployers; + } + + public AbstractEngineConfiguration setCustomPostDeployers(List customPostDeployers) { + this.customPostDeployers = customPostDeployers; + return this; + } + + public boolean isEnableConfiguratorServiceLoader() { + return enableConfiguratorServiceLoader; + } + + public AbstractEngineConfiguration setEnableConfiguratorServiceLoader(boolean enableConfiguratorServiceLoader) { + this.enableConfiguratorServiceLoader = enableConfiguratorServiceLoader; + return this; + } + + public List getConfigurators() { + return configurators; + } + + public AbstractEngineConfiguration addConfigurator(EngineConfigurator configurator) { + if (configurators == null) { + configurators = new ArrayList<>(); + } + configurators.add(configurator); + return this; + } + + /** + * @return All {@link EngineConfigurator} instances. Will only contain values after init of the engine. + * Use the {@link #getConfigurators()} or {@link #addConfigurator(EngineConfigurator)} methods otherwise. + */ + public List getAllConfigurators() { + return allConfigurators; + } + + public AbstractEngineConfiguration setConfigurators(List configurators) { + this.configurators = configurators; + return this; + } + + public EngineConfigurator getIdmEngineConfigurator() { + return idmEngineConfigurator; + } + + public AbstractEngineConfiguration setIdmEngineConfigurator(EngineConfigurator idmEngineConfigurator) { + this.idmEngineConfigurator = idmEngineConfigurator; + return this; + } + + public EngineConfigurator getEventRegistryConfigurator() { + return eventRegistryConfigurator; + } + + public AbstractEngineConfiguration setEventRegistryConfigurator(EngineConfigurator eventRegistryConfigurator) { + this.eventRegistryConfigurator = eventRegistryConfigurator; + return this; + } + + public AbstractEngineConfiguration setForceCloseMybatisConnectionPool(boolean forceCloseMybatisConnectionPool) { + this.forceCloseMybatisConnectionPool = forceCloseMybatisConnectionPool; + return this; + } + + public boolean isForceCloseMybatisConnectionPool() { + return forceCloseMybatisConnectionPool; + } +} diff --git a/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/package-info.md b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/package-info.md new file mode 100644 index 0000000..1932c7a --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/package-info.md @@ -0,0 +1 @@ +防止IDEA将`.`和`/`混为一谈 \ No newline at end of file diff --git a/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/services/liquibase.database.Database b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/services/liquibase.database.Database new file mode 100644 index 0000000..efbcfcc --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/flowable-patch/src/main/resources/META-INF/services/liquibase.database.Database @@ -0,0 +1,21 @@ +liquibase.database.core.CockroachDatabase +liquibase.database.core.DB2Database +liquibase.database.core.Db2zDatabase +liquibase.database.core.DerbyDatabase +liquibase.database.core.Firebird3Database +liquibase.database.core.FirebirdDatabase +liquibase.database.core.H2Database +liquibase.database.core.HsqlDatabase +liquibase.database.core.InformixDatabase +liquibase.database.core.Ingres9Database +liquibase.database.core.MSSQLDatabase +liquibase.database.core.MariaDBDatabase +liquibase.database.core.MockDatabase +liquibase.database.core.MySQLDatabase +liquibase.database.core.OracleDatabase +liquibase.database.core.PostgresDatabase +liquibase.database.core.SQLiteDatabase +liquibase.database.core.SybaseASADatabase +liquibase.database.core.SybaseDatabase +liquibase.database.core.DmDatabase +liquibase.database.core.UnsupportedDatabase diff --git a/ruoyi-vue-pro-master/sql/dm/ruoyi-vue-pro-dm8.sql b/ruoyi-vue-pro-master/sql/dm/ruoyi-vue-pro-dm8.sql new file mode 100644 index 0000000..78ae24d --- /dev/null +++ b/ruoyi-vue-pro-master/sql/dm/ruoyi-vue-pro-dm8.sql @@ -0,0 +1,4349 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : DM8 + + Date: 2024-05-03 22:21:06 +*/ + + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +CREATE TABLE infra_api_access_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id varchar(64) DEFAULT '' NULL, + user_id bigint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + application_name varchar(50) NOT NULL, + request_method varchar(16) DEFAULT '' NULL, + request_url varchar(255) DEFAULT '' NULL, + request_params text NULL, + response_body text NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + operate_module varchar(50) DEFAULT NULL NULL, + operate_name varchar(50) DEFAULT NULL NULL, + operate_type smallint DEFAULT 0 NULL, + begin_time datetime NOT NULL, + end_time datetime NOT NULL, + duration int NOT NULL, + result_code int DEFAULT 0 NOT NULL, + result_msg varchar(512) DEFAULT '' NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time); + +COMMENT ON COLUMN infra_api_access_log.id IS '־'; +COMMENT ON COLUMN infra_api_access_log.trace_id IS '·׷ٱ'; +COMMENT ON COLUMN infra_api_access_log.user_id IS 'û'; +COMMENT ON COLUMN infra_api_access_log.user_type IS 'û'; +COMMENT ON COLUMN infra_api_access_log.application_name IS 'Ӧ'; +COMMENT ON COLUMN infra_api_access_log.request_method IS '󷽷'; +COMMENT ON COLUMN infra_api_access_log.request_url IS 'ַ'; +COMMENT ON COLUMN infra_api_access_log.request_params IS ''; +COMMENT ON COLUMN infra_api_access_log.response_body IS 'Ӧ'; +COMMENT ON COLUMN infra_api_access_log.user_ip IS 'û IP'; +COMMENT ON COLUMN infra_api_access_log.user_agent IS ' UA'; +COMMENT ON COLUMN infra_api_access_log.operate_module IS 'ģ'; +COMMENT ON COLUMN infra_api_access_log.operate_name IS ''; +COMMENT ON COLUMN infra_api_access_log.operate_type IS ''; +COMMENT ON COLUMN infra_api_access_log.begin_time IS 'ʼʱ'; +COMMENT ON COLUMN infra_api_access_log.end_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_access_log.duration IS 'ִʱ'; +COMMENT ON COLUMN infra_api_access_log.result_code IS ''; +COMMENT ON COLUMN infra_api_access_log.result_msg IS 'ʾ'; +COMMENT ON COLUMN infra_api_access_log.creator IS ''; +COMMENT ON COLUMN infra_api_access_log.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_access_log.updater IS ''; +COMMENT ON COLUMN infra_api_access_log.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_access_log.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN infra_api_access_log.tenant_id IS '⻧'; +COMMENT ON TABLE infra_api_access_log IS 'API ־'; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +CREATE TABLE infra_api_error_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id varchar(64) NOT NULL, + user_id int DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + application_name varchar(50) NOT NULL, + request_method varchar(16) NOT NULL, + request_url varchar(255) NOT NULL, + request_params varchar(8000) NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + exception_time datetime NOT NULL, + exception_name varchar(128) DEFAULT '' NULL, + exception_message text NOT NULL, + exception_root_cause_message text NOT NULL, + exception_stack_trace text NOT NULL, + exception_class_name varchar(512) NOT NULL, + exception_file_name varchar(512) NOT NULL, + exception_method_name varchar(512) NOT NULL, + exception_line_number int NOT NULL, + process_status smallint NOT NULL, + process_time datetime DEFAULT NULL NULL, + process_user_id int DEFAULT 0 NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN infra_api_error_log.id IS ''; +COMMENT ON COLUMN infra_api_error_log.trace_id IS '·׷ٱ + * + * һ˵ͨ·׷ٱţԽ־־·׷־logger ӡ־ȣһ𣬴ӶŴ'; +COMMENT ON COLUMN infra_api_error_log.user_id IS 'û'; +COMMENT ON COLUMN infra_api_error_log.user_type IS 'û'; +COMMENT ON COLUMN infra_api_error_log.application_name IS 'Ӧ + * + * Ŀǰȡ spring.application.name'; +COMMENT ON COLUMN infra_api_error_log.request_method IS '󷽷'; +COMMENT ON COLUMN infra_api_error_log.request_url IS 'ַ'; +COMMENT ON COLUMN infra_api_error_log.request_params IS ''; +COMMENT ON COLUMN infra_api_error_log.user_ip IS 'û IP'; +COMMENT ON COLUMN infra_api_error_log.user_agent IS ' UA'; +COMMENT ON COLUMN infra_api_error_log.exception_time IS '쳣ʱ'; +COMMENT ON COLUMN infra_api_error_log.exception_name IS '쳣 + * + * {@link Throwable#getClass()} ȫ'; +COMMENT ON COLUMN infra_api_error_log.exception_message IS '쳣µϢ + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '쳣µĸϢ + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '쳣ջ켣 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}'; +COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '쳣ȫ + * + * {@link StackTraceElement#getClassName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '쳣ļ + * + * {@link StackTraceElement#getFileName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '쳣ķ + * + * {@link StackTraceElement#getMethodName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '쳣ķ + * + * {@link StackTraceElement#getLineNumber()}'; +COMMENT ON COLUMN infra_api_error_log.process_status IS '״̬'; +COMMENT ON COLUMN infra_api_error_log.process_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_error_log.process_user_id IS 'û'; +COMMENT ON COLUMN infra_api_error_log.creator IS ''; +COMMENT ON COLUMN infra_api_error_log.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_error_log.updater IS ''; +COMMENT ON COLUMN infra_api_error_log.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_api_error_log.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN infra_api_error_log.tenant_id IS '⻧'; +COMMENT ON TABLE infra_api_error_log IS 'ϵͳ쳣־'; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +CREATE TABLE infra_codegen_column +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + table_id bigint NOT NULL, + column_name varchar(200) NOT NULL, + data_type varchar(100) NOT NULL, + column_comment varchar(500) NOT NULL, + nullable bit NOT NULL, + primary_key bit NOT NULL, + ordinal_position int NOT NULL, + java_type varchar(32) NOT NULL, + java_field varchar(64) NOT NULL, + dict_type varchar(200) DEFAULT '' NULL, + example varchar(64) DEFAULT NULL NULL, + create_operation bit NOT NULL, + update_operation bit NOT NULL, + list_operation bit NOT NULL, + list_operation_condition varchar(32) DEFAULT '=' NOT NULL, + list_operation_result bit NOT NULL, + html_type varchar(32) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_codegen_column.id IS ''; +COMMENT ON COLUMN infra_codegen_column.table_id IS ''; +COMMENT ON COLUMN infra_codegen_column.column_name IS 'ֶ'; +COMMENT ON COLUMN infra_codegen_column.data_type IS 'ֶ'; +COMMENT ON COLUMN infra_codegen_column.column_comment IS 'ֶ'; +COMMENT ON COLUMN infra_codegen_column.nullable IS 'ǷΪ'; +COMMENT ON COLUMN infra_codegen_column.primary_key IS 'Ƿ'; +COMMENT ON COLUMN infra_codegen_column.ordinal_position IS ''; +COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java '; +COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java '; +COMMENT ON COLUMN infra_codegen_column.dict_type IS 'ֵ'; +COMMENT ON COLUMN infra_codegen_column.example IS 'ʾ'; +COMMENT ON COLUMN infra_codegen_column.create_operation IS 'ǷΪ Create ֶ'; +COMMENT ON COLUMN infra_codegen_column.update_operation IS 'ǷΪ Update ²ֶ'; +COMMENT ON COLUMN infra_codegen_column.list_operation IS 'ǷΪ List ѯֶ'; +COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List ѯ'; +COMMENT ON COLUMN infra_codegen_column.list_operation_result IS 'ǷΪ List ѯķֶ'; +COMMENT ON COLUMN infra_codegen_column.html_type IS 'ʾ'; +COMMENT ON COLUMN infra_codegen_column.creator IS ''; +COMMENT ON COLUMN infra_codegen_column.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_codegen_column.updater IS ''; +COMMENT ON COLUMN infra_codegen_column.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_codegen_column.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_codegen_column IS 'ɱֶζ'; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +CREATE TABLE infra_codegen_table +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + data_source_config_id bigint NOT NULL, + scene smallint DEFAULT 1 NOT NULL, + table_name varchar(200) DEFAULT '' NULL, + table_comment varchar(500) DEFAULT '' NULL, + remark varchar(500) DEFAULT NULL NULL, + module_name varchar(30) NOT NULL, + business_name varchar(30) NOT NULL, + class_name varchar(100) DEFAULT '' NULL, + class_comment varchar(50) NOT NULL, + author varchar(50) NOT NULL, + template_type smallint DEFAULT 1 NOT NULL, + front_type smallint NOT NULL, + parent_menu_id bigint DEFAULT NULL NULL, + master_table_id bigint DEFAULT NULL NULL, + sub_join_column_id bigint DEFAULT NULL NULL, + sub_join_many bit DEFAULT NULL NULL, + tree_parent_column_id bigint DEFAULT NULL NULL, + tree_name_column_id bigint DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_codegen_table.id IS ''; +COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS 'Դõı'; +COMMENT ON COLUMN infra_codegen_table.scene IS 'ɳ'; +COMMENT ON COLUMN infra_codegen_table.table_name IS ''; +COMMENT ON COLUMN infra_codegen_table.table_comment IS ''; +COMMENT ON COLUMN infra_codegen_table.remark IS 'ע'; +COMMENT ON COLUMN infra_codegen_table.module_name IS 'ģ'; +COMMENT ON COLUMN infra_codegen_table.business_name IS 'ҵ'; +COMMENT ON COLUMN infra_codegen_table.class_name IS ''; +COMMENT ON COLUMN infra_codegen_table.class_comment IS ''; +COMMENT ON COLUMN infra_codegen_table.author IS ''; +COMMENT ON COLUMN infra_codegen_table.template_type IS 'ģ'; +COMMENT ON COLUMN infra_codegen_table.front_type IS 'ǰ'; +COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '˵'; +COMMENT ON COLUMN infra_codegen_table.master_table_id IS 'ı'; +COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS 'ӱֶα'; +COMMENT ON COLUMN infra_codegen_table.sub_join_many IS 'ӱǷһԶ'; +COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS 'ĸֶα'; +COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS 'ֶα'; +COMMENT ON COLUMN infra_codegen_table.creator IS ''; +COMMENT ON COLUMN infra_codegen_table.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_codegen_table.updater IS ''; +COMMENT ON COLUMN infra_codegen_table.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_codegen_table.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_codegen_table IS 'ɱ'; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +CREATE TABLE infra_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + category varchar(50) NOT NULL, + type smallint NOT NULL, + name varchar(100) DEFAULT '' NULL, + config_key varchar(100) DEFAULT '' NULL, + value varchar(500) DEFAULT '' NULL, + visible bit NOT NULL, + remark varchar(500) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_config.id IS ''; +COMMENT ON COLUMN infra_config.category IS ''; +COMMENT ON COLUMN infra_config.type IS ''; +COMMENT ON COLUMN infra_config.name IS ''; +COMMENT ON COLUMN infra_config.config_key IS ''; +COMMENT ON COLUMN infra_config.value IS 'ֵ'; +COMMENT ON COLUMN infra_config.visible IS 'Ƿɼ'; +COMMENT ON COLUMN infra_config.remark IS 'ע'; +COMMENT ON COLUMN infra_config.creator IS ''; +COMMENT ON COLUMN infra_config.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_config.updater IS ''; +COMMENT ON COLUMN infra_config.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_config.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_config IS 'ñ'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT infra_config ON; +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, 'û-˺ųʼ', 'sys.user.init-password', '123456', '0', 'ʼ 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-04-03 17:22:28', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL صĵַ', 'url.druid', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking صĵַ', 'url.skywalking', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin صĵַ', 'url.spring-boot-admin', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger ӿĵĵַ', 'url.swagger', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, 'ui', 2, 'Ѷͼ key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', '1', 'Ѷͼ key', '1', '2023-06-03 19:16:27', '1', '2023-06-03 19:16:27', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', '2023-12-03 09:55:16', '1', '2023-12-03 09:55:27', '0'); +COMMIT; +SET IDENTITY_INSERT infra_config OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +CREATE TABLE infra_data_source_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(100) DEFAULT '' NULL, + url varchar(1024) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) DEFAULT '' NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_data_source_config.id IS ''; +COMMENT ON COLUMN infra_data_source_config.name IS ''; +COMMENT ON COLUMN infra_data_source_config.url IS 'Դ'; +COMMENT ON COLUMN infra_data_source_config.username IS 'û'; +COMMENT ON COLUMN infra_data_source_config.password IS ''; +COMMENT ON COLUMN infra_data_source_config.creator IS ''; +COMMENT ON COLUMN infra_data_source_config.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_data_source_config.updater IS ''; +COMMENT ON COLUMN infra_data_source_config.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_data_source_config.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_data_source_config IS 'Դñ'; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +CREATE TABLE infra_file +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + config_id bigint DEFAULT NULL NULL, + name varchar(256) DEFAULT NULL NULL, + path varchar(512) NOT NULL, + url varchar(1024) NOT NULL, + type varchar(128) DEFAULT NULL NULL, + size int NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_file.id IS 'ļ'; +COMMENT ON COLUMN infra_file.config_id IS 'ñ'; +COMMENT ON COLUMN infra_file.name IS 'ļ'; +COMMENT ON COLUMN infra_file.path IS 'ļ·'; +COMMENT ON COLUMN infra_file.url IS 'ļ URL'; +COMMENT ON COLUMN infra_file.type IS 'ļ'; +COMMENT ON COLUMN infra_file.size IS 'ļС'; +COMMENT ON COLUMN infra_file.creator IS ''; +COMMENT ON COLUMN infra_file.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_file.updater IS ''; +COMMENT ON COLUMN infra_file.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_file.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_file IS 'ļ'; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +CREATE TABLE infra_file_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(63) NOT NULL, + storage smallint NOT NULL, + remark varchar(255) DEFAULT NULL NULL, + master bit NOT NULL, + config varchar(4096) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_file_config.id IS ''; +COMMENT ON COLUMN infra_file_config.name IS ''; +COMMENT ON COLUMN infra_file_config.storage IS '洢'; +COMMENT ON COLUMN infra_file_config.remark IS 'ע'; +COMMENT ON COLUMN infra_file_config.master IS 'ǷΪ'; +COMMENT ON COLUMN infra_file_config.config IS '洢'; +COMMENT ON COLUMN infra_file_config.creator IS ''; +COMMENT ON COLUMN infra_file_config.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_file_config.updater IS ''; +COMMENT ON COLUMN infra_file_config.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_file_config.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_file_config IS 'ļñ'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT infra_file_config ON; +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, 'ݿ', 1, 'ݿ', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, 'ţ洢', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +COMMIT; +SET IDENTITY_INSERT infra_file_config OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +CREATE TABLE infra_file_content +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + config_id bigint NOT NULL, + path varchar(512) NOT NULL, + content varchar(10240) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_file_content.id IS ''; +COMMENT ON COLUMN infra_file_content.config_id IS 'ñ'; +COMMENT ON COLUMN infra_file_content.path IS 'ļ·'; +COMMENT ON COLUMN infra_file_content.content IS 'ļ'; +COMMENT ON COLUMN infra_file_content.creator IS ''; +COMMENT ON COLUMN infra_file_content.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_file_content.updater IS ''; +COMMENT ON COLUMN infra_file_content.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_file_content.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_file_content IS 'ļ'; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +CREATE TABLE infra_job +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(32) NOT NULL, + status smallint NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) DEFAULT NULL NULL, + cron_expression varchar(32) NOT NULL, + retry_count int DEFAULT 0 NOT NULL, + retry_interval int DEFAULT 0 NOT NULL, + monitor_timeout int DEFAULT 0 NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_job.id IS ''; +COMMENT ON COLUMN infra_job.name IS ''; +COMMENT ON COLUMN infra_job.status IS '״̬'; +COMMENT ON COLUMN infra_job.handler_name IS ''; +COMMENT ON COLUMN infra_job.handler_param IS 'IJ'; +COMMENT ON COLUMN infra_job.cron_expression IS 'CRON ʽ'; +COMMENT ON COLUMN infra_job.retry_count IS 'Դ'; +COMMENT ON COLUMN infra_job.retry_interval IS 'Լ'; +COMMENT ON COLUMN infra_job.monitor_timeout IS 'سʱʱ'; +COMMENT ON COLUMN infra_job.creator IS ''; +COMMENT ON COLUMN infra_job.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_job.updater IS ''; +COMMENT ON COLUMN infra_job.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_job.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_job IS 'ʱ'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT infra_job ON; +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '֧֪ͨ Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '֧ͬ Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '֧ Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '˿ͬ Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, '׶Զ Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, '׶Զջ Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, '׶Զ Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, 'Ӷⶳ Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '־ Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '־ Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '־ Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', '0'); +COMMIT; +SET IDENTITY_INSERT infra_job OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +CREATE TABLE infra_job_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + job_id bigint NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) DEFAULT NULL NULL, + execute_index smallint DEFAULT 1 NOT NULL, + begin_time datetime NOT NULL, + end_time datetime DEFAULT NULL NULL, + duration int DEFAULT NULL NULL, + status smallint NOT NULL, + result varchar(4000) DEFAULT '' NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN infra_job_log.id IS '־'; +COMMENT ON COLUMN infra_job_log.job_id IS ''; +COMMENT ON COLUMN infra_job_log.handler_name IS ''; +COMMENT ON COLUMN infra_job_log.handler_param IS 'IJ'; +COMMENT ON COLUMN infra_job_log.execute_index IS 'ڼִ'; +COMMENT ON COLUMN infra_job_log.begin_time IS 'ʼִʱ'; +COMMENT ON COLUMN infra_job_log.end_time IS 'ִʱ'; +COMMENT ON COLUMN infra_job_log.duration IS 'ִʱ'; +COMMENT ON COLUMN infra_job_log.status IS '״̬'; +COMMENT ON COLUMN infra_job_log.result IS ''; +COMMENT ON COLUMN infra_job_log.creator IS ''; +COMMENT ON COLUMN infra_job_log.create_time IS 'ʱ'; +COMMENT ON COLUMN infra_job_log.updater IS ''; +COMMENT ON COLUMN infra_job_log.update_time IS 'ʱ'; +COMMENT ON COLUMN infra_job_log.deleted IS 'Ƿɾ'; +COMMENT ON TABLE infra_job_log IS 'ʱ־'; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +CREATE TABLE system_dept +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(30) DEFAULT '' NULL, + parent_id bigint DEFAULT 0 NOT NULL, + sort int DEFAULT 0 NOT NULL, + leader_user_id bigint DEFAULT NULL NULL, + phone varchar(11) DEFAULT NULL NULL, + email varchar(50) DEFAULT NULL NULL, + status smallint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_dept.id IS 'id'; +COMMENT ON COLUMN system_dept.name IS ''; +COMMENT ON COLUMN system_dept.parent_id IS 'id'; +COMMENT ON COLUMN system_dept.sort IS 'ʾ˳'; +COMMENT ON COLUMN system_dept.leader_user_id IS ''; +COMMENT ON COLUMN system_dept.phone IS 'ϵ绰'; +COMMENT ON COLUMN system_dept.email IS ''; +COMMENT ON COLUMN system_dept.status IS '״̬0 1ͣã'; +COMMENT ON COLUMN system_dept.creator IS ''; +COMMENT ON COLUMN system_dept.create_time IS 'ʱ'; +COMMENT ON COLUMN system_dept.updater IS ''; +COMMENT ON COLUMN system_dept.update_time IS 'ʱ'; +COMMENT ON COLUMN system_dept.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_dept.tenant_id IS '⻧'; +COMMENT ON TABLE system_dept IS 'ű'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_dept ON; +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'Դ', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, 'ܹ˾', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, 'ɳֹ˾', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'з', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'г', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, 'Բ', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'ά', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'г', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '²', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', '0', 121); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', '0', 122); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'Ʒ', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'ֲ֧', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2023-12-02 09:47:38', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_dept OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +CREATE TABLE system_dict_data +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + sort int DEFAULT 0 NOT NULL, + label varchar(100) DEFAULT '' NULL, + value varchar(100) DEFAULT '' NULL, + dict_type varchar(100) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + color_type varchar(100) DEFAULT '' NULL, + css_class varchar(100) DEFAULT '' NULL, + remark varchar(500) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_dict_data.id IS 'ֵ'; +COMMENT ON COLUMN system_dict_data.sort IS 'ֵ'; +COMMENT ON COLUMN system_dict_data.label IS 'ֵǩ'; +COMMENT ON COLUMN system_dict_data.value IS 'ֵֵ'; +COMMENT ON COLUMN system_dict_data.dict_type IS 'ֵ'; +COMMENT ON COLUMN system_dict_data.status IS '״̬0 1ͣã'; +COMMENT ON COLUMN system_dict_data.color_type IS 'ɫ'; +COMMENT ON COLUMN system_dict_data.css_class IS 'css ʽ'; +COMMENT ON COLUMN system_dict_data.remark IS 'ע'; +COMMENT ON COLUMN system_dict_data.creator IS ''; +COMMENT ON COLUMN system_dict_data.create_time IS 'ʱ'; +COMMENT ON COLUMN system_dict_data.updater IS ''; +COMMENT ON COLUMN system_dict_data.update_time IS 'ʱ'; +COMMENT ON COLUMN system_dict_data.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_dict_data IS 'ֵݱ'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_dict_data ON; +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '', '1', 'system_user_sex', 0, 'default', 'A', 'Ա', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, 'Ů', '2', 'system_user_sex', 0, 'success', '', 'ԱŮ', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '', '1', 'infra_job_status', 0, 'success', '', '״̬', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 'ͣ', '2', 'infra_job_status', 0, 'danger', '', 'ͣ״̬', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, 'ϵͳ', '1', 'infra_config_type', 0, 'danger', '', ' - ϵͳ', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, 'Զ', '2', 'infra_config_type', 0, 'primary', '', ' - Զ', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '֪ͨ', '1', 'system_notice_type', 0, 'success', '', '֪ͨ', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '', '2', 'system_notice_type', 0, 'info', '', '', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '', '0', 'infra_operate_type', 0, 'default', '', '', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, 'ѯ', '1', 'infra_operate_type', 0, 'info', '', 'ѯ', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '', '2', 'infra_operate_type', 0, 'primary', '', '', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '޸', '3', 'infra_operate_type', 0, 'warning', '', '޸IJ', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, 'ɾ', '4', 'infra_operate_type', 0, 'danger', '', 'ɾ', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '', '5', 'infra_operate_type', 0, 'default', '', '', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '', '6', 'infra_operate_type', 0, 'default', '', '', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '', '0', 'common_status', 0, 'primary', '', '״̬', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, 'ر', '1', 'common_status', 0, 'info', '', 'ر״̬', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, 'Ŀ¼', '1', 'system_menu_type', 0, '', '', 'Ŀ¼', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '˵', '2', 'system_menu_type', 0, '', '', '˵', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, 'ť', '3', 'system_menu_type', 0, '', '', 'ť', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '', '1', 'system_role_type', 0, 'danger', '', 'ýɫ', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, 'Զ', '2', 'system_role_type', 0, 'primary', '', 'Զɫ', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, 'ȫȨ', '1', 'system_data_scope', 0, '', '', 'ȫȨ', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, 'ָȨ', '2', 'system_data_scope', 0, '', '', 'ָȨ', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, 'Ȩ', '3', 'system_data_scope', 0, '', '', 'Ȩ', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, 'żȨ', '4', 'system_data_scope', 0, '', '', 'żȨ', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, 'Ȩ', '5', 'system_data_scope', 0, '', '', 'Ȩ', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, 'ɹ', '0', 'system_login_result', 0, 'success', '', '½ - ɹ', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '˺Ż벻ȷ', '10', 'system_login_result', 0, 'primary', '', '½ - ˺Ż벻ȷ', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, 'û', '20', 'system_login_result', 0, 'warning', '', '½ - û', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '֤벻', '30', 'system_login_result', 0, 'info', '', '½ - ֤벻', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '֤벻ȷ', '31', 'system_login_result', 0, 'info', '', '½ - ֤벻ȷ', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, 'δ֪쳣', '100', 'system_login_result', 0, 'danger', '', '½ - δ֪쳣', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean Ƿ - ', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean Ƿ - ', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, 'ɾIJ飩', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, 'ɾIJ飩', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, 'ʼ', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, 'ɹ', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, 'ʧ', '2', 'infra_job_log_status', 0, 'warning', '', 'ʧ', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, 'Ա', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, 'Ա', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2022-02-16 10:22:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, 'δ', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, 'Ѵ', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, 'Ѻ', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, '', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '֤', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '֪ͨ', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, 'Ӫ', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, 'ʼ', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, 'ͳɹ', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, 'ʧ', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, 'ȴ', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, 'ճɹ', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, 'ʧ', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '()', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '˺ŵ¼', '100', 'system_login_type', 0, 'primary', '', '˺ŵ¼', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '罻¼', '101', 'system_login_type', 0, 'info', '', '罻¼', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, 'dz', '200', 'system_login_type', 0, 'primary', '', 'dz', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, 'ǿƵdz', '202', 'system_login_type', 0, 'danger', '', 'ǿ˳', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '¼', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '΢Źں֧', 'wx_pub', 'pay_channel_code', 0, 'success', '', '΢Źں֧', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '΢С֧', 'wx_lite', 'pay_channel_code', 0, 'success', '', '΢С֧', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '΢ App ֧', 'wx_app', 'pay_channel_code', 0, 'success', '', '΢ App ֧', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '֧ PC վ֧', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '֧ PC վ֧', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '֧ Wap վ֧', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '֧ Wap վ֧', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '֧ App ֧', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '֧ App ֧', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '֧ɨ֧', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '֧ɨ֧', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '֪ͨɹ', '10', 'pay_notify_status', 0, 'success', '', '֪ͨɹ', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '֪ͨʧ', '20', 'pay_notify_status', 0, 'danger', '', '֪ͨʧ', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, 'ȴ֪ͨ', '0', 'pay_notify_status', 0, 'info', '', 'δ֪ͨ', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '֧ɹ', '10', 'pay_order_status', 0, 'success', '', '֧ɹ', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '֧ر', '30', 'pay_order_status', 0, 'info', '', '֧ر', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, 'ȴ֧', '0', 'pay_order_status', 0, 'info', '', 'δ֧', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, 'ҳ', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, 'ɱҳ', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, 'ۻҳ', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, 'ʱۿҳ', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, 'ҳ', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, 'ȴ˿', '0', 'pay_refund_status', 0, 'info', '', 'ȴ˿', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '˿ʧ', '20', 'pay_refund_status', 0, 'danger', '', '˿ʧ', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '˿ɹ', '10', 'pay_refund_status', 0, 'success', '', '˿ɹ', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '', '1', 'bpm_process_instance_status', 0, 'default', '', 'ʵ״̬ - ', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, 'ͨ', '2', 'bpm_process_instance_status', 0, 'success', '', 'ʵ״̬ - ', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '', '1', 'bpm_task_status', 0, 'primary', '', 'ʵĽ - ', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, 'ͨ', '2', 'bpm_task_status', 0, 'success', '', 'ʵĽ - ͨ', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, 'ͨ', '3', 'bpm_task_status', 0, 'danger', '', 'ʵĽ - ͨ', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, 'ȡ', '4', 'bpm_task_status', 0, 'info', '', 'ʵĽ - ', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '̱', '10', 'bpm_model_form_type', 0, '', '', '̵ı - ̱', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, 'ҵ', '20', 'bpm_model_form_type', 0, '', '', '̵ı - ҵ', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, 'ɫ', '10', 'bpm_task_candidate_strategy', 0, 'info', '', ' - ɫ', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, 'ŵijԱ', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', ' - ŵijԱ', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, 'ŵĸ', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', ' - ŵĸ', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, 'û', '30', 'bpm_task_candidate_strategy', 0, 'info', '', ' - û', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, 'û', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', ' - û', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '̱ʽ', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', ' - ̱ʽ', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, 'λ', '22', 'bpm_task_candidate_strategy', 0, 'success', '', ' - λ', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '̨', '1', 'infra_codegen_scene', 0, '', '', 'ɵijö - ̨', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, 'û APP', '2', 'infra_codegen_scene', 0, '', '', 'ɵijö - û APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, 'ݿ', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, 'ش', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP ', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP ', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 洢', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, 'ŵ¼', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', 'ģʽ', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', 'Ȩģʽ', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', 'ģʽ', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', 'ͻģʽ', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', 'ˢģʽ', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '', '1', 'product_spu_status', 0, 'success', '', 'Ʒ SPU ״̬ - ', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, 'ֿ', '0', 'product_spu_status', 0, 'info', '', 'Ʒ SPU ״̬ - ֿ', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, 'վ', '-1', 'product_spu_status', 0, 'default', '', 'Ʒ SPU ״̬ - վ', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '', '1', 'promotion_discount_type', 0, 'success', '', 'Ż - ', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, 'ۿ', '2', 'promotion_discount_type', 0, 'primary', '', 'Ż - ۿ', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '̶', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', 'Ż݄ģ - ̶', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, 'ȡ֮', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', 'Ż݄ģ - ȡ֮', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, 'ͨÄ', '1', 'promotion_product_scope', 0, 'default', '', 'ӪƷΧ - ȫƷ', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, 'Ʒ', '2', 'promotion_product_scope', 0, 'default', '', 'ӪƷΧ - ָƷ', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, 'δʹ', '1', 'promotion_coupon_status', 0, 'primary', '', 'Ż݄״̬ - ȡ', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, 'ʹ', '2', 'promotion_coupon_status', 0, 'success', '', 'Ż݄״̬ - ʹ', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, 'ѹ', '3', 'promotion_coupon_status', 0, 'info', '', 'Ż݄״̬ - ѹ', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, 'ֱȡ', '1', 'promotion_coupon_take_type', 0, 'primary', '', 'Ż݄ȡʽ - ֱȡ', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, 'ָ', '2', 'promotion_coupon_take_type', 0, 'success', '', 'Ż݄ȡʽ - ָ', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, 'δʼ', '10', 'promotion_activity_status', 0, 'primary', '', '״̬ö - δʼ', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '', '20', 'promotion_activity_status', 0, 'success', '', '״̬ö - ', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, 'ѽ', '30', 'promotion_activity_status', 0, 'info', '', '״̬ö - ѽ', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, 'ѹر', '40', 'promotion_activity_status', 0, 'warning', '', '״̬ö - ѹر', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, ' N Ԫ', '10', 'promotion_condition_type', 0, 'primary', '', 'Ӫ - N Ԫ', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, ' N ', '20', 'promotion_condition_type', 0, 'success', '', 'Ӫ - N ', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, 'ۺ', '10', 'trade_after_sale_status', 0, 'primary', '', 'ۺ״̬ - ۺ', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, 'Ʒ˻', '20', 'trade_after_sale_status', 0, 'primary', '', 'ۺ״̬ - Ʒ˻', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '̼Ҵջ', '30', 'trade_after_sale_status', 0, 'primary', '', 'ۺ״̬ - ̼Ҵջ', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, 'ȴ˿', '40', 'trade_after_sale_status', 0, 'primary', '', 'ۺ״̬ - ȴ˿', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '˿ɹ', '50', 'trade_after_sale_status', 0, 'default', '', 'ۺ״̬ - ˿ɹ', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, 'ȡ', '61', 'trade_after_sale_status', 0, 'info', '', 'ۺ״̬ - ȡ', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '̼Ҿܾ', '62', 'trade_after_sale_status', 0, 'info', '', 'ۺ״̬ - ̼Ҿܾ', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '̼Ҿջ', '63', 'trade_after_sale_status', 0, 'info', '', 'ۺ״̬ - ̼Ҿջ', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '˿', '10', 'trade_after_sale_type', 0, 'success', '', 'ۺ - ˿', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, 'ۺ˿', '20', 'trade_after_sale_type', 0, 'primary', '', 'ۺ - ۺ˿', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '˿', '10', 'trade_after_sale_way', 0, 'primary', '', 'ۺķʽ - ˿', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '˻˿', '20', 'trade_after_sale_way', 0, 'success', '', 'ۺķʽ - ˻˿', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '΢С', '10', 'terminal', 0, 'default', '', 'ն - ΢С', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 ҳ', '20', 'terminal', 0, 'default', '', 'ն - H5 ҳ', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '΢Źں', '11', 'terminal', 0, 'default', '', 'ն - ΢Źں', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, 'ƻ App', '31', 'terminal', 0, 'default', '', 'ն - ƻ App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '׿ App', '32', 'terminal', 0, 'default', '', 'ն - ׿ App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, 'ͨ', '0', 'trade_order_type', 0, 'default', '', '׶ - ͨ', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, 'ɱ', '1', 'trade_order_type', 0, 'default', '', '׶ - ɱ', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, 'ƴŶ', '2', 'trade_order_type', 0, 'default', '', '׶ - ƴŶ', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '۶', '3', 'trade_order_type', 0, 'default', '', '׶ - ۶', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '֧', '0', 'trade_order_status', 0, 'default', '', '׶״̬ - ֧', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '', '10', 'trade_order_status', 0, 'primary', '', '׶״̬ - ', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, 'ѷ', '20', 'trade_order_status', 0, 'primary', '', '׶״̬ - ѷ', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '', '30', 'trade_order_status', 0, 'success', '', '׶״̬ - ', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, 'ȡ', '40', 'trade_order_status', 0, 'danger', '', '׶״̬ - ȡ', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, 'δۺ', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '׶ۺ״̬ - δۺ', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, 'ۺ', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '׶ۺ״̬ - ۺ', '1', '2022-12-10 20:59:21', '1', '2022-12-10 20:59:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, '˿', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '׶ۺ״̬ - ˿', '1', '2022-12-10 20:59:46', '1', '2022-12-10 20:59:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, 'ȫƥ', '1', 'mp_auto_reply_request_match', 0, 'primary', '', 'ںԶظؼƥģʽ - ȫƥ', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, 'ƥ', '2', 'mp_auto_reply_request_match', 0, 'success', '', 'ںԶظؼƥģʽ - ƥ', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, 'ı', 'text', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ı', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, 'ͼƬ', 'image', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ͼƬ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '', 'voice', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, 'Ƶ', 'video', 'mp_message_type', 0, 'default', '', 'ںŵϢ - Ƶ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, 'СƵ', 'shortvideo', 'mp_message_type', 0, 'default', '', 'ںŵϢ - СƵ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, 'ͼ', 'news', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ͼ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '', 'music', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, 'λ', 'location', 'mp_message_type', 0, 'default', '', 'ںŵϢ - λ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '', 'link', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '¼', 'event', 'mp_message_type', 0, 'default', '', 'ںŵϢ - ¼', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, 'ʼ', '0', 'system_mail_send_status', 0, 'primary', '', 'ʼ״̬ - ʼ\n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, 'ͳɹ', '10', 'system_mail_send_status', 0, 'success', '', 'ʼ״̬ - ͳɹ', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, 'ʧ', '20', 'system_mail_send_status', 0, 'danger', '', 'ʼ״̬ - ʧ', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '', '30', 'system_mail_send_status', 0, 'info', '', 'ʼ״̬ - ', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '֪ͨ', '1', 'system_notify_template_type', 0, 'primary', '', 'վģ - ֪ͨ', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, 'ϵͳϢ', '2', 'system_notify_template_type', 0, 'success', '', 'վģ - ϵͳϢ', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '֧֧', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '֧֧', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI ׼ģ', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus ׼ģ', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, 'Vue3 Element Plus Schema ģ', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vue3 vben ģ', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, 'ֵֿ', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, 'ǩ', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '˿', '20', 'pay_order_status', 0, 'danger', '', '˿', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, 'ɹǽʧ', '21', 'pay_notify_status', 0, 'warning', '', 'ɹǽʧ', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, 'ʧ', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '΢ɨ֧', 'wx_native', 'pay_channel_code', 0, 'success', '', '΢ɨ֧', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '΢֧', 'wx_bar', 'pay_channel_code', 0, 'success', '', '΢֧\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '֧', '1', 'pay_notify_type', 0, 'primary', '', '֧', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '˿', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, 'ģ֧', 'mock', 'pay_channel_code', 0, 'default', '', 'ģ֧', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, 'ֵֿۣȡ', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, 'Ա', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '½', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, 'µ', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, 'µȡ', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, 'ǩ', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '齱', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, 'ݷ', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, 'û', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, 'Ʒ', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '˷', '1', 'brokerage_enabled_condition', 0, '', '', 'ûԷ', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, 'ָ', '2', 'brokerage_enabled_condition', 0, '', '', 'ɺֶ̨ƹԱ', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '״ΰ', '1', 'brokerage_bind_mode', 0, '', '', 'ֻҪûûƹˣʱ԰ƹϵ', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, 'ע', '2', 'brokerage_bind_mode', 0, '', '', 'ûעʱܰƹϵ', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, 'ǰ', '3', 'brokerage_bind_mode', 0, '', '', 'ûѾƹˣƹ˻ᱻ', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, 'Ǯ', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, 'п', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '΢', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '֧', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, 'Ӷ', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, 'ֲ', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, 'ѽ', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, 'ȡ', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, 'ͨ', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, 'ֳɹ', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '˲ͨ', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, 'ʧ', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, 'ũҵ', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, 'й', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, 'ͨ', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, 'Ǯ', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '۳ɹ', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, 'ʧ', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, 'ƴ', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, 'ƴųɹ', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, 'ƴʧ', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, 'Ա޸', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, 'ֵֿۣ˿', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, 'ֽ', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, 'ֽȡ', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, 'ֽ˿', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, 'µ˿', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, 'ת', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '֧', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '΢֧', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, 'ҵ', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, 'ز', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, 'ҵ', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '/', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, 'Ļý', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A صͻ', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B ͨͻ', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C ȿͻ', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, 'ת', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, 'ע', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, 'ѯ', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, 'ԤԼ', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, 'İ', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '绰ѯ', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, 'ʼѯ', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, 'ҵ΢', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '΢Źƽ̨', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '΢ſƽ̨', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '΢С', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, 'ϼ', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '¼', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, 'ӱ', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '׼ģʽ', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, 'ERP ģʽ', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, 'Ƕģʽ', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, 'ֻ', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, 'д', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, 'δύ', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, 'ͨ', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '˲ͨ', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, 'ȡ', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '֧Ʊ', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, 'ֽ', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, 'ת', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, 'ֻ', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, 'ö', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, 'ƿ', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '̨', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, 'ǧ', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '绰', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, 'Űݷ', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '΢Źͨ', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, 'Ǯ', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, 'п', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, '΢', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, '֧', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, 'תʧ', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, 'ת˳ɹ', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, 'ת˽', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, 'ȴת', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '⣨ϣ', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '⣨ϣ', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, 'δ', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '⣨ϣ', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '⣨ϣ', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, 'ӯ', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, 'ӯ⣨ϣ', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '̿', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '̿⣨ϣ', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '۳', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '۳⣨ϣ', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '˻', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '˻⣨ϣ', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, 'ɹ', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, 'ɹ⣨ϣ', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, 'ɹ˻', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, 'ɹ˻⣨ϣ', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, 'ͨ', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, 'ȡ', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '˻', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, 'ί', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, 'ͨ', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, 'ѡ', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, 'ִм', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java ', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, 'ʽ', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, 'ʽ', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, 'Ӯ', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '䵥', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, 'Ч', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0'); +COMMIT; +SET IDENTITY_INSERT system_dict_data OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +CREATE TABLE system_dict_type +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(100) DEFAULT '' NULL, + type varchar(100) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + remark varchar(500) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + deleted_time datetime DEFAULT NULL NULL +); + +COMMENT ON COLUMN system_dict_type.id IS 'ֵ'; +COMMENT ON COLUMN system_dict_type.name IS 'ֵ'; +COMMENT ON COLUMN system_dict_type.type IS 'ֵ'; +COMMENT ON COLUMN system_dict_type.status IS '״̬0 1ͣã'; +COMMENT ON COLUMN system_dict_type.remark IS 'ע'; +COMMENT ON COLUMN system_dict_type.creator IS ''; +COMMENT ON COLUMN system_dict_type.create_time IS 'ʱ'; +COMMENT ON COLUMN system_dict_type.updater IS ''; +COMMENT ON COLUMN system_dict_type.update_time IS 'ʱ'; +COMMENT ON COLUMN system_dict_type.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_dict_type.deleted_time IS 'ɾʱ'; +COMMENT ON TABLE system_dict_type IS 'ֵͱ'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_dict_type ON; +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, 'ûԱ', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '֪ͨ', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, 'ϵͳ״̬', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean Ƿ', 'infra_boolean_string', 0, 'boolean תǷ', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '½', 'system_login_result', 0, '½', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, 'ģ', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, 'ʱ״̬', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, 'ʱ־״̬', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, 'û', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 쳣ݵĴ״̬', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, 'ģ', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, 'ŷ״̬', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, 'Ž״̬', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '½־', 'system_login_type', 0, '½־', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA ', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '֧', 'pay_channel_code', 0, '֧ı', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '֧ص״̬', 'pay_notify_status', 0, '֧ص״̬˿ص', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '֧״̬', 'pay_order_status', 0, '֧״̬', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '˿״̬', 'pay_refund_status', 0, '˿״̬', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, 'ʵ״̬', 'bpm_process_instance_status', 0, 'ʵ״̬', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, 'ʵĽ', 'bpm_task_status', 0, 'ʵĽ', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '̵ı', 'bpm_model_form_type', 0, '̵ı', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '', 'bpm_task_candidate_strategy', 0, 'BPM ĺѡ˵IJ', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, 'ɵijö', 'infra_codegen_scene', 0, 'ɵijö', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, 'ɫ', 'system_role_type', 0, 'ɫ', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, 'ļ洢', 'infra_file_storage', 0, 'ļ洢', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 Ȩ', 'system_oauth2_grant_type', 0, 'OAuth 2.0 Ȩͣģʽ', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, 'Ʒ SPU ״̬', 'product_spu_status', 0, 'Ʒ SPU ״̬', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, 'Ż', 'promotion_discount_type', 0, 'Ż', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, 'Ż݄ģ', 'promotion_coupon_template_validity_type', 0, 'Ż݄ģ', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, 'ӪƷΧ', 'promotion_product_scope', 0, 'ӪƷΧ', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, 'Ż݄״̬', 'promotion_coupon_status', 0, 'Ż݄״̬', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, 'Ż݄ȡʽ', 'promotion_coupon_take_type', 0, 'Ż݄ȡʽ', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '״̬', 'promotion_activity_status', 0, '״̬', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, 'Ӫ', 'promotion_condition_type', 0, 'Ӫ', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, 'ۺ״̬', 'trade_after_sale_status', 0, 'ۺ״̬', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, 'ۺ', 'trade_after_sale_type', 0, 'ۺ', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, 'ۺķʽ', 'trade_after_sale_way', 0, 'ۺķʽ', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, 'ն', 'terminal', 0, 'ն', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '׶', 'trade_order_type', 0, '׶', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '׶״̬', 'trade_order_status', 0, '׶״̬', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '׶ۺ״̬', 'trade_order_item_after_sale_status', 0, '׶ۺ״̬', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, 'ںԶظؼƥģʽ', 'mp_auto_reply_request_match', 0, 'ںԶظؼƥģʽ', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, 'ںŵϢ', 'mp_message_type', 0, 'ںŵϢ', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, 'ʼ״̬', 'system_mail_send_status', 0, 'ʼ״̬', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, 'վģ', 'system_notify_template_type', 0, 'վģ', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, 'ɵǰ', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, 'ݼƷѷʽ', 'trade_delivery_express_charge_mode', 0, '̳ǽģ͹', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, 'ҵ', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '֧֪ͨ', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, 'Աҵ', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, 'Ӷģʽ', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, 'ϵģʽ', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, 'Ӷ', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, 'Ӷ¼ҵ', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, 'Ӷ¼״̬', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, 'Ӷ״̬', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, 'Ӷ', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, 'ۼ¼״̬', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, 'ƴż¼״̬', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, 'ؿ-ؿʽ', 'crm_receivable_return_type', 0, 'ؿ-ؿʽ', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM ͻҵ', 'crm_customer_industry', 0, 'CRM ͻҵ', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, 'ͻȼ', 'crm_customer_level', 0, 'CRM ͻȼ', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, 'ͻԴ', 'crm_customer_source', 0, 'CRM ͻԴ', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner λ', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '罻', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, 'Ʒ״̬', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM Ȩ޵ļ', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM ״̬', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM Ʒλ', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM ʽ', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, '֧ת', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, 'ת˶״̬', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP ϸҵ', 'erp_stock_record_biz_type', 0, 'ERP ϸҵ', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP ״̬', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM ', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM ֵ', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, 'ʱ', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM ̻״̬', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', '0', '1970-01-01 00:00:00'); +COMMIT; +SET IDENTITY_INSERT system_dict_type OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +CREATE TABLE system_login_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + log_type bigint NOT NULL, + trace_id varchar(64) DEFAULT '' NULL, + user_id bigint DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + username varchar(50) DEFAULT '' NULL, + result smallint NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_login_log.id IS 'ID'; +COMMENT ON COLUMN system_login_log.log_type IS '־'; +COMMENT ON COLUMN system_login_log.trace_id IS '·׷ٱ'; +COMMENT ON COLUMN system_login_log.user_id IS 'û'; +COMMENT ON COLUMN system_login_log.user_type IS 'û'; +COMMENT ON COLUMN system_login_log.username IS 'û˺'; +COMMENT ON COLUMN system_login_log.result IS '½'; +COMMENT ON COLUMN system_login_log.user_ip IS 'û IP'; +COMMENT ON COLUMN system_login_log.user_agent IS ' UA'; +COMMENT ON COLUMN system_login_log.creator IS ''; +COMMENT ON COLUMN system_login_log.create_time IS 'ʱ'; +COMMENT ON COLUMN system_login_log.updater IS ''; +COMMENT ON COLUMN system_login_log.update_time IS 'ʱ'; +COMMENT ON COLUMN system_login_log.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_login_log.tenant_id IS '⻧'; +COMMENT ON TABLE system_login_log IS 'ϵͳʼ¼'; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +CREATE TABLE system_mail_account +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + mail varchar(255) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + host varchar(255) NOT NULL, + port int NOT NULL, + ssl_enable bit DEFAULT '0' NOT NULL, + starttls_enable bit DEFAULT '0' NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_mail_account.id IS ''; +COMMENT ON COLUMN system_mail_account.mail IS ''; +COMMENT ON COLUMN system_mail_account.username IS 'û'; +COMMENT ON COLUMN system_mail_account.password IS ''; +COMMENT ON COLUMN system_mail_account.host IS 'SMTP '; +COMMENT ON COLUMN system_mail_account.port IS 'SMTP ˿'; +COMMENT ON COLUMN system_mail_account.ssl_enable IS 'Ƿ SSL'; +COMMENT ON COLUMN system_mail_account.starttls_enable IS 'Ƿ STARTTLS'; +COMMENT ON COLUMN system_mail_account.creator IS ''; +COMMENT ON COLUMN system_mail_account.create_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_account.updater IS ''; +COMMENT ON COLUMN system_mail_account.update_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_account.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_mail_account IS '˺ű'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_mail_account ON; +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', '1'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', '1'); +COMMIT; +SET IDENTITY_INSERT system_mail_account OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +CREATE TABLE system_mail_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint DEFAULT NULL NULL, + user_type smallint DEFAULT NULL NULL, + to_mail varchar(255) NOT NULL, + account_id bigint NOT NULL, + from_mail varchar(255) NOT NULL, + template_id bigint NOT NULL, + template_code varchar(63) NOT NULL, + template_nickname varchar(255) DEFAULT NULL NULL, + template_title varchar(255) NOT NULL, + template_content varchar(10240) NOT NULL, + template_params varchar(255) NOT NULL, + send_status smallint DEFAULT 0 NOT NULL, + send_time datetime DEFAULT NULL NULL, + send_message_id varchar(255) DEFAULT NULL NULL, + send_exception varchar(4096) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_mail_log.id IS ''; +COMMENT ON COLUMN system_mail_log.user_id IS 'û'; +COMMENT ON COLUMN system_mail_log.user_type IS 'û'; +COMMENT ON COLUMN system_mail_log.to_mail IS 'ַ'; +COMMENT ON COLUMN system_mail_log.account_id IS '˺ű'; +COMMENT ON COLUMN system_mail_log.from_mail IS 'ַ'; +COMMENT ON COLUMN system_mail_log.template_id IS 'ģ'; +COMMENT ON COLUMN system_mail_log.template_code IS 'ģ'; +COMMENT ON COLUMN system_mail_log.template_nickname IS 'ģ淢'; +COMMENT ON COLUMN system_mail_log.template_title IS 'ʼ'; +COMMENT ON COLUMN system_mail_log.template_content IS 'ʼ'; +COMMENT ON COLUMN system_mail_log.template_params IS 'ʼ'; +COMMENT ON COLUMN system_mail_log.send_status IS '״̬'; +COMMENT ON COLUMN system_mail_log.send_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_log.send_message_id IS 'ͷصϢ ID'; +COMMENT ON COLUMN system_mail_log.send_exception IS '쳣'; +COMMENT ON COLUMN system_mail_log.creator IS ''; +COMMENT ON COLUMN system_mail_log.create_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_log.updater IS ''; +COMMENT ON COLUMN system_mail_log.update_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_log.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_mail_log IS 'ʼ־'; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +CREATE TABLE system_mail_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(63) NOT NULL, + code varchar(63) NOT NULL, + account_id bigint NOT NULL, + nickname varchar(255) DEFAULT NULL NULL, + title varchar(255) NOT NULL, + content varchar(10240) NOT NULL, + params varchar(255) NOT NULL, + status smallint NOT NULL, + remark varchar(255) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_mail_template.id IS ''; +COMMENT ON COLUMN system_mail_template.name IS 'ģ'; +COMMENT ON COLUMN system_mail_template.code IS 'ģ'; +COMMENT ON COLUMN system_mail_template.account_id IS '͵˺ű'; +COMMENT ON COLUMN system_mail_template.nickname IS ''; +COMMENT ON COLUMN system_mail_template.title IS 'ģ'; +COMMENT ON COLUMN system_mail_template.content IS 'ģ'; +COMMENT ON COLUMN system_mail_template.params IS ''; +COMMENT ON COLUMN system_mail_template.status IS '״̬'; +COMMENT ON COLUMN system_mail_template.remark IS 'ע'; +COMMENT ON COLUMN system_mail_template.creator IS ''; +COMMENT ON COLUMN system_mail_template.create_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_template.updater IS ''; +COMMENT ON COLUMN system_mail_template.update_time IS 'ʱ'; +COMMENT ON COLUMN system_mail_template.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_mail_template IS 'ʼģ'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_mail_template ON; +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '̨ûŵ¼', 'admin-sms-login', 1, '', 'Ҳ', '

֤{code}{name}

', '["code","name"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 'ģ', 'test_01', 2, 'ܵ', 'һ', '

{key01}


ǵĻϽ {key02} һ£

', '["key01","key02"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', '0'); +COMMIT; +SET IDENTITY_INSERT system_mail_template OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +CREATE TABLE system_menu +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(50) NOT NULL, + permission varchar(100) DEFAULT '' NULL, + type smallint NOT NULL, + sort int DEFAULT 0 NOT NULL, + parent_id bigint DEFAULT 0 NOT NULL, + path varchar(200) DEFAULT '' NULL, + icon varchar(100) DEFAULT '#' NULL, + component varchar(255) DEFAULT NULL NULL, + component_name varchar(255) DEFAULT NULL NULL, + status smallint DEFAULT 0 NOT NULL, + visible bit DEFAULT '1' NOT NULL, + keep_alive bit DEFAULT '1' NOT NULL, + always_show bit DEFAULT '1' NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_menu.id IS '˵ID'; +COMMENT ON COLUMN system_menu.name IS '˵'; +COMMENT ON COLUMN system_menu.permission IS 'Ȩޱʶ'; +COMMENT ON COLUMN system_menu.type IS '˵'; +COMMENT ON COLUMN system_menu.sort IS 'ʾ˳'; +COMMENT ON COLUMN system_menu.parent_id IS '˵ID'; +COMMENT ON COLUMN system_menu.path IS '·ɵַ'; +COMMENT ON COLUMN system_menu.icon IS '˵ͼ'; +COMMENT ON COLUMN system_menu.component IS '·'; +COMMENT ON COLUMN system_menu.component_name IS ''; +COMMENT ON COLUMN system_menu.status IS '˵״̬'; +COMMENT ON COLUMN system_menu.visible IS 'Ƿɼ'; +COMMENT ON COLUMN system_menu.keep_alive IS 'Ƿ񻺴'; +COMMENT ON COLUMN system_menu.always_show IS 'Ƿʾ'; +COMMENT ON COLUMN system_menu.creator IS ''; +COMMENT ON COLUMN system_menu.create_time IS 'ʱ'; +COMMENT ON COLUMN system_menu.updater IS ''; +COMMENT ON COLUMN system_menu.update_time IS 'ʱ'; +COMMENT ON COLUMN system_menu.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_menu IS '˵Ȩޱ'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_menu ON; +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, 'ϵͳ', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, 'ʩ', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA ʾ', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, 'û', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, 'ɫ', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '˵', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, 'Ź', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, 'λ', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, 'ֵ', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, 'ù', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '֪ͨ', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '־', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, 'ƹ', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, 'ʱ', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL ', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java ', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis ', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API ӿ', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '־', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '¼־', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, 'ûѯ', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, 'û', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, 'û޸', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, 'ûɾ', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, 'û', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, 'û', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, 'ɫѯ', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, 'ɫ', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, 'ɫ޸', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, 'ɫɾ', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, 'ɫ', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '˵ѯ', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '˵', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '˵޸', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '˵ɾ', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, 'Ųѯ', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '޸', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, 'ɾ', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, 'λѯ', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, 'λ', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, 'λ޸', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, 'λɾ', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, 'λ', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, 'ֵѯ', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, 'ֵ', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, 'ֵ޸', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, 'ֵɾ', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, 'ֵ䵼', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, 'òѯ', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '޸', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, 'ɾ', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, 'õ', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, 'ѯ', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '޸', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, 'ɾ', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, 'ѯ', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '־', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '¼ѯ', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '־', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, 'б', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, 'ɾ', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '޸', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, 'ɾ', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '״̬޸', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '񵼳', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '޸', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, 'ɾ', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, 'Ԥ', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, 'ɴ', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, 'ýɫ˵Ȩ', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, 'ýɫȨ', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, 'ûɫ', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, ' Redis Ϣ', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, ' Redis Key б', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, 'ɰ', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '񴥷', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '·׷', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '־', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '־', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API ־', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '־', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '־', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '־', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, 'ѯ', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '־ѯ', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '־ѯ', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, 'ļб', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, 'ļѯ', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, 'ļɾ', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, 'Ź', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, 'ѯ', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, 'ɾ', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, 'ģ', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, 'ģѯ', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, 'ģ崴', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, 'ģ', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, 'ģɾ', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, 'ģ嵼', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, 'ͲԶ', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '־', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '־ѯ', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '־', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '֧', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, 'ٲѯ', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, 'ѯ', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '봴', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, 'ӦϢ', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '֧ӦϢѯ', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '֧ӦϢ', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '֧ӦϢ', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '֧ӦϢɾ', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, 'Կ', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '֧̻Ϣѯ', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '֧̻Ϣ', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '֧̻Ϣ', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '֧̻Ϣɾ', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '֧̻Ϣ', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '⻧б', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '⻧ѯ', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '⻧', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '⻧', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '⻧ɾ', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '⻧', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, 'Կ', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '˿', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '˿ѯ', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, '˿', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, '˿', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, '˿ɾ', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '˿', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '֧', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '֧ѯ', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, '֧', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, '֧', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, '֧ɾ', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '֧', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '̹', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '̱', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, 'ѯ', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, 'ɾ', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, 'ģ', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, 'ģͲѯ', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, 'ģʹ', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, 'ģ͵', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, 'ģ͸', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, 'ģɾ', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, 'ģͷ', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, 'ҵ', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, 'ʵIJѯ', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, 'Ѱ', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, 'û', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, 'ûѯ', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, 'û鴴', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, 'û', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, 'ûɾ', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '̶ѯ', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, 'ѯ', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '򴴽', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, 'ʵĴ', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, 'ʵȡ', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, 'IJѯ', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, 'ĸ', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '⻧', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '⻧ײ', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '⻧ײͲѯ', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '⻧ײʹ', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '⻧ײ͸', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '⻧ײɾ', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, 'ļ', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, 'ļòѯ', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, 'ļô', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, 'ļø', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, 'ļɾ', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, 'ļõ', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, 'ļ', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '߶̬', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, 'Դ', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, 'Դòѯ', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, 'Դô', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, 'Դø', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, 'Դɾ', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, 'Դõ', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, 'Ӧù', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, 'ͻ˲ѯ', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, 'ͻ˴', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, 'ͻ˸', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, 'ͻɾ', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, '1', '1', '1', '1', '2022-07-10 20:26:36', '1', '2024-02-29 12:33:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, 'Ʒ', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, 'Ʒ', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, 'ѯ', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, 'ഴ', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, 'ɾ', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, 'ƷƷ', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, 'ƷƲѯ', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, 'Ʒƴ', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, 'ƷƸ', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, 'Ʒɾ', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, 'Ʒб', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, 'Ʒѯ', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, 'Ʒ', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, 'Ʒ', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, 'Ʒɾ', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, 'Ʒ', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, 'ѯ', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '񴴽', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, 'ɾ', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Bannerѯ', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Bannerɾ', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, 'Ӫ', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, 'Ż݄б', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, 'Ż݄ģѯ', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, 'Ż݄ģ崴', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, 'Ż݄ģ', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, 'Ż݄ģɾ', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, 'ȡ¼', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, 'Ż݄ѯ', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, 'Ż݄ɾ', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, 'ͻѯ', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, 'ͻ', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, 'ͻ', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, 'ͻɾ', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, 'ͻر', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, 'ʱۿ', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, 'ʱۿۻѯ', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, 'ʱۿۻ', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, 'ʱۿۻ', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, 'ʱۿۻɾ', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, 'ʱۿۻر', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, 'ɱƷ', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, 'ɱѯ', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, 'ɱ', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, 'ɱ', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, 'ɱɾ', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, 'ɱʱ', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, 'ɱʱβѯ', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, 'ɱʱδ', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, 'ɱʱθ', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, 'ɱʱɾ', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, 'ۺ˿', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, 'ۺѯ', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, 'ɱر', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, 'б', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, 'ںŹ', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '˺Ź', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '˺', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '޸˺', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, 'ѯ˺', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, 'ɾ˺', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, 'ɶά', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, ' API ', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, 'ͳ', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, 'ǩ', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, 'ѯǩ', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, 'ǩ', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '޸ıǩ', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, 'ɾǩ', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, 'ͬǩ', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '˿', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, 'ѯ˿', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '޸ķ˿', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, 'ͬ˿', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, 'Ϣ', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, 'ͼķ¼', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, 'ѯб', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, 'ݸ', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, 'ɾ¼', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, 'ͼIJݸ', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '½ݸ', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '޸IJݸ', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, 'ѯݸ', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, 'ɾݸ', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, 'زĹ', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, 'ϴʱز', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, 'ϴز', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, 'ɾز', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, 'ϴͼͼƬ', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, 'ѯز', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '˵', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', '2023-01-14 17:43:54', '1', '2024-02-29 12:42:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, 'Զظ', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, 'ѯظ', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, 'ظ', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '޸Ļظ', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, 'ɾظ', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, 'ѯ˵', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '˵', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, 'ɾ˵', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, 'ѯϢ', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, 'Ϣ', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '˺', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '˺Ųѯ', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '˺Ŵ', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '˺Ÿ', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '˺ɾ', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, 'ʼģ', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, 'ģѯ', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, 'ģ洴', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, 'ģ', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, 'ģɾ', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, 'ʼ¼', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '־ѯ', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, 'Ͳʼ', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, 'վŹ', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, 'ģ', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, 'վģѯ', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, 'վģ崴', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, 'վģ', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, 'վģɾ', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, 'Ͳվ', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, 'Ϣ¼', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, 'վϢѯ', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, '1', '1', '1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, 'Ŀ', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, 'Ŀ', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, 'ѯĿ', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, 'ʹ SQL ѯ', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, 'ʹ HTTP ѯ', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot ĵ', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:46:28', '1', '2023-12-02 21:32:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud ĵ', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, 'ʾ', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, 'Ʒ', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '͹', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, 'ݷ', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, 'ŵ', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, 'ݹ˾', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, 'ݹ˾ѯ', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, 'ݹ˾', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, 'ݹ˾', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, 'ݹ˾ɾ', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, 'ݹ˾', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '˷ģ', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '˷ģѯ', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '˷ģ崴', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '˷ģ', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '˷ģɾ', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '˷ģ嵼', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, 'ŵ', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, 'ŵѯ', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, 'ŵ괴', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, 'ŵ', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, 'ŵɾ', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, 'ŵ굼', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, 'ɱ', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, 'Ա', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, 'Ա', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, 'Աòѯ', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, 'Աñ', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, 'ǩ', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, 'ǩѯ', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, 'ǩ򴴽', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, 'ǩ', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, 'ǩɾ', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, 'Ա', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, 'ûּ¼ѯ', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, 'ǩ¼', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, 'ûǩֲѯ', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, 'ûǩɾ', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, 'Աǩ', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, 'ص֪ͨ', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '֧֪ͨѯ', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, 'ƴŻ', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, 'ƴƷ', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, 'ƴŻѯ', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, 'ƴŻ', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, 'ƴŻ', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, 'ƴŻɾ', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, 'ƴŻر', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, 'ۻ', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, 'Ʒ', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, 'ۻѯ', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, 'ۻ', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, 'ۻ', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, 'ۻɾ', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, 'ۻر', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, 'Ա', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, 'Աûѯ', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, 'Աû', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, 'Աǩ', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, 'Աǩѯ', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, 'Աǩ', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, 'Աǩ', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, 'Աǩɾ', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, 'Աȼ', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, 'Աȼѯ', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, 'Աȼ', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, 'Աȼ', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, 'Աȼɾ', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, 'Ա', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, 'ûѯ', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, 'û鴴', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, 'û', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, 'ûɾ', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, 'ûȼ޸', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, 'Ʒ', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '۲ѯ', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '̼һظ', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, 'Ż݄', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, 'òѯ', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, 'ñ', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, 'û', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, 'ûѯ', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, 'ûƹ˲ѯ', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, 'ûƹ㶩ѯ', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, 'û޸ƹʸ', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, 'û޸ƹԱ', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, 'ûƹԱ', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, 'Ӷ¼', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, 'Ӷ¼ѯ', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, 'Ӷ', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, 'Ӷֲѯ', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, 'Ӷ', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, 'ͳ', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, 'ͳ', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, 'ͳƲѯ', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, 'ͳƵ', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '̳ϵͳ', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, 'û޸', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, 'û޸', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, 'Ż݄', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, 'ۼ¼', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, 'ۼ¼ѯ', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '¼ѯ', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, 'ƴż¼', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, 'Աͳ', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, 'ԱͳƲѯ', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '·', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, 'ѯ', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, 'ഴ', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, 'ɾ', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, 'б', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '¹ѯ', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '¹', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '¹', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '¹ɾ', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, 'ݹ', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '̳ҳ', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, 'Żݻ', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, 'ͻ', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, 'ͻѯ', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, 'ͻ', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, 'ͻ', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, 'ͻɾ', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, 'ͻ', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM ϵͳ', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, '1', '1', '1', '1', '2023-10-29 17:08:30', '1', '2024-02-04 15:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, 'ͬ', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, 'ͬѯ', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, 'ͬ', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, 'ͬ', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, 'ͬɾ', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, 'ͬ', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, 'ѯ', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, 'ɾ', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '̻', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '̻ѯ', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '̻', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '̻', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '̻ɾ', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '̻', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, 'ϵ˹', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, 'ϵ˲ѯ', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, 'ϵ˴', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, 'ϵ˸', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, 'ϵɾ', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, 'ϵ˵', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, 'ؿ', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, 'ؿѯ', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, 'ؿ', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, 'ؿ', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, 'ؿɾ', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, 'ؿ', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, 'ؿƻ', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, 'ؿƻѯ', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, 'ؿƻ', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, 'ؿƻ', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, 'ؿƻɾ', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, 'ؿƻ', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '̳װ', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, 'װģ', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, 'װģѯ', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, 'װģ崴', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, 'װģ', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, 'װģɾ', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, 'װģʹ', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, 'װҳ', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, 'װҳѯ', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, 'װҳ洴', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, 'װҳ', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, 'װҳɾ', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '¼', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, 'Ӧ', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, 'Ӧòѯ', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, 'Ӧô', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, 'Ӧø', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, 'Ӧɾ', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, 'û', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, 'ӱǶ', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, 'ɾIJ飩', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, 'ʾϵ˲ѯ', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, 'ʾϵ˴', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, 'ʾϵ˸', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, 'ʾϵɾ', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, 'ʾϵ˵', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, 'ɾIJ飩', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, 'ʾѯ', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, 'ʾഴ', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, 'ʾ', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, 'ʾɾ', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, 'ʾർ', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, 'ӱ׼', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, 'ѧѯ', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, 'ѧ', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, 'ѧ', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, 'ѧɾ', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, 'ѧ', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, 'ӱERP', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, 'ͻ', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, 'ͻñ', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, 'ͻ', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, 'ͻòѯ', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, 'ͻô', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, 'ͻø', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, 'ͻɾ', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, 'ͻõ', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, 'ϵͳ', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, 'Ʒ', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, 'Ʒѯ', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, 'Ʒ', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, 'Ʒ', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, 'Ʒɾ', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, 'Ʒ', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, 'Ʒ', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, 'Ʒѯ', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, 'Ʒഴ', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, 'Ʒ', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, 'Ʒɾ', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '̻', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, 'ȡ̻', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, 'Ʒͳ', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, 'ͻ', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, 'ѯ', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '֧&˿', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, 'ת˰', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:51:16', '1', '2024-01-18 23:51:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, 'Ǯ', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, 'ֵײ', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, 'ǮֵײͲѯ', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, 'Ǯֵײʹ', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, 'Ǯֵײ͸', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, 'Ǯֵײɾ', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, 'Ǯ', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, 'Ǯѯ', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, 'ת˶', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, 'ͳ', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, 'а', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, 'ͻ', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP ϵͳ', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, 'Ʒ', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, 'ƷϢ', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, 'Ʒѯ', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, 'Ʒ', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, 'Ʒ', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, 'Ʒɾ', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, 'Ʒ', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, 'Ʒ', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, 'ѯ', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, 'ഴ', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, 'ɾ', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, 'ർ', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, 'Ʒλ', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, 'λѯ', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, 'λ', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, 'λ', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, 'λɾ', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, 'λ', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, 'ֿϢ', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, 'ֿѯ', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, 'ֿⴴ', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, 'ֿ', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, 'ֿɾ', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, 'ֿ⵼', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, 'Ʒ', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, 'ѯ', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '浼', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, 'ϸ', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, 'ϸѯ', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, 'ϸ', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, 'ⵥѯ', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, 'ⵥ', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, 'ⵥ', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, 'ⵥɾ', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, 'ⵥ', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, 'ɹ', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, 'ӦϢ', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, 'Ӧ̲ѯ', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, 'Ӧ̴', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, 'Ӧ̸', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, 'Ӧɾ', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, 'Ӧ̵', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, 'ⵥ', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, 'ⵥѯ', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, 'ⵥ', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, 'ⵥ', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, 'ⵥɾ', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, 'ⵥ', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, 'ⵥ', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '۹', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, 'ͻϢ', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, 'ͻѯ', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, 'ͻ', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, 'ͻ', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, 'ͻɾ', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, 'ͻ', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, 'ȵѯ', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, 'ȵ', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, 'ȵ', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, 'ȵɾ', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, 'ȵ', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, 'ȵ', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '̵', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '̵㵥ѯ', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '̵㵥', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '̵㵥', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '̵㵥ɾ', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '̵㵥', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '̵㵥', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '۶', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '۶ѯ', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '۶', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '۶', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '۶ɾ', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '۶', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '۶', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '˻', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '˻ѯ', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '˻', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '˻', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '˻ɾ', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '˻', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '۳', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '۳ѯ', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '۳ⴴ', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '۳', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '۳ɾ', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '۳⵼', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '۳', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '˻', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '˻ѯ', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '˻', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '˻', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '˻ɾ', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '˻', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '˻', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, 'ɹ', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, 'ɹѯ', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, 'ɹ', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, 'ɹ', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, 'ɹɾ', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, 'ɹ', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, 'ɹ', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, 'ɹ', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, 'ɹѯ', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, 'ɹⴴ', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, 'ɹ', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, 'ɹɾ', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, 'ɹ⵼', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, 'ɹ', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, 'ɹ˻', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, 'ɹ˻ѯ', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, 'ɹ˻', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, 'ɹ˻', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, 'ɹ˻ɾ', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, 'ɹ˻', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, 'ɹ˻', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, 'ѯ', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, 'ɾ', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, 'տ', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, 'տѯ', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, 'տ', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, 'տ', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, 'տɾ', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, 'տ', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, 'տ', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP ҳ', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '̻״̬', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '̻״̬ѯ', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '̻״̬', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '̻״̬', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '̻״̬ɾ', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, 'ͬ', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, 'ͻòѯ', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, 'ͬø', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, 'ͬòѯ', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, 'ͻ', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, 'ҵ', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '̷', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, 'ѯ', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, 'ഴ', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, 'ɾ', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, 'ʵ', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, 'ʵIJѯԱ', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, 'ʵȡԱ', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, 'IJѯԱ', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '̼', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '̼ѯ', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '̼', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '̼', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '̼ɾ', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '̱ʽ', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '̱ʽѯ', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '̱ʽ', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '̱ʽ', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '̱ʽɾ', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, 'Աҵ', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, 'ͻ', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '©', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, 'Ϣ', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, 'ȡͻ', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '乫ͻ', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, 'ƷͳƲѯ', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, 'ƷͳƵ', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '֧ѯ', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '֧', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '֧', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '֧ɾ', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, 'Ʒղزѯ', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, 'Ʒѯ', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, 'ۺͬ', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, 'ۺͬ', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, 'ۺȷ˻', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, 'ۺȷ˿', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, 'ɾĿ', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, 'Աȼ¼ѯ', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, 'Ա¼ѯ', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0'); +COMMIT; +SET IDENTITY_INSERT system_menu OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +CREATE TABLE system_notice +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + title varchar(50) NOT NULL, + content text NOT NULL, + type smallint NOT NULL, + status smallint DEFAULT 0 NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_notice.id IS 'ID'; +COMMENT ON COLUMN system_notice.title IS ''; +COMMENT ON COLUMN system_notice.content IS ''; +COMMENT ON COLUMN system_notice.type IS 'ͣ1֪ͨ 2棩'; +COMMENT ON COLUMN system_notice.status IS '״̬0 1رգ'; +COMMENT ON COLUMN system_notice.creator IS ''; +COMMENT ON COLUMN system_notice.create_time IS 'ʱ'; +COMMENT ON COLUMN system_notice.updater IS ''; +COMMENT ON COLUMN system_notice.update_time IS 'ʱ'; +COMMENT ON COLUMN system_notice.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_notice.tenant_id IS '⻧'; +COMMENT ON TABLE system_notice IS '֪ͨ'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_notice ON; +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'Ĺ', '

°汾133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'ά֪ͨ2018-07-01 ϵͳ賿ά', '

11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'DzԱ', '

123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', '0', 121); +COMMIT; +SET IDENTITY_INSERT system_notice OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +CREATE TABLE system_notify_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type smallint NOT NULL, + template_id bigint NOT NULL, + template_code varchar(64) NOT NULL, + template_nickname varchar(63) NOT NULL, + template_content varchar(1024) NOT NULL, + template_type int NOT NULL, + template_params varchar(255) NOT NULL, + read_status bit NOT NULL, + read_time datetime DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_notify_message.id IS 'ûID'; +COMMENT ON COLUMN system_notify_message.user_id IS 'ûid'; +COMMENT ON COLUMN system_notify_message.user_type IS 'û'; +COMMENT ON COLUMN system_notify_message.template_id IS 'ģ'; +COMMENT ON COLUMN system_notify_message.template_code IS 'ģ'; +COMMENT ON COLUMN system_notify_message.template_nickname IS 'ģ淢'; +COMMENT ON COLUMN system_notify_message.template_content IS 'ģ'; +COMMENT ON COLUMN system_notify_message.template_type IS 'ģ'; +COMMENT ON COLUMN system_notify_message.template_params IS 'ģ'; +COMMENT ON COLUMN system_notify_message.read_status IS 'ǷѶ'; +COMMENT ON COLUMN system_notify_message.read_time IS 'Ķʱ'; +COMMENT ON COLUMN system_notify_message.creator IS ''; +COMMENT ON COLUMN system_notify_message.create_time IS 'ʱ'; +COMMENT ON COLUMN system_notify_message.updater IS ''; +COMMENT ON COLUMN system_notify_message.update_time IS 'ʱ'; +COMMENT ON COLUMN system_notify_message.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_notify_message.tenant_id IS '⻧'; +COMMENT ON TABLE system_notify_message IS 'վϢ'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_notify_message ON; +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', ' 1ҿʼ 2 ', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:44:08', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', ' 1ҿʼ 2 ', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:45:04', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', 'ϵͳϢ', 'ãӭ ͥ', 2, '{"name":""}', '0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', ' ܵҿʼ д ', 1, '{"name":"ܵ","what":"д"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 22:21:42', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', ' ܵҿʼ д ', 1, '{"name":"ܵ","what":"д"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', ' 2ҿʼ 3 ', 1, '{"name":"2","what":"3"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', 'ϵͳϢ', 'ãӭ 123 ͥ', 2, '{"name":"123"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '2023-09-28 08:35:46֣0.09Ԫͨ', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '2023-09-30 20:59:40֣1.00Ԫͨ', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_notify_message OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +CREATE TABLE system_notify_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(63) NOT NULL, + code varchar(64) NOT NULL, + nickname varchar(255) NOT NULL, + content varchar(1024) NOT NULL, + type smallint NOT NULL, + params varchar(255) DEFAULT NULL NULL, + status smallint NOT NULL, + remark varchar(255) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_notify_template.id IS ''; +COMMENT ON COLUMN system_notify_template.name IS 'ģ'; +COMMENT ON COLUMN system_notify_template.code IS 'ģ'; +COMMENT ON COLUMN system_notify_template.nickname IS ''; +COMMENT ON COLUMN system_notify_template.content IS 'ģ'; +COMMENT ON COLUMN system_notify_template.type IS ''; +COMMENT ON COLUMN system_notify_template.params IS ''; +COMMENT ON COLUMN system_notify_template.status IS '״̬'; +COMMENT ON COLUMN system_notify_template.remark IS 'ע'; +COMMENT ON COLUMN system_notify_template.creator IS ''; +COMMENT ON COLUMN system_notify_template.create_time IS 'ʱ'; +COMMENT ON COLUMN system_notify_template.updater IS ''; +COMMENT ON COLUMN system_notify_template.update_time IS 'ʱ'; +COMMENT ON COLUMN system_notify_template.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_notify_template IS 'վģ'; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +CREATE TABLE system_oauth2_access_token +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type smallint NOT NULL, + user_info varchar(512) NOT NULL, + access_token varchar(255) NOT NULL, + refresh_token varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) DEFAULT NULL NULL, + expires_time datetime NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token); +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token); + +COMMENT ON COLUMN system_oauth2_access_token.id IS ''; +COMMENT ON COLUMN system_oauth2_access_token.user_id IS 'û'; +COMMENT ON COLUMN system_oauth2_access_token.user_type IS 'û'; +COMMENT ON COLUMN system_oauth2_access_token.user_info IS 'ûϢ'; +COMMENT ON COLUMN system_oauth2_access_token.access_token IS ''; +COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS 'ˢ'; +COMMENT ON COLUMN system_oauth2_access_token.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_oauth2_access_token.scopes IS 'ȨΧ'; +COMMENT ON COLUMN system_oauth2_access_token.expires_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_access_token.creator IS ''; +COMMENT ON COLUMN system_oauth2_access_token.create_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_access_token.updater IS ''; +COMMENT ON COLUMN system_oauth2_access_token.update_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_access_token.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '⻧'; +COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 '; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +CREATE TABLE system_oauth2_approve +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type smallint NOT NULL, + client_id varchar(255) NOT NULL, + scope varchar(255) DEFAULT '' NULL, + approved bit DEFAULT '0' NOT NULL, + expires_time datetime NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_oauth2_approve.id IS ''; +COMMENT ON COLUMN system_oauth2_approve.user_id IS 'û'; +COMMENT ON COLUMN system_oauth2_approve.user_type IS 'û'; +COMMENT ON COLUMN system_oauth2_approve.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_oauth2_approve.scope IS 'ȨΧ'; +COMMENT ON COLUMN system_oauth2_approve.approved IS 'Ƿ'; +COMMENT ON COLUMN system_oauth2_approve.expires_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_approve.creator IS ''; +COMMENT ON COLUMN system_oauth2_approve.create_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_approve.updater IS ''; +COMMENT ON COLUMN system_oauth2_approve.update_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_approve.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '⻧'; +COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 ׼'; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +CREATE TABLE system_oauth2_client +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + client_id varchar(255) NOT NULL, + secret varchar(255) NOT NULL, + name varchar(255) NOT NULL, + logo varchar(255) NOT NULL, + description varchar(255) DEFAULT NULL NULL, + status smallint NOT NULL, + access_token_validity_seconds int NOT NULL, + refresh_token_validity_seconds int NOT NULL, + redirect_uris varchar(255) NOT NULL, + authorized_grant_types varchar(255) NOT NULL, + scopes varchar(255) DEFAULT NULL NULL, + auto_approve_scopes varchar(255) DEFAULT NULL NULL, + authorities varchar(255) DEFAULT NULL NULL, + resource_ids varchar(255) DEFAULT NULL NULL, + additional_information varchar(4096) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_oauth2_client.id IS ''; +COMMENT ON COLUMN system_oauth2_client.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_oauth2_client.secret IS 'ͻԿ'; +COMMENT ON COLUMN system_oauth2_client.name IS 'Ӧ'; +COMMENT ON COLUMN system_oauth2_client.logo IS 'Ӧͼ'; +COMMENT ON COLUMN system_oauth2_client.description IS 'Ӧ'; +COMMENT ON COLUMN system_oauth2_client.status IS '״̬'; +COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS 'ƵЧ'; +COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS 'ˢƵЧ'; +COMMENT ON COLUMN system_oauth2_client.redirect_uris IS 'ض URI ַ'; +COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS 'Ȩ'; +COMMENT ON COLUMN system_oauth2_client.scopes IS 'ȨΧ'; +COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS 'ԶͨȨΧ'; +COMMENT ON COLUMN system_oauth2_client.authorities IS 'Ȩ'; +COMMENT ON COLUMN system_oauth2_client.resource_ids IS 'Դ'; +COMMENT ON COLUMN system_oauth2_client.additional_information IS 'Ϣ'; +COMMENT ON COLUMN system_oauth2_client.creator IS ''; +COMMENT ON COLUMN system_oauth2_client.create_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_client.updater IS ''; +COMMENT ON COLUMN system_oauth2_client.update_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_client.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_oauth2_client IS 'OAuth2 ͻ˱'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_oauth2_client ON; +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', 'Դ', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2024-02-22 16:31:52', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2023-12-02 21:01:01', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', 'Ȩģʽʵ SSO ¼', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2022-09-29 13:28:31', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', 'ģʽʵ SSO ¼', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2022-10-04 20:31:21', '0'); +COMMIT; +SET IDENTITY_INSERT system_oauth2_client OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +CREATE TABLE system_oauth2_code +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type smallint NOT NULL, + code varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) DEFAULT '' NULL, + expires_time datetime NOT NULL, + redirect_uri varchar(255) DEFAULT NULL NULL, + state varchar(255) DEFAULT '' NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_oauth2_code.id IS ''; +COMMENT ON COLUMN system_oauth2_code.user_id IS 'û'; +COMMENT ON COLUMN system_oauth2_code.user_type IS 'û'; +COMMENT ON COLUMN system_oauth2_code.code IS 'Ȩ'; +COMMENT ON COLUMN system_oauth2_code.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_oauth2_code.scopes IS 'ȨΧ'; +COMMENT ON COLUMN system_oauth2_code.expires_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_code.redirect_uri IS 'ض URI ַ'; +COMMENT ON COLUMN system_oauth2_code.state IS '״̬'; +COMMENT ON COLUMN system_oauth2_code.creator IS ''; +COMMENT ON COLUMN system_oauth2_code.create_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_code.updater IS ''; +COMMENT ON COLUMN system_oauth2_code.update_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_code.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_oauth2_code.tenant_id IS '⻧'; +COMMENT ON TABLE system_oauth2_code IS 'OAuth2 Ȩ'; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +CREATE TABLE system_oauth2_refresh_token +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + refresh_token varchar(32) NOT NULL, + user_type smallint NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) DEFAULT NULL NULL, + expires_time datetime NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_oauth2_refresh_token.id IS ''; +COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS 'û'; +COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS 'ˢ'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS 'û'; +COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS 'ȨΧ'; +COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_refresh_token.creator IS ''; +COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_refresh_token.updater IS ''; +COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS 'ʱ'; +COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '⻧'; +COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 ˢ'; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +CREATE TABLE system_operate_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id varchar(64) DEFAULT '' NULL, + user_id bigint NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + type varchar(50) NOT NULL, + sub_type varchar(50) NOT NULL, + biz_id bigint NOT NULL, + action varchar(2000) DEFAULT '' NULL, + extra varchar(2000) DEFAULT '' NULL, + request_method varchar(16) DEFAULT '' NULL, + request_url varchar(255) DEFAULT '' NULL, + user_ip varchar(50) DEFAULT NULL NULL, + user_agent varchar(200) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_operate_log.id IS '־'; +COMMENT ON COLUMN system_operate_log.trace_id IS '·׷ٱ'; +COMMENT ON COLUMN system_operate_log.user_id IS 'û'; +COMMENT ON COLUMN system_operate_log.user_type IS 'û'; +COMMENT ON COLUMN system_operate_log.type IS 'ģ'; +COMMENT ON COLUMN system_operate_log.sub_type IS ''; +COMMENT ON COLUMN system_operate_log.biz_id IS 'ģ'; +COMMENT ON COLUMN system_operate_log.action IS ''; +COMMENT ON COLUMN system_operate_log.extra IS 'չֶ'; +COMMENT ON COLUMN system_operate_log.request_method IS '󷽷'; +COMMENT ON COLUMN system_operate_log.request_url IS 'ַ'; +COMMENT ON COLUMN system_operate_log.user_ip IS 'û IP'; +COMMENT ON COLUMN system_operate_log.user_agent IS ' UA'; +COMMENT ON COLUMN system_operate_log.creator IS ''; +COMMENT ON COLUMN system_operate_log.create_time IS 'ʱ'; +COMMENT ON COLUMN system_operate_log.updater IS ''; +COMMENT ON COLUMN system_operate_log.update_time IS 'ʱ'; +COMMENT ON COLUMN system_operate_log.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_operate_log.tenant_id IS '⻧'; +COMMENT ON TABLE system_operate_log IS '־¼ V2 汾'; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +CREATE TABLE system_post +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + code varchar(64) NOT NULL, + name varchar(50) NOT NULL, + sort int NOT NULL, + status smallint NOT NULL, + remark varchar(500) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_post.id IS 'λID'; +COMMENT ON COLUMN system_post.code IS 'λ'; +COMMENT ON COLUMN system_post.name IS 'λ'; +COMMENT ON COLUMN system_post.sort IS 'ʾ˳'; +COMMENT ON COLUMN system_post.status IS '״̬0 1ͣã'; +COMMENT ON COLUMN system_post.remark IS 'ע'; +COMMENT ON COLUMN system_post.creator IS ''; +COMMENT ON COLUMN system_post.create_time IS 'ʱ'; +COMMENT ON COLUMN system_post.updater IS ''; +COMMENT ON COLUMN system_post.update_time IS 'ʱ'; +COMMENT ON COLUMN system_post.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_post.tenant_id IS '⻧'; +COMMENT ON TABLE system_post IS 'λϢ'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_post ON; +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'ceo', '³', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', 'Ŀ', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', 'ͨԱ', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 10:04:37', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', 'Դ', 5, 0, '', '1', '2024-03-24 20:45:40', '1', '2024-03-24 20:45:40', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_post OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +CREATE TABLE system_role +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(30) NOT NULL, + code varchar(100) NOT NULL, + sort int NOT NULL, + data_scope smallint DEFAULT 1 NOT NULL, + data_scope_dept_ids varchar(500) DEFAULT '' NULL, + status smallint NOT NULL, + type smallint NOT NULL, + remark varchar(500) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_role.id IS 'ɫID'; +COMMENT ON COLUMN system_role.name IS 'ɫ'; +COMMENT ON COLUMN system_role.code IS 'ɫȨַ'; +COMMENT ON COLUMN system_role.sort IS 'ʾ˳'; +COMMENT ON COLUMN system_role.data_scope IS 'ݷΧ1ȫȨ 2ԶȨ 3Ȩ 4żȨޣ'; +COMMENT ON COLUMN system_role.data_scope_dept_ids IS 'ݷΧ(ָ)'; +COMMENT ON COLUMN system_role.status IS 'ɫ״̬0 1ͣã'; +COMMENT ON COLUMN system_role.type IS 'ɫ'; +COMMENT ON COLUMN system_role.remark IS 'ע'; +COMMENT ON COLUMN system_role.creator IS ''; +COMMENT ON COLUMN system_role.create_time IS 'ʱ'; +COMMENT ON COLUMN system_role.updater IS ''; +COMMENT ON COLUMN system_role.update_time IS 'ʱ'; +COMMENT ON COLUMN system_role.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_role.tenant_id IS '⻧'; +COMMENT ON TABLE system_role IS 'ɫϢ'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_role ON; +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'Ա', 'super_admin', 1, 1, '', 0, 1, 'Ա', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'ͨɫ', 'common', 2, 2, '', 0, 1, 'ͨɫ', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM Ա', 'crm_admin', 2, 1, '', 0, 1, 'CRM רɫ', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '˺', 'test', 0, 1, '[]', 0, 2, '', '', '2021-01-06 13:49:35', '1', '2024-03-24 22:22:45', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '⻧Ա', 'tenant_admin', 0, 1, '', 0, 1, 'ϵͳԶ', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '⻧Ա', 'tenant_admin', 0, 1, '', 0, 1, 'ϵͳԶ', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +COMMIT; +SET IDENTITY_INSERT system_role OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +CREATE TABLE system_role_menu +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + role_id bigint NOT NULL, + menu_id bigint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_role_menu.id IS ''; +COMMENT ON COLUMN system_role_menu.role_id IS 'ɫID'; +COMMENT ON COLUMN system_role_menu.menu_id IS '˵ID'; +COMMENT ON COLUMN system_role_menu.creator IS ''; +COMMENT ON COLUMN system_role_menu.create_time IS 'ʱ'; +COMMENT ON COLUMN system_role_menu.updater IS ''; +COMMENT ON COLUMN system_role_menu.update_time IS 'ʱ'; +COMMENT ON COLUMN system_role_menu.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_role_menu.tenant_id IS '⻧'; +COMMENT ON TABLE system_role_menu IS 'ɫͲ˵'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_role_menu ON; +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_role_menu OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +CREATE TABLE system_sms_channel +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + signature varchar(12) NOT NULL, + code varchar(63) NOT NULL, + status smallint NOT NULL, + remark varchar(255) DEFAULT NULL NULL, + api_key varchar(128) NOT NULL, + api_secret varchar(128) DEFAULT NULL NULL, + callback_url varchar(255) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_sms_channel.id IS ''; +COMMENT ON COLUMN system_sms_channel.signature IS 'ǩ'; +COMMENT ON COLUMN system_sms_channel.code IS ''; +COMMENT ON COLUMN system_sms_channel.status IS '״̬'; +COMMENT ON COLUMN system_sms_channel.remark IS 'ע'; +COMMENT ON COLUMN system_sms_channel.api_key IS ' API ˺'; +COMMENT ON COLUMN system_sms_channel.api_secret IS ' API Կ'; +COMMENT ON COLUMN system_sms_channel.callback_url IS 'ŷͻص URL'; +COMMENT ON COLUMN system_sms_channel.creator IS ''; +COMMENT ON COLUMN system_sms_channel.create_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_channel.updater IS ''; +COMMENT ON COLUMN system_sms_channel.update_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_channel.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_sms_channel IS ''; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_sms_channel ON; +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, 'ҪŶֻҿã', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2023-12-02 22:10:17', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, 'ʾ', 'DEBUG_DING_TALK', 0, '', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2023-12-02 22:10:08', '0'); +COMMIT; +SET IDENTITY_INSERT system_sms_channel OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +CREATE TABLE system_sms_code +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + mobile varchar(11) NOT NULL, + code varchar(6) NOT NULL, + create_ip varchar(15) NOT NULL, + scene smallint NOT NULL, + today_index smallint NOT NULL, + used smallint NOT NULL, + used_time datetime DEFAULT NULL NULL, + used_ip varchar(255) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile); + +COMMENT ON COLUMN system_sms_code.id IS ''; +COMMENT ON COLUMN system_sms_code.mobile IS 'ֻ'; +COMMENT ON COLUMN system_sms_code.code IS '֤'; +COMMENT ON COLUMN system_sms_code.create_ip IS ' IP'; +COMMENT ON COLUMN system_sms_code.scene IS 'ͳ'; +COMMENT ON COLUMN system_sms_code.today_index IS 'շ͵ĵڼ'; +COMMENT ON COLUMN system_sms_code.used IS 'Ƿʹ'; +COMMENT ON COLUMN system_sms_code.used_time IS 'ʹʱ'; +COMMENT ON COLUMN system_sms_code.used_ip IS 'ʹ IP'; +COMMENT ON COLUMN system_sms_code.creator IS ''; +COMMENT ON COLUMN system_sms_code.create_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_code.updater IS ''; +COMMENT ON COLUMN system_sms_code.update_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_code.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_sms_code.tenant_id IS '⻧'; +COMMENT ON TABLE system_sms_code IS 'ֻ֤'; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +CREATE TABLE system_sms_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + channel_id bigint NOT NULL, + channel_code varchar(63) NOT NULL, + template_id bigint NOT NULL, + template_code varchar(63) NOT NULL, + template_type smallint NOT NULL, + template_content varchar(255) NOT NULL, + template_params varchar(255) NOT NULL, + api_template_id varchar(63) NOT NULL, + mobile varchar(11) NOT NULL, + user_id bigint DEFAULT NULL NULL, + user_type smallint DEFAULT NULL NULL, + send_status smallint DEFAULT 0 NOT NULL, + send_time datetime DEFAULT NULL NULL, + api_send_code varchar(63) DEFAULT NULL NULL, + api_send_msg varchar(255) DEFAULT NULL NULL, + api_request_id varchar(255) DEFAULT NULL NULL, + api_serial_no varchar(255) DEFAULT NULL NULL, + receive_status smallint DEFAULT 0 NOT NULL, + receive_time datetime DEFAULT NULL NULL, + api_receive_code varchar(63) DEFAULT NULL NULL, + api_receive_msg varchar(255) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_sms_log.id IS ''; +COMMENT ON COLUMN system_sms_log.channel_id IS ''; +COMMENT ON COLUMN system_sms_log.channel_code IS ''; +COMMENT ON COLUMN system_sms_log.template_id IS 'ģ'; +COMMENT ON COLUMN system_sms_log.template_code IS 'ģ'; +COMMENT ON COLUMN system_sms_log.template_type IS ''; +COMMENT ON COLUMN system_sms_log.template_content IS ''; +COMMENT ON COLUMN system_sms_log.template_params IS 'Ų'; +COMMENT ON COLUMN system_sms_log.api_template_id IS ' API ģ'; +COMMENT ON COLUMN system_sms_log.mobile IS 'ֻ'; +COMMENT ON COLUMN system_sms_log.user_id IS 'û'; +COMMENT ON COLUMN system_sms_log.user_type IS 'û'; +COMMENT ON COLUMN system_sms_log.send_status IS '״̬'; +COMMENT ON COLUMN system_sms_log.send_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_log.api_send_code IS ' API ͽı'; +COMMENT ON COLUMN system_sms_log.api_send_msg IS ' API ʧܵʾ'; +COMMENT ON COLUMN system_sms_log.api_request_id IS ' API ͷصΨһ ID'; +COMMENT ON COLUMN system_sms_log.api_serial_no IS ' API ͷص'; +COMMENT ON COLUMN system_sms_log.receive_status IS '״̬'; +COMMENT ON COLUMN system_sms_log.receive_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API սı'; +COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API ս˵'; +COMMENT ON COLUMN system_sms_log.creator IS ''; +COMMENT ON COLUMN system_sms_log.create_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_log.updater IS ''; +COMMENT ON COLUMN system_sms_log.update_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_log.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_sms_log IS '־'; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +CREATE TABLE system_sms_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + type smallint NOT NULL, + status smallint NOT NULL, + code varchar(63) NOT NULL, + name varchar(63) NOT NULL, + content varchar(255) NOT NULL, + params varchar(255) NOT NULL, + remark varchar(255) DEFAULT NULL NULL, + api_template_id varchar(63) NOT NULL, + channel_id bigint NOT NULL, + channel_code varchar(63) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_sms_template.id IS ''; +COMMENT ON COLUMN system_sms_template.type IS 'ģ'; +COMMENT ON COLUMN system_sms_template.status IS '״̬'; +COMMENT ON COLUMN system_sms_template.code IS 'ģ'; +COMMENT ON COLUMN system_sms_template.name IS 'ģ'; +COMMENT ON COLUMN system_sms_template.content IS 'ģ'; +COMMENT ON COLUMN system_sms_template.params IS ''; +COMMENT ON COLUMN system_sms_template.remark IS 'ע'; +COMMENT ON COLUMN system_sms_template.api_template_id IS ' API ģ'; +COMMENT ON COLUMN system_sms_template.channel_id IS ''; +COMMENT ON COLUMN system_sms_template.channel_code IS ''; +COMMENT ON COLUMN system_sms_template.creator IS ''; +COMMENT ON COLUMN system_sms_template.create_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_template.updater IS ''; +COMMENT ON COLUMN system_sms_template.update_time IS 'ʱ'; +COMMENT ON COLUMN system_sms_template.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_sms_template IS 'ģ'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_sms_template ON; +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '֤', 'ڽе¼{operation}֤{code}', '["operation","code"]', 'Աע', '4383920', 6, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2023-12-02 22:32:47', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '֪ͨ', '֤{code}֤5Чй©ˣ', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', 'ģ', ' {name}', '["name"]', 'f', '4383920', 6, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2022-12-10 21:26:09', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '', 'ϼ{name}ţ{code}', '["name","code"]', '', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', 'ǰ̨ûŵ¼', '֤{code}', '["code"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2022-12-10 21:25:59', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '񱻷', 'յһµĴ{processInstanceName}-{taskName}ˣ{startUserNickname}ӣ{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '̱ͨ', '̱ͨ{processInstanceName}ԭ{reason}鿴ӣ{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '̱ͨ', '̱ͨ{processInstanceName}鿴ӣ{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', 'ʾģ', 'ҾDzһ', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2023-03-24 23:45:07', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', 'Աû - ޸ֻ', '֤{code}֤ 5 Чй©ˣ', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', 'Աû - ޸', '֤{code}֤ 5 Чй©ˣ', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', 'Աû - ', '֤{code}֤ 5 Чй©ˣ', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', '0'); +COMMIT; +SET IDENTITY_INSERT system_sms_template OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +CREATE TABLE system_social_client +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(255) NOT NULL, + social_type smallint NOT NULL, + user_type smallint NOT NULL, + client_id varchar(255) NOT NULL, + client_secret varchar(255) NOT NULL, + agent_id varchar(255) DEFAULT NULL NULL, + status smallint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_social_client.id IS ''; +COMMENT ON COLUMN system_social_client.name IS 'Ӧ'; +COMMENT ON COLUMN system_social_client.social_type IS '罻ƽ̨'; +COMMENT ON COLUMN system_social_client.user_type IS 'û'; +COMMENT ON COLUMN system_social_client.client_id IS 'ͻ˱'; +COMMENT ON COLUMN system_social_client.client_secret IS 'ͻԿ'; +COMMENT ON COLUMN system_social_client.agent_id IS ''; +COMMENT ON COLUMN system_social_client.status IS '״̬'; +COMMENT ON COLUMN system_social_client.creator IS ''; +COMMENT ON COLUMN system_social_client.create_time IS 'ʱ'; +COMMENT ON COLUMN system_social_client.updater IS ''; +COMMENT ON COLUMN system_social_client.update_time IS 'ʱ'; +COMMENT ON COLUMN system_social_client.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_social_client.tenant_id IS '⻧'; +COMMENT ON TABLE system_social_client IS '罻ͻ˱'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_social_client ON; +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', '1', 121); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '΢Źں', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '΢С', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', '1', 1); +COMMIT; +SET IDENTITY_INSERT system_social_client OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +CREATE TABLE system_social_user +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + type smallint NOT NULL, + openid varchar(32) NOT NULL, + token varchar(256) DEFAULT NULL NULL, + raw_token_info varchar(1024) NOT NULL, + nickname varchar(32) NOT NULL, + avatar varchar(255) DEFAULT NULL NULL, + raw_user_info varchar(1024) NOT NULL, + code varchar(256) NOT NULL, + state varchar(256) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_social_user.id IS '()'; +COMMENT ON COLUMN system_social_user.type IS '罻ƽ̨'; +COMMENT ON COLUMN system_social_user.openid IS '罻 openid'; +COMMENT ON COLUMN system_social_user.token IS '罻 token'; +COMMENT ON COLUMN system_social_user.raw_token_info IS 'ԭʼ Token ݣһ JSON ʽ'; +COMMENT ON COLUMN system_social_user.nickname IS 'ûdz'; +COMMENT ON COLUMN system_social_user.avatar IS 'ûͷ'; +COMMENT ON COLUMN system_social_user.raw_user_info IS 'ԭʼûݣһ JSON ʽ'; +COMMENT ON COLUMN system_social_user.code IS 'һε֤ code'; +COMMENT ON COLUMN system_social_user.state IS 'һε֤ state'; +COMMENT ON COLUMN system_social_user.creator IS ''; +COMMENT ON COLUMN system_social_user.create_time IS 'ʱ'; +COMMENT ON COLUMN system_social_user.updater IS ''; +COMMENT ON COLUMN system_social_user.update_time IS 'ʱ'; +COMMENT ON COLUMN system_social_user.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_social_user.tenant_id IS '⻧'; +COMMENT ON TABLE system_social_user IS '罻û'; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +CREATE TABLE system_social_user_bind +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type smallint NOT NULL, + social_type smallint NOT NULL, + social_user_id bigint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_social_user_bind.id IS '()'; +COMMENT ON COLUMN system_social_user_bind.user_id IS 'û'; +COMMENT ON COLUMN system_social_user_bind.user_type IS 'û'; +COMMENT ON COLUMN system_social_user_bind.social_type IS '罻ƽ̨'; +COMMENT ON COLUMN system_social_user_bind.social_user_id IS '罻ûı'; +COMMENT ON COLUMN system_social_user_bind.creator IS ''; +COMMENT ON COLUMN system_social_user_bind.create_time IS 'ʱ'; +COMMENT ON COLUMN system_social_user_bind.updater IS ''; +COMMENT ON COLUMN system_social_user_bind.update_time IS 'ʱ'; +COMMENT ON COLUMN system_social_user_bind.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_social_user_bind.tenant_id IS '⻧'; +COMMENT ON TABLE system_social_user_bind IS '罻󶨱'; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +CREATE TABLE system_tenant +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(30) NOT NULL, + contact_user_id bigint DEFAULT NULL NULL, + contact_name varchar(30) NOT NULL, + contact_mobile varchar(500) DEFAULT NULL NULL, + status smallint DEFAULT 0 NOT NULL, + website varchar(256) DEFAULT '' NULL, + package_id bigint NOT NULL, + expire_time datetime NOT NULL, + account_count int NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_tenant.id IS '⻧'; +COMMENT ON COLUMN system_tenant.name IS '⻧'; +COMMENT ON COLUMN system_tenant.contact_user_id IS 'ϵ˵û'; +COMMENT ON COLUMN system_tenant.contact_name IS 'ϵ'; +COMMENT ON COLUMN system_tenant.contact_mobile IS 'ϵֻ'; +COMMENT ON COLUMN system_tenant.status IS '⻧״̬0 1ͣã'; +COMMENT ON COLUMN system_tenant.website IS ''; +COMMENT ON COLUMN system_tenant.package_id IS '⻧ײͱ'; +COMMENT ON COLUMN system_tenant.expire_time IS 'ʱ'; +COMMENT ON COLUMN system_tenant.account_count IS '˺'; +COMMENT ON COLUMN system_tenant.creator IS ''; +COMMENT ON COLUMN system_tenant.create_time IS 'ʱ'; +COMMENT ON COLUMN system_tenant.updater IS ''; +COMMENT ON COLUMN system_tenant.update_time IS 'ʱ'; +COMMENT ON COLUMN system_tenant.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_tenant IS '⻧'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_tenant ON; +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, 'Դ', NULL, 'ܵ', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, 'С⻧', 110, 'С2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '⻧', 113, '', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', '0'); +COMMIT; +SET IDENTITY_INSERT system_tenant OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +CREATE TABLE system_tenant_package +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(30) NOT NULL, + status smallint DEFAULT 0 NOT NULL, + remark varchar(256) DEFAULT '' NULL, + menu_ids varchar(4096) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL +); + +COMMENT ON COLUMN system_tenant_package.id IS 'ײͱ'; +COMMENT ON COLUMN system_tenant_package.name IS 'ײ'; +COMMENT ON COLUMN system_tenant_package.status IS '⻧״̬0 1ͣã'; +COMMENT ON COLUMN system_tenant_package.remark IS 'ע'; +COMMENT ON COLUMN system_tenant_package.menu_ids IS 'IJ˵'; +COMMENT ON COLUMN system_tenant_package.creator IS ''; +COMMENT ON COLUMN system_tenant_package.create_time IS 'ʱ'; +COMMENT ON COLUMN system_tenant_package.updater IS ''; +COMMENT ON COLUMN system_tenant_package.update_time IS 'ʱ'; +COMMENT ON COLUMN system_tenant_package.deleted IS 'Ƿɾ'; +COMMENT ON TABLE system_tenant_package IS '⻧ײͱ'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_tenant_package ON; +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, 'ͨײ', 0, 'С', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-03-30 17:53:17', '0'); +COMMIT; +SET IDENTITY_INSERT system_tenant_package OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +CREATE TABLE system_user_post +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint DEFAULT 0 NOT NULL, + post_id bigint DEFAULT 0 NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_user_post.id IS 'id'; +COMMENT ON COLUMN system_user_post.user_id IS 'ûID'; +COMMENT ON COLUMN system_user_post.post_id IS 'λID'; +COMMENT ON COLUMN system_user_post.creator IS ''; +COMMENT ON COLUMN system_user_post.create_time IS 'ʱ'; +COMMENT ON COLUMN system_user_post.updater IS ''; +COMMENT ON COLUMN system_user_post.update_time IS 'ʱ'; +COMMENT ON COLUMN system_user_post.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_user_post.tenant_id IS '⻧'; +COMMENT ON TABLE system_user_post IS 'ûλ'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_user_post ON; +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_user_post OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +CREATE TABLE system_user_role +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + role_id bigint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NULL, + deleted bit DEFAULT '0' NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_user_role.id IS ''; +COMMENT ON COLUMN system_user_role.user_id IS 'ûID'; +COMMENT ON COLUMN system_user_role.role_id IS 'ɫID'; +COMMENT ON COLUMN system_user_role.creator IS ''; +COMMENT ON COLUMN system_user_role.create_time IS 'ʱ'; +COMMENT ON COLUMN system_user_role.updater IS ''; +COMMENT ON COLUMN system_user_role.update_time IS 'ʱ'; +COMMENT ON COLUMN system_user_role.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_user_role.tenant_id IS '⻧'; +COMMENT ON TABLE system_user_role IS 'ûͽɫ'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_user_role ON; +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_user_role OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +CREATE TABLE system_users +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + username varchar(30) NOT NULL, + password varchar(100) DEFAULT '' NULL, + nickname varchar(30) NOT NULL, + remark varchar(500) DEFAULT NULL NULL, + dept_id bigint DEFAULT NULL NULL, + post_ids varchar(255) DEFAULT NULL NULL, + email varchar(50) DEFAULT '' NULL, + mobile varchar(11) DEFAULT '' NULL, + sex smallint DEFAULT 0 NULL, + avatar varchar(512) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + login_ip varchar(50) DEFAULT '' NULL, + login_date datetime DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN system_users.id IS 'ûID'; +COMMENT ON COLUMN system_users.username IS 'û˺'; +COMMENT ON COLUMN system_users.password IS ''; +COMMENT ON COLUMN system_users.nickname IS 'ûdz'; +COMMENT ON COLUMN system_users.remark IS 'ע'; +COMMENT ON COLUMN system_users.dept_id IS 'ID'; +COMMENT ON COLUMN system_users.post_ids IS 'λ'; +COMMENT ON COLUMN system_users.email IS 'û'; +COMMENT ON COLUMN system_users.mobile IS 'ֻ'; +COMMENT ON COLUMN system_users.sex IS 'ûԱ'; +COMMENT ON COLUMN system_users.avatar IS 'ͷַ'; +COMMENT ON COLUMN system_users.status IS 'ʺ״̬0 1ͣã'; +COMMENT ON COLUMN system_users.login_ip IS '¼IP'; +COMMENT ON COLUMN system_users.login_date IS '¼ʱ'; +COMMENT ON COLUMN system_users.creator IS ''; +COMMENT ON COLUMN system_users.create_time IS 'ʱ'; +COMMENT ON COLUMN system_users.updater IS ''; +COMMENT ON COLUMN system_users.update_time IS 'ʱ'; +COMMENT ON COLUMN system_users.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN system_users.tenant_id IS '⻧'; +COMMENT ON TABLE system_users IS 'ûϢ'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT system_users ON; +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', 'Դ', 'Ա', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '', 'Ҫ', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', 'Դ', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', 'Ժ', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', 'ܵ', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', '0', 118); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', 'ܵ', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', '0', 119); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', 'ܵ', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', '0', 120); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', 'С', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', 'û', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '¶', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', '0', 122); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr С', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', 'Ժ', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', 'Ǻ', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', '0', 1); +COMMIT; +SET IDENTITY_INSERT system_users OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +CREATE TABLE yudao_demo01_contact +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(100) DEFAULT '' NULL, + sex smallint NOT NULL, + birthday datetime NOT NULL, + description varchar(255) NOT NULL, + avatar varchar(512) DEFAULT NULL NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN yudao_demo01_contact.id IS ''; +COMMENT ON COLUMN yudao_demo01_contact.name IS ''; +COMMENT ON COLUMN yudao_demo01_contact.sex IS 'Ա'; +COMMENT ON COLUMN yudao_demo01_contact.birthday IS ''; +COMMENT ON COLUMN yudao_demo01_contact.description IS ''; +COMMENT ON COLUMN yudao_demo01_contact.avatar IS 'ͷ'; +COMMENT ON COLUMN yudao_demo01_contact.creator IS ''; +COMMENT ON COLUMN yudao_demo01_contact.create_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo01_contact.updater IS ''; +COMMENT ON COLUMN yudao_demo01_contact.update_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo01_contact.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '⻧'; +COMMENT ON TABLE yudao_demo01_contact IS 'ʾϵ˱'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT yudao_demo01_contact ON; +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '', 2, '2023-11-07 00:00:00', '

ѽ

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', '0', 1); +COMMIT; +SET IDENTITY_INSERT yudao_demo01_contact OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +CREATE TABLE yudao_demo02_category +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(100) DEFAULT '' NULL, + parent_id bigint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN yudao_demo02_category.id IS ''; +COMMENT ON COLUMN yudao_demo02_category.name IS ''; +COMMENT ON COLUMN yudao_demo02_category.parent_id IS ''; +COMMENT ON COLUMN yudao_demo02_category.creator IS ''; +COMMENT ON COLUMN yudao_demo02_category.create_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo02_category.updater IS ''; +COMMENT ON COLUMN yudao_demo02_category.update_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo02_category.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '⻧'; +COMMENT ON TABLE yudao_demo02_category IS 'ʾ'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT yudao_demo02_category ON; +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'ֹ', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'С', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', '0', 1); +COMMIT; +SET IDENTITY_INSERT yudao_demo02_category OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +CREATE TABLE yudao_demo03_course +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + student_id bigint NOT NULL, + name varchar(100) DEFAULT '' NULL, + score smallint NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN yudao_demo03_course.id IS ''; +COMMENT ON COLUMN yudao_demo03_course.student_id IS 'ѧ'; +COMMENT ON COLUMN yudao_demo03_course.name IS ''; +COMMENT ON COLUMN yudao_demo03_course.score IS ''; +COMMENT ON COLUMN yudao_demo03_course.creator IS ''; +COMMENT ON COLUMN yudao_demo03_course.create_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_course.updater IS ''; +COMMENT ON COLUMN yudao_demo03_course.update_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_course.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '⻧'; +COMMENT ON TABLE yudao_demo03_course IS 'ѧγ̱'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT yudao_demo03_course ON; +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, 'ѧ', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, 'ѩ', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', '0', 1); +COMMIT; +SET IDENTITY_INSERT yudao_demo03_course OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +CREATE TABLE yudao_demo03_grade +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + student_id bigint NOT NULL, + name varchar(100) DEFAULT '' NULL, + teacher varchar(255) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN yudao_demo03_grade.id IS ''; +COMMENT ON COLUMN yudao_demo03_grade.student_id IS 'ѧ'; +COMMENT ON COLUMN yudao_demo03_grade.name IS ''; +COMMENT ON COLUMN yudao_demo03_grade.teacher IS ''; +COMMENT ON COLUMN yudao_demo03_grade.creator IS ''; +COMMENT ON COLUMN yudao_demo03_grade.create_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_grade.updater IS ''; +COMMENT ON COLUMN yudao_demo03_grade.update_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_grade.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '⻧'; +COMMENT ON TABLE yudao_demo03_grade IS 'ѧ༶'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT yudao_demo03_grade ON; +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, ' 2 ', 'ܽ', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, 'Ϊ', 'ңң', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, 'Сͼ', 'С111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', '0', 1); +COMMIT; +SET IDENTITY_INSERT yudao_demo03_grade OFF; +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +CREATE TABLE yudao_demo03_student +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name varchar(100) DEFAULT '' NULL, + sex smallint NOT NULL, + birthday datetime NOT NULL, + description varchar(255) NOT NULL, + creator varchar(64) DEFAULT '' NULL, + create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar(64) DEFAULT '' NULL, + update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT '0' NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +); + +COMMENT ON COLUMN yudao_demo03_student.id IS ''; +COMMENT ON COLUMN yudao_demo03_student.name IS ''; +COMMENT ON COLUMN yudao_demo03_student.sex IS 'Ա'; +COMMENT ON COLUMN yudao_demo03_student.birthday IS ''; +COMMENT ON COLUMN yudao_demo03_student.description IS ''; +COMMENT ON COLUMN yudao_demo03_student.creator IS ''; +COMMENT ON COLUMN yudao_demo03_student.create_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_student.updater IS ''; +COMMENT ON COLUMN yudao_demo03_student.update_time IS 'ʱ'; +COMMENT ON COLUMN yudao_demo03_student.deleted IS 'Ƿɾ'; +COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '⻧'; +COMMENT ON TABLE yudao_demo03_student IS 'ѧ'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT yudao_demo03_student ON; +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'С', 1, '2023-11-16 00:00:00', '

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '', 2, '2023-11-13 00:00:00', '

ڽ?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 'С', 1, '2023-11-07 00:00:00', '

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', '0', 1); +COMMIT; +SET IDENTITY_INSERT yudao_demo03_student OFF; +-- @formatter:on + diff --git a/ruoyi-vue-pro-master/sql/kingbase/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/kingbase/ruoyi-vue-pro.sql new file mode 100644 index 0000000..37f3b9b --- /dev/null +++ b/ruoyi-vue-pro-master/sql/kingbase/ruoyi-vue-pro.sql @@ -0,0 +1,4723 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : Kingbase + + Date: 2024-05-31 22:42:53 +*/ + + +-- ---------------------------- +-- Table structure for dual +-- ---------------------------- +DROP TABLE IF EXISTS dual; +CREATE TABLE dual +( + id int2 +); + +COMMENT ON TABLE dual IS '数据库连接的表'; + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1); +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_access_log; +CREATE TABLE infra_api_access_log +( + id int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NULL DEFAULT '', + request_url varchar(255) NULL DEFAULT '', + request_params text NULL, + response_body text NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + operate_module varchar(50) NULL DEFAULT NULL, + operate_name varchar(50) NULL DEFAULT NULL, + operate_type int2 NULL DEFAULT 0, + begin_time timestamp NOT NULL, + end_time timestamp NOT NULL, + duration int4 NOT NULL, + result_code int4 NOT NULL DEFAULT 0, + result_msg varchar(512) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_access_log + ADD CONSTRAINT pk_infra_api_access_log PRIMARY KEY (id); + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time); + +COMMENT ON COLUMN infra_api_access_log.id IS '日志主键'; +COMMENT ON COLUMN infra_api_access_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN infra_api_access_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_access_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_access_log.application_name IS '应用名'; +COMMENT ON COLUMN infra_api_access_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_access_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_access_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_access_log.response_body IS '响应结果'; +COMMENT ON COLUMN infra_api_access_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_access_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_access_log.operate_module IS '操作模块'; +COMMENT ON COLUMN infra_api_access_log.operate_name IS '操作名'; +COMMENT ON COLUMN infra_api_access_log.operate_type IS '操作分类'; +COMMENT ON COLUMN infra_api_access_log.begin_time IS '开始请求时间'; +COMMENT ON COLUMN infra_api_access_log.end_time IS '结束请求时间'; +COMMENT ON COLUMN infra_api_access_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_api_access_log.result_code IS '结果码'; +COMMENT ON COLUMN infra_api_access_log.result_msg IS '结果提示'; +COMMENT ON COLUMN infra_api_access_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_access_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_access_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_access_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_access_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_access_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_access_log IS 'API 访问日志表'; + +DROP SEQUENCE IF EXISTS infra_api_access_log_seq; +CREATE SEQUENCE infra_api_access_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_error_log; +CREATE TABLE infra_api_error_log +( + id int4 NOT NULL, + trace_id varchar(64) NOT NULL, + user_id int4 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NOT NULL, + request_url varchar(255) NOT NULL, + request_params varchar(8000) NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + exception_time timestamp NOT NULL, + exception_name varchar(128) NULL DEFAULT '', + exception_message text NOT NULL, + exception_root_cause_message text NOT NULL, + exception_stack_trace text NOT NULL, + exception_class_name varchar(512) NOT NULL, + exception_file_name varchar(512) NOT NULL, + exception_method_name varchar(512) NOT NULL, + exception_line_number int4 NOT NULL, + process_status int2 NOT NULL, + process_time timestamp NULL DEFAULT NULL, + process_user_id int4 NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_error_log + ADD CONSTRAINT pk_infra_api_error_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_api_error_log.id IS '编号'; +COMMENT ON COLUMN infra_api_error_log.trace_id IS '链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。'; +COMMENT ON COLUMN infra_api_error_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_error_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_error_log.application_name IS '应用名 + * + * 目前读取 spring.application.name'; +COMMENT ON COLUMN infra_api_error_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_error_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_error_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_error_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_error_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_error_log.exception_time IS '异常发生时间'; +COMMENT ON COLUMN infra_api_error_log.exception_name IS '异常名 + * + * {@link Throwable#getClass()} 的类全名'; +COMMENT ON COLUMN infra_api_error_log.exception_message IS '异常导致的消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '异常导致的根消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '异常的栈轨迹 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}'; +COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '异常发生的类全名 + * + * {@link StackTraceElement#getClassName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '异常发生的类文件 + * + * {@link StackTraceElement#getFileName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()}'; +COMMENT ON COLUMN infra_api_error_log.process_status IS '处理状态'; +COMMENT ON COLUMN infra_api_error_log.process_time IS '处理时间'; +COMMENT ON COLUMN infra_api_error_log.process_user_id IS '处理用户编号'; +COMMENT ON COLUMN infra_api_error_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_error_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_error_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_error_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_error_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_error_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_error_log IS '系统异常日志'; + +DROP SEQUENCE IF EXISTS infra_api_error_log_seq; +CREATE SEQUENCE infra_api_error_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_column; +CREATE TABLE infra_codegen_column +( + id int8 NOT NULL, + table_id int8 NOT NULL, + column_name varchar(200) NOT NULL, + data_type varchar(100) NOT NULL, + column_comment varchar(500) NOT NULL, + nullable bool NOT NULL, + primary_key bool NOT NULL, + ordinal_position int4 NOT NULL, + java_type varchar(32) NOT NULL, + java_field varchar(64) NOT NULL, + dict_type varchar(200) NULL DEFAULT '', + example varchar(64) NULL DEFAULT NULL, + create_operation bool NOT NULL, + update_operation bool NOT NULL, + list_operation bool NOT NULL, + list_operation_condition varchar(32) NOT NULL DEFAULT '=', + list_operation_result bool NOT NULL, + html_type varchar(32) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_column + ADD CONSTRAINT pk_infra_codegen_column PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_column.id IS '编号'; +COMMENT ON COLUMN infra_codegen_column.table_id IS '表编号'; +COMMENT ON COLUMN infra_codegen_column.column_name IS '字段名'; +COMMENT ON COLUMN infra_codegen_column.data_type IS '字段类型'; +COMMENT ON COLUMN infra_codegen_column.column_comment IS '字段描述'; +COMMENT ON COLUMN infra_codegen_column.nullable IS '是否允许为空'; +COMMENT ON COLUMN infra_codegen_column.primary_key IS '是否主键'; +COMMENT ON COLUMN infra_codegen_column.ordinal_position IS '排序'; +COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java 属性类型'; +COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java 属性名'; +COMMENT ON COLUMN infra_codegen_column.dict_type IS '字典类型'; +COMMENT ON COLUMN infra_codegen_column.example IS '数据示例'; +COMMENT ON COLUMN infra_codegen_column.create_operation IS '是否为 Create 创建操作的字段'; +COMMENT ON COLUMN infra_codegen_column.update_operation IS '是否为 Update 更新操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation IS '是否为 List 查询操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List 查询操作的条件类型'; +COMMENT ON COLUMN infra_codegen_column.list_operation_result IS '是否为 List 查询操作的返回字段'; +COMMENT ON COLUMN infra_codegen_column.html_type IS '显示类型'; +COMMENT ON COLUMN infra_codegen_column.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_column.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_column.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_column.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_column.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_column IS '代码生成表字段定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_column_seq; +CREATE SEQUENCE infra_codegen_column_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_table; +CREATE TABLE infra_codegen_table +( + id int8 NOT NULL, + data_source_config_id int8 NOT NULL, + scene int2 NOT NULL DEFAULT 1, + table_name varchar(200) NULL DEFAULT '', + table_comment varchar(500) NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + module_name varchar(30) NOT NULL, + business_name varchar(30) NOT NULL, + class_name varchar(100) NULL DEFAULT '', + class_comment varchar(50) NOT NULL, + author varchar(50) NOT NULL, + template_type int2 NOT NULL DEFAULT 1, + front_type int2 NOT NULL, + parent_menu_id int8 NULL DEFAULT NULL, + master_table_id int8 NULL DEFAULT NULL, + sub_join_column_id int8 NULL DEFAULT NULL, + sub_join_many bool NULL DEFAULT NULL, + tree_parent_column_id int8 NULL DEFAULT NULL, + tree_name_column_id int8 NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_table + ADD CONSTRAINT pk_infra_codegen_table PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_table.id IS '编号'; +COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS '数据源配置的编号'; +COMMENT ON COLUMN infra_codegen_table.scene IS '生成场景'; +COMMENT ON COLUMN infra_codegen_table.table_name IS '表名称'; +COMMENT ON COLUMN infra_codegen_table.table_comment IS '表描述'; +COMMENT ON COLUMN infra_codegen_table.remark IS '备注'; +COMMENT ON COLUMN infra_codegen_table.module_name IS '模块名'; +COMMENT ON COLUMN infra_codegen_table.business_name IS '业务名'; +COMMENT ON COLUMN infra_codegen_table.class_name IS '类名称'; +COMMENT ON COLUMN infra_codegen_table.class_comment IS '类描述'; +COMMENT ON COLUMN infra_codegen_table.author IS '作者'; +COMMENT ON COLUMN infra_codegen_table.template_type IS '模板类型'; +COMMENT ON COLUMN infra_codegen_table.front_type IS '前端类型'; +COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '父菜单编号'; +COMMENT ON COLUMN infra_codegen_table.master_table_id IS '主表的编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS '子表关联主表的字段编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_many IS '主表与子表是否一对多'; +COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS '树表的父字段编号'; +COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS '树表的名字字段编号'; +COMMENT ON COLUMN infra_codegen_table.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_table.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_table.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_table.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_table.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_table IS '代码生成表定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_table_seq; +CREATE SEQUENCE infra_codegen_table_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_config; +CREATE TABLE infra_config +( + id int4 NOT NULL, + category varchar(50) NOT NULL, + type int2 NOT NULL, + name varchar(100) NULL DEFAULT '', + config_key varchar(100) NULL DEFAULT '', + value varchar(500) NULL DEFAULT '', + visible bool NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_config + ADD CONSTRAINT pk_infra_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_config.id IS '参数主键'; +COMMENT ON COLUMN infra_config.category IS '参数分组'; +COMMENT ON COLUMN infra_config.type IS '参数类型'; +COMMENT ON COLUMN infra_config.name IS '参数名称'; +COMMENT ON COLUMN infra_config.config_key IS '参数键名'; +COMMENT ON COLUMN infra_config.value IS '参数键值'; +COMMENT ON COLUMN infra_config.visible IS '是否可见'; +COMMENT ON COLUMN infra_config.remark IS '备注'; +COMMENT ON COLUMN infra_config.creator IS '创建者'; +COMMENT ON COLUMN infra_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_config.updater IS '更新者'; +COMMENT ON COLUMN infra_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_config IS '参数配置表'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, '用户管理-账号初始密码', 'sys.user.init-password', '123456', '0', '初始化密码 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-04-03 17:22:28', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL 监控的地址', 'url.druid', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking 监控的地址', 'url.skywalking', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin 监控的地址', 'url.spring-boot-admin', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger 接口文档的地址', 'url.swagger', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, 'ui', 2, '腾讯地图 key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', '1', '腾讯地图 key', '1', '2023-06-03 19:16:27', '1', '2023-06-03 19:16:27', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', '2023-12-03 09:55:16', '1', '2023-12-03 09:55:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_config_seq; +CREATE SEQUENCE infra_config_seq + START 13; + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_data_source_config; +CREATE TABLE infra_data_source_config +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + url varchar(1024) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_data_source_config + ADD CONSTRAINT pk_infra_data_source_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_data_source_config.id IS '主键编号'; +COMMENT ON COLUMN infra_data_source_config.name IS '参数名称'; +COMMENT ON COLUMN infra_data_source_config.url IS '数据源连接'; +COMMENT ON COLUMN infra_data_source_config.username IS '用户名'; +COMMENT ON COLUMN infra_data_source_config.password IS '密码'; +COMMENT ON COLUMN infra_data_source_config.creator IS '创建者'; +COMMENT ON COLUMN infra_data_source_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_data_source_config.updater IS '更新者'; +COMMENT ON COLUMN infra_data_source_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_data_source_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_data_source_config IS '数据源配置表'; + +DROP SEQUENCE IF EXISTS infra_data_source_config_seq; +CREATE SEQUENCE infra_data_source_config_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +DROP TABLE IF EXISTS infra_file; +CREATE TABLE infra_file +( + id int8 NOT NULL, + config_id int8 NULL DEFAULT NULL, + name varchar(256) NULL DEFAULT NULL, + path varchar(512) NOT NULL, + url varchar(1024) NOT NULL, + type varchar(128) NULL DEFAULT NULL, + size int4 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file + ADD CONSTRAINT pk_infra_file PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file.id IS '文件编号'; +COMMENT ON COLUMN infra_file.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file.name IS '文件名'; +COMMENT ON COLUMN infra_file.path IS '文件路径'; +COMMENT ON COLUMN infra_file.url IS '文件 URL'; +COMMENT ON COLUMN infra_file.type IS '文件类型'; +COMMENT ON COLUMN infra_file.size IS '文件大小'; +COMMENT ON COLUMN infra_file.creator IS '创建者'; +COMMENT ON COLUMN infra_file.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file.updater IS '更新者'; +COMMENT ON COLUMN infra_file.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file.deleted IS '是否删除'; +COMMENT ON TABLE infra_file IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_seq; +CREATE SEQUENCE infra_file_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_config; +CREATE TABLE infra_file_config +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + storage int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + master bool NOT NULL, + config varchar(4096) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_config + ADD CONSTRAINT pk_infra_file_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_config.id IS '编号'; +COMMENT ON COLUMN infra_file_config.name IS '配置名'; +COMMENT ON COLUMN infra_file_config.storage IS '存储器'; +COMMENT ON COLUMN infra_file_config.remark IS '备注'; +COMMENT ON COLUMN infra_file_config.master IS '是否为主配置'; +COMMENT ON COLUMN infra_file_config.config IS '存储配置'; +COMMENT ON COLUMN infra_file_config.creator IS '创建者'; +COMMENT ON COLUMN infra_file_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_config.updater IS '更新者'; +COMMENT ON COLUMN infra_file_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_config IS '文件配置表'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_file_config_seq; +CREATE SEQUENCE infra_file_config_seq + START 23; + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_content; +CREATE TABLE infra_file_content +( + id int8 NOT NULL, + config_id int8 NOT NULL, + path varchar(512) NOT NULL, + content bytea NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_content + ADD CONSTRAINT pk_infra_file_content PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_content.id IS '编号'; +COMMENT ON COLUMN infra_file_content.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file_content.path IS '文件路径'; +COMMENT ON COLUMN infra_file_content.content IS '文件内容'; +COMMENT ON COLUMN infra_file_content.creator IS '创建者'; +COMMENT ON COLUMN infra_file_content.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_content.updater IS '更新者'; +COMMENT ON COLUMN infra_file_content.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_content.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_content IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_content_seq; +CREATE SEQUENCE infra_file_content_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +DROP TABLE IF EXISTS infra_job; +CREATE TABLE infra_job +( + id int8 NOT NULL, + name varchar(32) NOT NULL, + status int2 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + cron_expression varchar(32) NOT NULL, + retry_count int4 NOT NULL DEFAULT 0, + retry_interval int4 NOT NULL DEFAULT 0, + monitor_timeout int4 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job + ADD CONSTRAINT pk_infra_job PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job.id IS '任务编号'; +COMMENT ON COLUMN infra_job.name IS '任务名称'; +COMMENT ON COLUMN infra_job.status IS '任务状态'; +COMMENT ON COLUMN infra_job.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job.cron_expression IS 'CRON 表达式'; +COMMENT ON COLUMN infra_job.retry_count IS '重试次数'; +COMMENT ON COLUMN infra_job.retry_interval IS '重试间隔'; +COMMENT ON COLUMN infra_job.monitor_timeout IS '监控超时时间'; +COMMENT ON COLUMN infra_job.creator IS '创建者'; +COMMENT ON COLUMN infra_job.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job.updater IS '更新者'; +COMMENT ON COLUMN infra_job.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job.deleted IS '是否删除'; +COMMENT ON TABLE infra_job IS '定时任务表'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_job_seq; +CREATE SEQUENCE infra_job_seq + START 28; + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_job_log; +CREATE TABLE infra_job_log +( + id int8 NOT NULL, + job_id int8 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + execute_index int2 NOT NULL DEFAULT 1, + begin_time timestamp NOT NULL, + end_time timestamp NULL DEFAULT NULL, + duration int4 NULL DEFAULT NULL, + status int2 NOT NULL, + result varchar(4000) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job_log + ADD CONSTRAINT pk_infra_job_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job_log.id IS '日志编号'; +COMMENT ON COLUMN infra_job_log.job_id IS '任务编号'; +COMMENT ON COLUMN infra_job_log.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job_log.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job_log.execute_index IS '第几次执行'; +COMMENT ON COLUMN infra_job_log.begin_time IS '开始执行时间'; +COMMENT ON COLUMN infra_job_log.end_time IS '结束执行时间'; +COMMENT ON COLUMN infra_job_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_job_log.status IS '任务状态'; +COMMENT ON COLUMN infra_job_log.result IS '结果数据'; +COMMENT ON COLUMN infra_job_log.creator IS '创建者'; +COMMENT ON COLUMN infra_job_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job_log.updater IS '更新者'; +COMMENT ON COLUMN infra_job_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job_log.deleted IS '是否删除'; +COMMENT ON TABLE infra_job_log IS '定时任务日志表'; + +DROP SEQUENCE IF EXISTS infra_job_log_seq; +CREATE SEQUENCE infra_job_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +DROP TABLE IF EXISTS system_dept; +CREATE TABLE system_dept +( + id int8 NOT NULL, + name varchar(30) NULL DEFAULT '', + parent_id int8 NOT NULL DEFAULT 0, + sort int4 NOT NULL DEFAULT 0, + leader_user_id int8 NULL DEFAULT NULL, + phone varchar(11) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dept + ADD CONSTRAINT pk_system_dept PRIMARY KEY (id); + +COMMENT ON COLUMN system_dept.id IS '部门id'; +COMMENT ON COLUMN system_dept.name IS '部门名称'; +COMMENT ON COLUMN system_dept.parent_id IS '父部门id'; +COMMENT ON COLUMN system_dept.sort IS '显示顺序'; +COMMENT ON COLUMN system_dept.leader_user_id IS '负责人'; +COMMENT ON COLUMN system_dept.phone IS '联系电话'; +COMMENT ON COLUMN system_dept.email IS '邮箱'; +COMMENT ON COLUMN system_dept.status IS '部门状态(0正常 1停用)'; +COMMENT ON COLUMN system_dept.creator IS '创建者'; +COMMENT ON COLUMN system_dept.create_time IS '创建时间'; +COMMENT ON COLUMN system_dept.updater IS '更新者'; +COMMENT ON COLUMN system_dept.update_time IS '更新时间'; +COMMENT ON COLUMN system_dept.deleted IS '是否删除'; +COMMENT ON COLUMN system_dept.tenant_id IS '租户编号'; +COMMENT ON TABLE system_dept IS '部门表'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, '运维部门', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', '0', 121); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', '0', 122); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, '产品部门', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, '支持部门', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2023-12-02 09:47:38', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dept_seq; +CREATE SEQUENCE system_dept_seq + START 114; + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_data; +CREATE TABLE system_dict_data +( + id int8 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + label varchar(100) NULL DEFAULT '', + value varchar(100) NULL DEFAULT '', + dict_type varchar(100) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + color_type varchar(100) NULL DEFAULT '', + css_class varchar(100) NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dict_data + ADD CONSTRAINT pk_system_dict_data PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_data.id IS '字典编码'; +COMMENT ON COLUMN system_dict_data.sort IS '字典排序'; +COMMENT ON COLUMN system_dict_data.label IS '字典标签'; +COMMENT ON COLUMN system_dict_data.value IS '字典键值'; +COMMENT ON COLUMN system_dict_data.dict_type IS '字典类型'; +COMMENT ON COLUMN system_dict_data.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_data.color_type IS '颜色类型'; +COMMENT ON COLUMN system_dict_data.css_class IS 'css 样式'; +COMMENT ON COLUMN system_dict_data.remark IS '备注'; +COMMENT ON COLUMN system_dict_data.creator IS '创建者'; +COMMENT ON COLUMN system_dict_data.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_data.updater IS '更新者'; +COMMENT ON COLUMN system_dict_data.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_data.deleted IS '是否删除'; +COMMENT ON TABLE system_dict_data IS '字典数据表'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, '自定义', '2', 'infra_config_type', 0, 'primary', '', '参数类型 - 自定义', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '通知', '1', 'system_notice_type', 0, 'success', '', '通知', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '公告', '2', 'system_notice_type', 0, 'info', '', '公告', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '其它', '0', 'infra_operate_type', 0, 'default', '', '其它操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, '查询', '1', 'infra_operate_type', 0, 'info', '', '查询操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '新增', '2', 'infra_operate_type', 0, 'primary', '', '新增操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '修改', '3', 'infra_operate_type', 0, 'warning', '', '修改操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, '删除', '4', 'infra_operate_type', 0, 'danger', '', '删除操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '导出', '5', 'infra_operate_type', 0, 'default', '', '导出操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '导入', '6', 'infra_operate_type', 0, 'default', '', '导入操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '开启', '0', 'common_status', 0, 'primary', '', '开启状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, '关闭', '1', 'common_status', 0, 'info', '', '关闭状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, '目录', '1', 'system_menu_type', 0, '', '', '目录', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '菜单', '2', 'system_menu_type', 0, '', '', '菜单', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, '按钮', '3', 'system_menu_type', 0, '', '', '按钮', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '内置', '1', 'system_role_type', 0, 'danger', '', '内置角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, '自定义', '2', 'system_role_type', 0, 'primary', '', '自定义角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, '全部数据权限', '1', 'system_data_scope', 0, '', '', '全部数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, '指定部门数据权限', '2', 'system_data_scope', 0, '', '', '指定部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '验证码不存在', '30', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不存在', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '验证码不正确', '31', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, '未知异常', '100', 'system_login_result', 0, 'danger', '', '登陆结果 - 未知异常', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '是', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 是否类型 - 是', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '否', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 是否类型 - 否', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, '单表(增删改查)', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, '树表(增删改查)', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, '初始化中', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '运行中', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, '成功', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, '失败', '2', 'infra_job_log_status', 0, 'warning', '', '失败', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, '会员', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, '管理员', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2022-02-16 10:22:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, '营销', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, '初始化', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, '发送成功', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, '发送失败', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '不发送', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, '等待结果', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '支付宝 PC 网站支付', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '支付宝 PC 网站支付', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, '本地磁盘', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP 服务器', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP 服务器', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 对象存储', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, '短信登录', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '密码模式', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '授权码模式', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '简化模式', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '客户端模式', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '刷新模式', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '销售中', '1', 'product_spu_status', 0, 'success', '', '商品 SPU 状态 - 销售中', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, '仓库中', '0', 'product_spu_status', 0, 'info', '', '商品 SPU 状态 - 仓库中', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, '回收站', '-1', 'product_spu_status', 0, 'default', '', '商品 SPU 状态 - 回收站', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '满减', '1', 'promotion_discount_type', 0, 'success', '', '优惠类型 - 满减', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, '通用劵', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, '商品劵', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, '未使用', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, '直接领取', '1', 'promotion_coupon_take_type', 0, 'primary', '', '优惠劵的领取方式 - 直接领取', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, '指定发放', '2', 'promotion_coupon_take_type', 0, 'success', '', '优惠劵的领取方式 - 指定发放', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, '未开始', '10', 'promotion_activity_status', 0, 'primary', '', '促销活动的状态枚举 - 未开始', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '进行中', '20', 'promotion_activity_status', 0, 'success', '', '促销活动的状态枚举 - 进行中', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, '已结束', '30', 'promotion_activity_status', 0, 'info', '', '促销活动的状态枚举 - 已结束', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, '已关闭', '40', 'promotion_activity_status', 0, 'warning', '', '促销活动的状态枚举 - 已关闭', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, '满 N 元', '10', 'promotion_condition_type', 0, 'primary', '', '营销的条件类型 - 满 N 元', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, '满 N 件', '20', 'promotion_condition_type', 0, 'success', '', '营销的条件类型 - 满 N 件', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, '申请售后', '10', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 申请售后', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, '商品待退货', '20', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商品待退货', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '商家待收货', '30', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商家待收货', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, '等待退款', '40', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 等待退款', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '退款成功', '50', 'trade_after_sale_status', 0, 'default', '', '交易售后状态 - 退款成功', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, '买家取消', '61', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 买家取消', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '商家拒绝', '62', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒绝', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '商家拒收货', '63', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒收货', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '售中退款', '10', 'trade_after_sale_type', 0, 'success', '', '交易售后的类型 - 售中退款', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, '售后退款', '20', 'trade_after_sale_type', 0, 'primary', '', '交易售后的类型 - 售后退款', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '仅退款', '10', 'trade_after_sale_way', 0, 'primary', '', '交易售后的方式 - 仅退款', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '退货退款', '20', 'trade_after_sale_way', 0, 'success', '', '交易售后的方式 - 退货退款', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '微信小程序', '10', 'terminal', 0, 'default', '', '终端 - 微信小程序', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 网页', '20', 'terminal', 0, 'default', '', '终端 - H5 网页', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '微信公众号', '11', 'terminal', 0, 'default', '', '终端 - 微信公众号', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, '苹果 App', '31', 'terminal', 0, 'default', '', '终端 - 苹果 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '已完成', '30', 'trade_order_status', 0, 'success', '', '交易订单状态 - 已完成', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, '已取消', '40', 'trade_order_status', 0, 'danger', '', '交易订单状态 - 已取消', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, '未售后', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '交易订单项的售后状态 - 未售后', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, '售后中', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '交易订单项的售后状态 - 售后中', '1', '2022-12-10 20:59:21', '1', '2022-12-10 20:59:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, '已退款', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '交易订单项的售后状态 - 已退款', '1', '2022-12-10 20:59:46', '1', '2022-12-10 20:59:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, '完全匹配', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '公众号自动回复的请求关键字匹配模式 - 完全匹配', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, '半匹配', '2', 'mp_auto_reply_request_match', 0, 'success', '', '公众号自动回复的请求关键字匹配模式 - 半匹配', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, '文本', 'text', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 文本', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, '图片', 'image', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图片', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '语音', 'voice', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 语音', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, '视频', 'video', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, '小视频', 'shortvideo', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 小视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, '图文', 'news', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图文', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '音乐', 'music', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 音乐', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, '地理位置', 'location', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 地理位置', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '链接', 'link', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 链接', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '事件', 'event', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 事件', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, '初始化', '0', 'system_mail_send_status', 0, 'primary', '', '邮件发送状态 - 初始化\n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, '订单积分抵扣', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, '签到', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '已退款', '20', 'pay_order_status', 0, 'danger', '', '已退款', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, '请求成功,但是结果失败', '21', 'pay_notify_status', 0, 'warning', '', '请求成功,但是结果失败', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, '请求失败', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '微信扫码支付', 'wx_native', 'pay_channel_code', 0, 'success', '', '微信扫码支付', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '微信条码支付', 'wx_bar', 'pay_channel_code', 0, 'success', '', '微信条码支付\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '支付单', '1', 'pay_notify_type', 0, 'primary', '', '支付单', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, '订单积分抵扣(整单取消)', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, '下单奖励', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, '下单奖励(整单取消)', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, '品类劵', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '人人分销', '1', 'brokerage_enabled_condition', 0, '', '', '所有用户都可以分销', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, '指定分销', '2', 'brokerage_enabled_condition', 0, '', '', '仅可后台手动设置推广员', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '首次绑定', '1', 'brokerage_bind_mode', 0, '', '', '只要用户没有推广人,随时都可以绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, '注册绑定', '2', 'brokerage_bind_mode', 0, '', '', '仅新用户注册时才能绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, '申请提现驳回', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '待结算', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, '已结算', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, '已取消', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '审核中', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, '审核通过', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, '提现成功', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '审核不通过', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, '提现失败', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '工商银行', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '建设银行', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, '农业银行', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, '中国银行', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, '交通银行', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '招商银行', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, '钱包', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '支付宝', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '微信支付', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '其他', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, '金融业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, '房地产', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, '商业服务', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '运输/物流', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '生产', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '政府', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, '文化传媒', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '负责人', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, '只读', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, '读写', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, '未提交', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '审批中', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, '审核通过', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '审核不通过', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, '已取消', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '支票', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, '现金', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '邮政汇款', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '电汇', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '个', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '块', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, '只', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '把', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, '枚', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, '瓶', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '盒', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '台', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '吨', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, '千克', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '米', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '箱', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '套', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '打电话', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '发短信', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, '上门拜访', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '微信沟通', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '其它入库', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '其它入库(作废)', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '其它出库', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '其它出库(作废)', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, '未审核', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '已审核', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '调拨入库', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '调拨入库(作废)', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '调拨出库', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '调拨出库(作废)', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, '盘盈入库', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, '盘盈入库(作废)', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '盘亏出库', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '盘亏出库(作废)', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '销售出库', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '销售出库(作废)', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '销售退货入库', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '销售退货入库(作废)', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, '采购入库', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '天', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '周', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_data_seq; +CREATE SEQUENCE system_dict_data_seq + START 1537; + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_type; +CREATE TABLE system_dict_type +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + type varchar(100) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + deleted_time timestamp NULL DEFAULT NULL +); + +ALTER TABLE system_dict_type + ADD CONSTRAINT pk_system_dict_type PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_type.id IS '字典主键'; +COMMENT ON COLUMN system_dict_type.name IS '字典名称'; +COMMENT ON COLUMN system_dict_type.type IS '字典类型'; +COMMENT ON COLUMN system_dict_type.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_type.remark IS '备注'; +COMMENT ON COLUMN system_dict_type.creator IS '创建者'; +COMMENT ON COLUMN system_dict_type.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_type.updater IS '更新者'; +COMMENT ON COLUMN system_dict_type.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_type.deleted IS '是否删除'; +COMMENT ON COLUMN system_dict_type.deleted_time IS '删除时间'; +COMMENT ON TABLE system_dict_type IS '字典类型表'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '操作类型', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '登陆结果', 'system_login_result', 0, '登陆结果', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, '代码生成模板类型', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, '定时任务状态', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, '定时任务日志状态', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 异常数据的处理状态', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '短信渠道编码', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 授权类型', 'system_oauth2_grant_type', 0, 'OAuth 2.0 授权类型(模式)', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, '商品 SPU 状态', 'product_spu_status', 0, '商品 SPU 状态', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, '优惠类型', 'promotion_discount_type', 0, '优惠类型', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, '优惠劵模板的有限期类型', 'promotion_coupon_template_validity_type', 0, '优惠劵模板的有限期类型', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, '营销的商品范围', 'promotion_product_scope', 0, '营销的商品范围', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, '优惠劵的状态', 'promotion_coupon_status', 0, '优惠劵的状态', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, '优惠劵的领取方式', 'promotion_coupon_take_type', 0, '优惠劵的领取方式', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '促销活动的状态', 'promotion_activity_status', 0, '促销活动的状态', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, '营销的条件类型', 'promotion_condition_type', 0, '营销的条件类型', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, '交易售后状态', 'trade_after_sale_status', 0, '交易售后状态', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, '交易售后的类型', 'trade_after_sale_type', 0, '交易售后的类型', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, '交易售后的方式', 'trade_after_sale_way', 0, '交易售后的方式', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, '终端', 'terminal', 0, '终端', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '交易订单的类型', 'trade_order_type', 0, '交易订单的类型', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '交易订单的状态', 'trade_order_status', 0, '交易订单的状态', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '交易订单项的售后状态', 'trade_order_item_after_sale_status', 0, '交易订单项的售后状态', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, '代码生成的前端类型', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, '分佣模式', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, '分销关系绑定模式', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, '佣金提现类型', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, '佣金记录业务类型', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, '佣金记录状态', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, '佣金提现状态', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, '回款-回款方式', 'crm_receivable_return_type', 0, '回款-回款方式', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM 客户行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM 数据权限的级别', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM 审批状态', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM 产品单位', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM 跟进方式', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', '0', '1970-01-01 00:00:00'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_type_seq; +CREATE SEQUENCE system_dict_type_seq + START 620; + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +DROP TABLE IF EXISTS system_login_log; +CREATE TABLE system_login_log +( + id int8 NOT NULL, + log_type int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + username varchar(50) NULL DEFAULT '', + result int2 NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_login_log + ADD CONSTRAINT pk_system_login_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_login_log.id IS '访问ID'; +COMMENT ON COLUMN system_login_log.log_type IS '日志类型'; +COMMENT ON COLUMN system_login_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_login_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_login_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_login_log.username IS '用户账号'; +COMMENT ON COLUMN system_login_log.result IS '登陆结果'; +COMMENT ON COLUMN system_login_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_login_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_login_log.creator IS '创建者'; +COMMENT ON COLUMN system_login_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_login_log.updater IS '更新者'; +COMMENT ON COLUMN system_login_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_login_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_login_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_login_log IS '系统访问记录'; + +DROP SEQUENCE IF EXISTS system_login_log_seq; +CREATE SEQUENCE system_login_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_account; +CREATE TABLE system_mail_account +( + id int8 NOT NULL, + mail varchar(255) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + host varchar(255) NOT NULL, + port int4 NOT NULL, + ssl_enable bool NOT NULL DEFAULT '0', + starttls_enable bool NOT NULL DEFAULT '0', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_account + ADD CONSTRAINT pk_system_mail_account PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_account.id IS '主键'; +COMMENT ON COLUMN system_mail_account.mail IS '邮箱'; +COMMENT ON COLUMN system_mail_account.username IS '用户名'; +COMMENT ON COLUMN system_mail_account.password IS '密码'; +COMMENT ON COLUMN system_mail_account.host IS 'SMTP 服务器域名'; +COMMENT ON COLUMN system_mail_account.port IS 'SMTP 服务器端口'; +COMMENT ON COLUMN system_mail_account.ssl_enable IS '是否开启 SSL'; +COMMENT ON COLUMN system_mail_account.starttls_enable IS '是否开启 STARTTLS'; +COMMENT ON COLUMN system_mail_account.creator IS '创建者'; +COMMENT ON COLUMN system_mail_account.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_account.updater IS '更新者'; +COMMENT ON COLUMN system_mail_account.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_account.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_account IS '邮箱账号表'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', '1'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', '1'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_account_seq; +CREATE SEQUENCE system_mail_account_seq + START 5; + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_log; +CREATE TABLE system_mail_log +( + id int8 NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + to_mail varchar(255) NOT NULL, + account_id int8 NOT NULL, + from_mail varchar(255) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_nickname varchar(255) NULL DEFAULT NULL, + template_title varchar(255) NOT NULL, + template_content varchar(10240) NOT NULL, + template_params varchar(255) NOT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + send_message_id varchar(255) NULL DEFAULT NULL, + send_exception varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_log + ADD CONSTRAINT pk_system_mail_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_log.id IS '编号'; +COMMENT ON COLUMN system_mail_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_mail_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_mail_log.to_mail IS '接收邮箱地址'; +COMMENT ON COLUMN system_mail_log.account_id IS '邮箱账号编号'; +COMMENT ON COLUMN system_mail_log.from_mail IS '发送邮箱地址'; +COMMENT ON COLUMN system_mail_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_mail_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_mail_log.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_mail_log.template_title IS '邮件标题'; +COMMENT ON COLUMN system_mail_log.template_content IS '邮件内容'; +COMMENT ON COLUMN system_mail_log.template_params IS '邮件参数'; +COMMENT ON COLUMN system_mail_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_mail_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_mail_log.send_message_id IS '发送返回的消息 ID'; +COMMENT ON COLUMN system_mail_log.send_exception IS '发送异常'; +COMMENT ON COLUMN system_mail_log.creator IS '创建者'; +COMMENT ON COLUMN system_mail_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_log.updater IS '更新者'; +COMMENT ON COLUMN system_mail_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_log.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_log IS '邮件日志表'; + +DROP SEQUENCE IF EXISTS system_mail_log_seq; +CREATE SEQUENCE system_mail_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_template; +CREATE TABLE system_mail_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(63) NOT NULL, + account_id int8 NOT NULL, + nickname varchar(255) NULL DEFAULT NULL, + title varchar(255) NOT NULL, + content varchar(10240) NOT NULL, + params varchar(255) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_template + ADD CONSTRAINT pk_system_mail_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_template.id IS '编号'; +COMMENT ON COLUMN system_mail_template.name IS '模板名称'; +COMMENT ON COLUMN system_mail_template.code IS '模板编码'; +COMMENT ON COLUMN system_mail_template.account_id IS '发送的邮箱账号编号'; +COMMENT ON COLUMN system_mail_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_mail_template.title IS '模板标题'; +COMMENT ON COLUMN system_mail_template.content IS '模板内容'; +COMMENT ON COLUMN system_mail_template.params IS '参数数组'; +COMMENT ON COLUMN system_mail_template.status IS '开启状态'; +COMMENT ON COLUMN system_mail_template.remark IS '备注'; +COMMENT ON COLUMN system_mail_template.creator IS '创建者'; +COMMENT ON COLUMN system_mail_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_template.updater IS '更新者'; +COMMENT ON COLUMN system_mail_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_template.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_template IS '邮件模版表'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '

您的验证码是{code},名字是{name}

', '["code","name"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', '["key01","key02"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_template_seq; +CREATE SEQUENCE system_mail_template_seq + START 16; + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_menu; +CREATE TABLE system_menu +( + id int8 NOT NULL, + name varchar(50) NOT NULL, + permission varchar(100) NULL DEFAULT '', + type int2 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + parent_id int8 NOT NULL DEFAULT 0, + path varchar(200) NULL DEFAULT '', + icon varchar(100) NULL DEFAULT '#', + component varchar(255) NULL DEFAULT NULL, + component_name varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + visible bool NOT NULL DEFAULT '1', + keep_alive bool NOT NULL DEFAULT '1', + always_show bool NOT NULL DEFAULT '1', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_menu + ADD CONSTRAINT pk_system_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_menu.id IS '菜单ID'; +COMMENT ON COLUMN system_menu.name IS '菜单名称'; +COMMENT ON COLUMN system_menu.permission IS '权限标识'; +COMMENT ON COLUMN system_menu.type IS '菜单类型'; +COMMENT ON COLUMN system_menu.sort IS '显示顺序'; +COMMENT ON COLUMN system_menu.parent_id IS '父菜单ID'; +COMMENT ON COLUMN system_menu.path IS '路由地址'; +COMMENT ON COLUMN system_menu.icon IS '菜单图标'; +COMMENT ON COLUMN system_menu.component IS '组件路径'; +COMMENT ON COLUMN system_menu.component_name IS '组件名'; +COMMENT ON COLUMN system_menu.status IS '菜单状态'; +COMMENT ON COLUMN system_menu.visible IS '是否可见'; +COMMENT ON COLUMN system_menu.keep_alive IS '是否缓存'; +COMMENT ON COLUMN system_menu.always_show IS '是否总是显示'; +COMMENT ON COLUMN system_menu.creator IS '创建者'; +COMMENT ON COLUMN system_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_menu.updater IS '更新者'; +COMMENT ON COLUMN system_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_menu.deleted IS '是否删除'; +COMMENT ON TABLE system_menu IS '菜单权限表'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '报表管理', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, '1', '1', '1', '1', '2022-07-10 20:26:36', '1', '2024-02-29 12:33:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, '商品中心', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, '优惠劵模板更新', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, '优惠劵模板删除', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, '限时折扣活动删除', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, '限时折扣活动关闭', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, '秒杀商品', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, '秒杀活动查询', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, '秒杀活动创建', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, '秒杀活动更新', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, '秒杀活动删除', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, '秒杀时段', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, '秒杀时段查询', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '订单中心', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, '售后退款', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, '秒杀活动关闭', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, '订单列表', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '新增账号', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '修改账号', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, '查询账号', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, '删除账号', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, '生成二维码', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, '清空 API 配额', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, '数据统计', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, '标签管理', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, '查询标签', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, '新增标签', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '修改标签', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, '删除标签', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, '同步标签', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '粉丝管理', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, '查询粉丝', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '修改粉丝', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, '同步粉丝', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, '消息管理', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, '图文发表记录', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, '查询发布列表', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, '发布草稿', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, '删除发布记录', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, '图文草稿箱', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '新建草稿', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '修改草稿', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, '查询草稿', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, '删除草稿', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, '素材管理', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, '上传临时素材', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, '上传永久素材', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, '删除素材', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, '上传图文图片', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, '查询素材', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '菜单管理', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', '2023-01-14 17:43:54', '1', '2024-02-29 12:42:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, '自动回复', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, '查询回复', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, '新增回复', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '修改回复', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, '删除回复', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, '查询菜单', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '保存菜单', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, '1', '1', '1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot 开发文档', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:46:28', '1', '2023-12-02 21:32:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, '接入示例', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '配送管理', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, '自提门店删除', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, '会员积分', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, '回调通知', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, '拼团活动', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, '拼团商品', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, '拼团活动查询', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, '拼团活动创建', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, '拼团活动更新', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, '拼团活动删除', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, '拼团活动关闭', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, '砍价活动', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, '砍价商品', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, '砍价活动查询', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, '砍价活动创建', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, '会员标签查询', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, '会员分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '交易配置', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, '交易中心配置查询', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, '交易中心配置保存', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '分销管理', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, '分销用户', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, '分销用户查询', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, '分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, '分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, '分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, '分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, '分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, '佣金记录', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, '佣金记录查询', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, '佣金提现', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, '佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, '佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, '统计中心', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, '交易统计', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, '交易统计查询', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '助力记录查询', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, '分类创建', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '分类更新', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, '分类删除', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, '文章列表', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '文章管理查询', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '文章管理创建', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '文章管理更新', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, '客户管理', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM 系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, '1', '1', '1', '1', '2023-10-29 17:08:30', '1', '2024-02-04 15:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, '合同管理', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '线索管理', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '商机管理', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, '联系人管理', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, '回款管理', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, '回款计划', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, '客户公海配置', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, '客户公海配置保存', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, '客户限制配置', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, '客户限制配置查询', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, '客户限制配置创建', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, '客户限制配置更新', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, '产品更新', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, '产品删除', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, '产品导出', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, '产品分类配置', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, '产品分类查询', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, '产品分类创建', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, '产品分类更新', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, '产品分类删除', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '关联商机', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, '取关商机', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, '商品统计', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, '客户公海', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, '订单查询', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '订单更新', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '支付&退款案例', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, '转账案例', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:51:16', '1', '2024-01-18 23:51:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, '钱包管理', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, '充值套餐', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, '钱包余额', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, '产品信息', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, '产品查询', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, '产品创建', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, '产品更新', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, '产品删除', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, '产品导出', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, '产品分类', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, '分类查询', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, '分类创建', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '分类更新', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, '分类删除', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, '分类导出', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, '产品单位', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, '单位查询', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, '单位创建', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, '单位更新', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, '单位删除', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, '单位导出', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '库存管理', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, '仓库信息', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, '仓库查询', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, '仓库创建', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, '仓库更新', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, '仓库删除', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, '仓库导出', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, '产品库存', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, '库存查询', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '库存导出', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, '出入库明细', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, '库存明细查询', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, '库存明细导出', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '其它入库', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, '其它入库单查询', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, '其它入库单创建', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, '其它入库单更新', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, '其它入库单删除', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, '其它入库单导出', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, '采购管理', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, '供应商信息', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, '供应商查询', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, '供应商创建', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, '供应商更新', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, '供应商删除', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, '供应商导出', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, '其它入库单审批', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '其它出库', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, '其它出库单查询', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, '其它出库单创建', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, '其它出库单更新', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, '其它出库单删除', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, '其它出库单导出', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, '其它出库单审批', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '销售管理', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, '客户信息', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, '客户查询', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, '客户创建', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, '客户更新', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, '客户删除', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, '客户导出', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '库存调拨', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, '库存调度单查询', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, '库存调度单创建', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, '库存调度单更新', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, '库存调度单删除', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, '库存调度单导出', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, '库存调度单审批', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '库存盘点', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '库存盘点单查询', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '库存盘点单创建', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '库存盘点单更新', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '库存盘点单删除', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '库存盘点单导出', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '库存盘点单审批', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '销售订单', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '销售订单查询', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '销售订单创建', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '销售订单更新', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '销售订单删除', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '销售订单导出', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '销售订单审批', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '财务管理', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '结算账户', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '结算账户查询', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '结算账户创建', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '结算账户更新', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '结算账户删除', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '结算账户导出', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '销售出库', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '销售出库查询', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '销售出库创建', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '销售出库更新', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '销售出库删除', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '销售出库导出', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '销售出库审批', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '销售退货', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '销售退货查询', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '销售退货创建', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '销售退货更新', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '销售退货删除', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '销售退货导出', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '销售退货审批', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, '采购订单', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, '采购订单查询', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, '采购订单创建', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, '采购订单更新', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, '采购订单删除', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, '采购订单导出', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, '采购订单审批', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, '采购入库', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, '采购入库查询', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, '采购入库创建', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, '采购入库更新', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, '采购入库删除', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, '采购入库导出', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, '采购入库审批', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, '采购退货', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, '采购退货查询', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, '采购退货创建', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, '采购退货更新', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, '采购退货删除', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, '采购退货导出', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, '采购退货审批', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '付款单', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, '付款单查询', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '付款单创建', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '付款单更新', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, '付款单删除', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '付款单导出', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '付款单审批', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, '收款单', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, '收款单查询', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, '收款单创建', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, '收款单更新', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, '收款单删除', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, '收款单导出', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, '收款单审批', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '待办事项', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP 首页', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '商机状态配置', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '商机状态查询', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '商机状态创建', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '商机状态更新', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '商机状态删除', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, '合同配置', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_menu_seq; +CREATE SEQUENCE system_menu_seq + START 2758; + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +DROP TABLE IF EXISTS system_notice; +CREATE TABLE system_notice +( + id int8 NOT NULL, + title varchar(50) NOT NULL, + content text NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notice + ADD CONSTRAINT pk_system_notice PRIMARY KEY (id); + +COMMENT ON COLUMN system_notice.id IS '公告ID'; +COMMENT ON COLUMN system_notice.title IS '公告标题'; +COMMENT ON COLUMN system_notice.content IS '公告内容'; +COMMENT ON COLUMN system_notice.type IS '公告类型(1通知 2公告)'; +COMMENT ON COLUMN system_notice.status IS '公告状态(0正常 1关闭)'; +COMMENT ON COLUMN system_notice.creator IS '创建者'; +COMMENT ON COLUMN system_notice.create_time IS '创建时间'; +COMMENT ON COLUMN system_notice.updater IS '更新者'; +COMMENT ON COLUMN system_notice.update_time IS '更新时间'; +COMMENT ON COLUMN system_notice.deleted IS '是否删除'; +COMMENT ON COLUMN system_notice.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notice IS '通知公告表'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', '0', 121); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notice_seq; +CREATE SEQUENCE system_notice_seq + START 5; + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_message; +CREATE TABLE system_notify_message +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + template_id int8 NOT NULL, + template_code varchar(64) NOT NULL, + template_nickname varchar(63) NOT NULL, + template_content varchar(1024) NOT NULL, + template_type int4 NOT NULL, + template_params varchar(255) NOT NULL, + read_status bool NOT NULL, + read_time timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_message + ADD CONSTRAINT pk_system_notify_message PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_message.id IS '用户ID'; +COMMENT ON COLUMN system_notify_message.user_id IS '用户id'; +COMMENT ON COLUMN system_notify_message.user_type IS '用户类型'; +COMMENT ON COLUMN system_notify_message.template_id IS '模版编号'; +COMMENT ON COLUMN system_notify_message.template_code IS '模板编码'; +COMMENT ON COLUMN system_notify_message.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_notify_message.template_content IS '模版内容'; +COMMENT ON COLUMN system_notify_message.template_type IS '模版类型'; +COMMENT ON COLUMN system_notify_message.template_params IS '模版参数'; +COMMENT ON COLUMN system_notify_message.read_status IS '是否已读'; +COMMENT ON COLUMN system_notify_message.read_time IS '阅读时间'; +COMMENT ON COLUMN system_notify_message.creator IS '创建者'; +COMMENT ON COLUMN system_notify_message.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_message.updater IS '更新者'; +COMMENT ON COLUMN system_notify_message.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_message.deleted IS '是否删除'; +COMMENT ON COLUMN system_notify_message.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notify_message IS '站内信消息表'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:44:08', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:45:04', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{"name":"哈哈"}', '0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 22:21:42', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', '我是 2,我开始 3 了', 1, '{"name":"2","what":"3"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{"name":"123"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notify_message_seq; +CREATE SEQUENCE system_notify_message_seq + START 11; + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_template; +CREATE TABLE system_notify_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(64) NOT NULL, + nickname varchar(255) NOT NULL, + content varchar(1024) NOT NULL, + type int2 NOT NULL, + params varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_template + ADD CONSTRAINT pk_system_notify_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_template.id IS '主键'; +COMMENT ON COLUMN system_notify_template.name IS '模板名称'; +COMMENT ON COLUMN system_notify_template.code IS '模版编码'; +COMMENT ON COLUMN system_notify_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_notify_template.content IS '模版内容'; +COMMENT ON COLUMN system_notify_template.type IS '类型'; +COMMENT ON COLUMN system_notify_template.params IS '参数数组'; +COMMENT ON COLUMN system_notify_template.status IS '状态'; +COMMENT ON COLUMN system_notify_template.remark IS '备注'; +COMMENT ON COLUMN system_notify_template.creator IS '创建者'; +COMMENT ON COLUMN system_notify_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_template.updater IS '更新者'; +COMMENT ON COLUMN system_notify_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_template.deleted IS '是否删除'; +COMMENT ON TABLE system_notify_template IS '站内信模板表'; + +DROP SEQUENCE IF EXISTS system_notify_template_seq; +CREATE SEQUENCE system_notify_template_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_access_token; +CREATE TABLE system_oauth2_access_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + user_info varchar(512) NOT NULL, + access_token varchar(255) NOT NULL, + refresh_token varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_access_token + ADD CONSTRAINT pk_system_oauth2_access_token PRIMARY KEY (id); + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token); +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token); + +COMMENT ON COLUMN system_oauth2_access_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_access_token.user_info IS '用户信息'; +COMMENT ON COLUMN system_oauth2_access_token.access_token IS '访问令牌'; +COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_access_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_access_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_access_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_access_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_access_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_access_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_access_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_access_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 访问令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq; +CREATE SEQUENCE system_oauth2_access_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_approve; +CREATE TABLE system_oauth2_approve +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scope varchar(255) NULL DEFAULT '', + approved bool NOT NULL DEFAULT '0', + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_approve + ADD CONSTRAINT pk_system_oauth2_approve PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_approve.id IS '编号'; +COMMENT ON COLUMN system_oauth2_approve.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_approve.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_approve.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_approve.scope IS '授权范围'; +COMMENT ON COLUMN system_oauth2_approve.approved IS '是否接受'; +COMMENT ON COLUMN system_oauth2_approve.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_approve.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_approve.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_approve.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_approve.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_approve.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 批准表'; + +DROP SEQUENCE IF EXISTS system_oauth2_approve_seq; +CREATE SEQUENCE system_oauth2_approve_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_client; +CREATE TABLE system_oauth2_client +( + id int8 NOT NULL, + client_id varchar(255) NOT NULL, + secret varchar(255) NOT NULL, + name varchar(255) NOT NULL, + logo varchar(255) NOT NULL, + description varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + access_token_validity_seconds int4 NOT NULL, + refresh_token_validity_seconds int4 NOT NULL, + redirect_uris varchar(255) NOT NULL, + authorized_grant_types varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + auto_approve_scopes varchar(255) NULL DEFAULT NULL, + authorities varchar(255) NULL DEFAULT NULL, + resource_ids varchar(255) NULL DEFAULT NULL, + additional_information varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_client + ADD CONSTRAINT pk_system_oauth2_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_client.id IS '编号'; +COMMENT ON COLUMN system_oauth2_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_client.secret IS '客户端密钥'; +COMMENT ON COLUMN system_oauth2_client.name IS '应用名'; +COMMENT ON COLUMN system_oauth2_client.logo IS '应用图标'; +COMMENT ON COLUMN system_oauth2_client.description IS '应用描述'; +COMMENT ON COLUMN system_oauth2_client.status IS '状态'; +COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS '访问令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS '刷新令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.redirect_uris IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS '授权类型'; +COMMENT ON COLUMN system_oauth2_client.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS '自动通过的授权范围'; +COMMENT ON COLUMN system_oauth2_client.authorities IS '权限'; +COMMENT ON COLUMN system_oauth2_client.resource_ids IS '资源'; +COMMENT ON COLUMN system_oauth2_client.additional_information IS '附加信息'; +COMMENT ON COLUMN system_oauth2_client.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_client.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_client.deleted IS '是否删除'; +COMMENT ON TABLE system_oauth2_client IS 'OAuth2 客户端表'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '我是描述', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2024-02-22 16:31:52', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '啦啦啦啦', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2023-12-02 21:01:01', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2022-09-29 13:28:31', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2022-10-04 20:31:21', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_oauth2_client_seq; +CREATE SEQUENCE system_oauth2_client_seq + START 43; + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_code; +CREATE TABLE system_oauth2_code +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + code varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT '', + expires_time timestamp NOT NULL, + redirect_uri varchar(255) NULL DEFAULT NULL, + state varchar(255) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_code + ADD CONSTRAINT pk_system_oauth2_code PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_code.id IS '编号'; +COMMENT ON COLUMN system_oauth2_code.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_code.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_code.code IS '授权码'; +COMMENT ON COLUMN system_oauth2_code.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_code.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_code.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_code.redirect_uri IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_code.state IS '状态'; +COMMENT ON COLUMN system_oauth2_code.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_code.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_code IS 'OAuth2 授权码表'; + +DROP SEQUENCE IF EXISTS system_oauth2_code_seq; +CREATE SEQUENCE system_oauth2_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_refresh_token; +CREATE TABLE system_oauth2_refresh_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + refresh_token varchar(32) NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_refresh_token + ADD CONSTRAINT pk_system_oauth2_refresh_token PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_refresh_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq; +CREATE SEQUENCE system_oauth2_refresh_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +DROP TABLE IF EXISTS system_operate_log; +CREATE TABLE system_operate_log +( + id int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL, + user_type int2 NOT NULL DEFAULT 0, + type varchar(50) NOT NULL, + sub_type varchar(50) NOT NULL, + biz_id int8 NOT NULL, + action varchar(2000) NULL DEFAULT '', + extra varchar(2000) NULL DEFAULT '', + request_method varchar(16) NULL DEFAULT '', + request_url varchar(255) NULL DEFAULT '', + user_ip varchar(50) NULL DEFAULT NULL, + user_agent varchar(200) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_operate_log + ADD CONSTRAINT pk_system_operate_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_operate_log.id IS '日志主键'; +COMMENT ON COLUMN system_operate_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_operate_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_operate_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_operate_log.type IS '操作模块类型'; +COMMENT ON COLUMN system_operate_log.sub_type IS '操作名'; +COMMENT ON COLUMN system_operate_log.biz_id IS '操作数据模块编号'; +COMMENT ON COLUMN system_operate_log.action IS '操作内容'; +COMMENT ON COLUMN system_operate_log.extra IS '拓展字段'; +COMMENT ON COLUMN system_operate_log.request_method IS '请求方法名'; +COMMENT ON COLUMN system_operate_log.request_url IS '请求地址'; +COMMENT ON COLUMN system_operate_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_operate_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_operate_log.creator IS '创建者'; +COMMENT ON COLUMN system_operate_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_operate_log.updater IS '更新者'; +COMMENT ON COLUMN system_operate_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_operate_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_operate_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_operate_log IS '操作日志记录 V2 版本'; + +DROP SEQUENCE IF EXISTS system_operate_log_seq; +CREATE SEQUENCE system_operate_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +DROP TABLE IF EXISTS system_post; +CREATE TABLE system_post +( + id int8 NOT NULL, + code varchar(64) NOT NULL, + name varchar(50) NOT NULL, + sort int4 NOT NULL, + status int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_post + ADD CONSTRAINT pk_system_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_post.id IS '岗位ID'; +COMMENT ON COLUMN system_post.code IS '岗位编码'; +COMMENT ON COLUMN system_post.name IS '岗位名称'; +COMMENT ON COLUMN system_post.sort IS '显示顺序'; +COMMENT ON COLUMN system_post.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_post.remark IS '备注'; +COMMENT ON COLUMN system_post.creator IS '创建者'; +COMMENT ON COLUMN system_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_post.updater IS '更新者'; +COMMENT ON COLUMN system_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_post IS '岗位信息表'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 10:04:37', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', '人力资源', 5, 0, '', '1', '2024-03-24 20:45:40', '1', '2024-03-24 20:45:40', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_post_seq; +CREATE SEQUENCE system_post_seq + START 6; + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +DROP TABLE IF EXISTS system_role; +CREATE TABLE system_role +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + code varchar(100) NOT NULL, + sort int4 NOT NULL, + data_scope int2 NOT NULL DEFAULT 1, + data_scope_dept_ids varchar(500) NULL DEFAULT '', + status int2 NOT NULL, + type int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role + ADD CONSTRAINT pk_system_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_role.id IS '角色ID'; +COMMENT ON COLUMN system_role.name IS '角色名称'; +COMMENT ON COLUMN system_role.code IS '角色权限字符串'; +COMMENT ON COLUMN system_role.sort IS '显示顺序'; +COMMENT ON COLUMN system_role.data_scope IS '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +COMMENT ON COLUMN system_role.data_scope_dept_ids IS '数据范围(指定部门数组)'; +COMMENT ON COLUMN system_role.status IS '角色状态(0正常 1停用)'; +COMMENT ON COLUMN system_role.type IS '角色类型'; +COMMENT ON COLUMN system_role.remark IS '备注'; +COMMENT ON COLUMN system_role.creator IS '创建者'; +COMMENT ON COLUMN system_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_role.updater IS '更新者'; +COMMENT ON COLUMN system_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role IS '角色信息表'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '我想测试', '', '2021-01-06 13:49:35', '1', '2024-03-24 22:22:45', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_seq; +CREATE SEQUENCE system_role_seq + START 112; + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_role_menu; +CREATE TABLE system_role_menu +( + id int8 NOT NULL, + role_id int8 NOT NULL, + menu_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role_menu + ADD CONSTRAINT pk_system_role_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_role_menu.id IS '自增编号'; +COMMENT ON COLUMN system_role_menu.role_id IS '角色ID'; +COMMENT ON COLUMN system_role_menu.menu_id IS '菜单ID'; +COMMENT ON COLUMN system_role_menu.creator IS '创建者'; +COMMENT ON COLUMN system_role_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_role_menu.updater IS '更新者'; +COMMENT ON COLUMN system_role_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_role_menu.deleted IS '是否删除'; +COMMENT ON COLUMN system_role_menu.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role_menu IS '角色和菜单关联表'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_menu_seq; +CREATE SEQUENCE system_role_menu_seq + START 5779; + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_channel; +CREATE TABLE system_sms_channel +( + id int8 NOT NULL, + signature varchar(12) NOT NULL, + code varchar(63) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_key varchar(128) NOT NULL, + api_secret varchar(128) NULL DEFAULT NULL, + callback_url varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_channel + ADD CONSTRAINT pk_system_sms_channel PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_channel.id IS '编号'; +COMMENT ON COLUMN system_sms_channel.signature IS '短信签名'; +COMMENT ON COLUMN system_sms_channel.code IS '渠道编码'; +COMMENT ON COLUMN system_sms_channel.status IS '开启状态'; +COMMENT ON COLUMN system_sms_channel.remark IS '备注'; +COMMENT ON COLUMN system_sms_channel.api_key IS '短信 API 的账号'; +COMMENT ON COLUMN system_sms_channel.api_secret IS '短信 API 的秘钥'; +COMMENT ON COLUMN system_sms_channel.callback_url IS '短信发送回调 URL'; +COMMENT ON COLUMN system_sms_channel.creator IS '创建者'; +COMMENT ON COLUMN system_sms_channel.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_channel.updater IS '更新者'; +COMMENT ON COLUMN system_sms_channel.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_channel.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_channel IS '短信渠道'; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2023-12-02 22:10:17', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, '仅测试', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2023-12-02 22:10:08', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_channel_seq; +CREATE SEQUENCE system_sms_channel_seq + START 7; + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_code; +CREATE TABLE system_sms_code +( + id int8 NOT NULL, + mobile varchar(11) NOT NULL, + code varchar(6) NOT NULL, + create_ip varchar(15) NOT NULL, + scene int2 NOT NULL, + today_index int2 NOT NULL, + used int2 NOT NULL, + used_time timestamp NULL DEFAULT NULL, + used_ip varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_code + ADD CONSTRAINT pk_system_sms_code PRIMARY KEY (id); + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile); + +COMMENT ON COLUMN system_sms_code.id IS '编号'; +COMMENT ON COLUMN system_sms_code.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_code.code IS '验证码'; +COMMENT ON COLUMN system_sms_code.create_ip IS '创建 IP'; +COMMENT ON COLUMN system_sms_code.scene IS '发送场景'; +COMMENT ON COLUMN system_sms_code.today_index IS '今日发送的第几条'; +COMMENT ON COLUMN system_sms_code.used IS '是否使用'; +COMMENT ON COLUMN system_sms_code.used_time IS '使用时间'; +COMMENT ON COLUMN system_sms_code.used_ip IS '使用 IP'; +COMMENT ON COLUMN system_sms_code.creator IS '创建者'; +COMMENT ON COLUMN system_sms_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_code.updater IS '更新者'; +COMMENT ON COLUMN system_sms_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_sms_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_sms_code IS '手机验证码'; + +DROP SEQUENCE IF EXISTS system_sms_code_seq; +CREATE SEQUENCE system_sms_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_log; +CREATE TABLE system_sms_log +( + id int8 NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_type int2 NOT NULL, + template_content varchar(255) NOT NULL, + template_params varchar(255) NOT NULL, + api_template_id varchar(63) NOT NULL, + mobile varchar(11) NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + api_send_code varchar(63) NULL DEFAULT NULL, + api_send_msg varchar(255) NULL DEFAULT NULL, + api_request_id varchar(255) NULL DEFAULT NULL, + api_serial_no varchar(255) NULL DEFAULT NULL, + receive_status int2 NOT NULL DEFAULT 0, + receive_time timestamp NULL DEFAULT NULL, + api_receive_code varchar(63) NULL DEFAULT NULL, + api_receive_msg varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_log + ADD CONSTRAINT pk_system_sms_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_log.id IS '编号'; +COMMENT ON COLUMN system_sms_log.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_log.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_sms_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_sms_log.template_type IS '短信类型'; +COMMENT ON COLUMN system_sms_log.template_content IS '短信内容'; +COMMENT ON COLUMN system_sms_log.template_params IS '短信参数'; +COMMENT ON COLUMN system_sms_log.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_log.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_sms_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_sms_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_sms_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_sms_log.api_send_code IS '短信 API 发送结果的编码'; +COMMENT ON COLUMN system_sms_log.api_send_msg IS '短信 API 发送失败的提示'; +COMMENT ON COLUMN system_sms_log.api_request_id IS '短信 API 发送返回的唯一请求 ID'; +COMMENT ON COLUMN system_sms_log.api_serial_no IS '短信 API 发送返回的序号'; +COMMENT ON COLUMN system_sms_log.receive_status IS '接收状态'; +COMMENT ON COLUMN system_sms_log.receive_time IS '接收时间'; +COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API 接收结果的编码'; +COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API 接收结果的说明'; +COMMENT ON COLUMN system_sms_log.creator IS '创建者'; +COMMENT ON COLUMN system_sms_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_log.updater IS '更新者'; +COMMENT ON COLUMN system_sms_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_log.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_log IS '短信日志'; + +DROP SEQUENCE IF EXISTS system_sms_log_seq; +CREATE SEQUENCE system_sms_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_template; +CREATE TABLE system_sms_template +( + id int8 NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL, + code varchar(63) NOT NULL, + name varchar(63) NOT NULL, + content varchar(255) NOT NULL, + params varchar(255) NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_template_id varchar(63) NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_template + ADD CONSTRAINT pk_system_sms_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_template.id IS '编号'; +COMMENT ON COLUMN system_sms_template.type IS '模板类型'; +COMMENT ON COLUMN system_sms_template.status IS '开启状态'; +COMMENT ON COLUMN system_sms_template.code IS '模板编码'; +COMMENT ON COLUMN system_sms_template.name IS '模板名称'; +COMMENT ON COLUMN system_sms_template.content IS '模板内容'; +COMMENT ON COLUMN system_sms_template.params IS '参数数组'; +COMMENT ON COLUMN system_sms_template.remark IS '备注'; +COMMENT ON COLUMN system_sms_template.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_template.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_template.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_template.creator IS '创建者'; +COMMENT ON COLUMN system_sms_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_template.updater IS '更新者'; +COMMENT ON COLUMN system_sms_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_template.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_template IS '短信模板'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '["operation","code"]', '测试备注', '4383920', 6, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2023-12-02 22:32:47', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '["name"]', 'f哈哈哈', '4383920', 6, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2022-12-10 21:26:09', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '["name","code"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '["code"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2022-12-10 21:25:59', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '【工作流】流程被通过', '您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', '演示模板', '我就是测试一下下', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2023-03-24 23:45:07', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', '会员用户 - 修改手机', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', '会员用户 - 修改密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', '会员用户 - 重置密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_template_seq; +CREATE SEQUENCE system_sms_template_seq + START 17; + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +DROP TABLE IF EXISTS system_social_client; +CREATE TABLE system_social_client +( + id int8 NOT NULL, + name varchar(255) NOT NULL, + social_type int2 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + client_secret varchar(255) NOT NULL, + agent_id varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_client + ADD CONSTRAINT pk_system_social_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_client.id IS '编号'; +COMMENT ON COLUMN system_social_client.name IS '应用名'; +COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; +COMMENT ON COLUMN system_social_client.status IS '状态'; +COMMENT ON COLUMN system_social_client.creator IS '创建者'; +COMMENT ON COLUMN system_social_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_client.updater IS '更新者'; +COMMENT ON COLUMN system_social_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_client.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_client.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_client IS '社交客户端表'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '钉钉', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '钉钉(王土豆)', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', '1', 121); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '微信公众号', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '微信小程序', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', '1', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_social_client_seq; +CREATE SEQUENCE system_social_client_seq + START 44; + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user; +CREATE TABLE system_social_user +( + id int8 NOT NULL, + type int2 NOT NULL, + openid varchar(32) NOT NULL, + token varchar(256) NULL DEFAULT NULL, + raw_token_info varchar(1024) NOT NULL, + nickname varchar(32) NOT NULL, + avatar varchar(255) NULL DEFAULT NULL, + raw_user_info varchar(1024) NOT NULL, + code varchar(256) NOT NULL, + state varchar(256) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user + ADD CONSTRAINT pk_system_social_user PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user.type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user.openid IS '社交 openid'; +COMMENT ON COLUMN system_social_user.token IS '社交 token'; +COMMENT ON COLUMN system_social_user.raw_token_info IS '原始 Token 数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.nickname IS '用户昵称'; +COMMENT ON COLUMN system_social_user.avatar IS '用户头像'; +COMMENT ON COLUMN system_social_user.raw_user_info IS '原始用户数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.code IS '最后一次的认证 code'; +COMMENT ON COLUMN system_social_user.state IS '最后一次的认证 state'; +COMMENT ON COLUMN system_social_user.creator IS '创建者'; +COMMENT ON COLUMN system_social_user.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user.updater IS '更新者'; +COMMENT ON COLUMN system_social_user.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user IS '社交用户表'; + +DROP SEQUENCE IF EXISTS system_social_user_seq; +CREATE SEQUENCE system_social_user_seq + START 1; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user_bind; +CREATE TABLE system_social_user_bind +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + social_type int2 NOT NULL, + social_user_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user_bind + ADD CONSTRAINT pk_system_social_user_bind PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user_bind.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user_bind.user_id IS '用户编号'; +COMMENT ON COLUMN system_social_user_bind.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_user_bind.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user_bind.social_user_id IS '社交用户的编号'; +COMMENT ON COLUMN system_social_user_bind.creator IS '创建者'; +COMMENT ON COLUMN system_social_user_bind.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user_bind.updater IS '更新者'; +COMMENT ON COLUMN system_social_user_bind.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user_bind.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user_bind.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user_bind IS '社交绑定表'; + +DROP SEQUENCE IF EXISTS system_social_user_bind_seq; +CREATE SEQUENCE system_social_user_bind_seq + START 1; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant; +CREATE TABLE system_tenant +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + contact_user_id int8 NULL DEFAULT NULL, + contact_name varchar(30) NOT NULL, + contact_mobile varchar(500) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + website varchar(256) NULL DEFAULT '', + package_id int8 NOT NULL, + expire_time timestamp NOT NULL, + account_count int4 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant + ADD CONSTRAINT pk_system_tenant PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant.id IS '租户编号'; +COMMENT ON COLUMN system_tenant.name IS '租户名'; +COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号'; +COMMENT ON COLUMN system_tenant.contact_name IS '联系人'; +COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机'; +COMMENT ON COLUMN system_tenant.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant.website IS '绑定域名'; +COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号'; +COMMENT ON COLUMN system_tenant.expire_time IS '过期时间'; +COMMENT ON COLUMN system_tenant.account_count IS '账号数量'; +COMMENT ON COLUMN system_tenant.creator IS '创建者'; +COMMENT ON COLUMN system_tenant.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant.updater IS '更新者'; +COMMENT ON COLUMN system_tenant.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant IS '租户表'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_seq; +CREATE SEQUENCE system_tenant_seq + START 123; + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant_package; +CREATE TABLE system_tenant_package +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + status int2 NOT NULL DEFAULT 0, + remark varchar(256) NULL DEFAULT '', + menu_ids varchar(4096) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant_package + ADD CONSTRAINT pk_system_tenant_package PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant_package.id IS '套餐编号'; +COMMENT ON COLUMN system_tenant_package.name IS '套餐名'; +COMMENT ON COLUMN system_tenant_package.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant_package.remark IS '备注'; +COMMENT ON COLUMN system_tenant_package.menu_ids IS '关联的菜单编号'; +COMMENT ON COLUMN system_tenant_package.creator IS '创建者'; +COMMENT ON COLUMN system_tenant_package.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant_package.updater IS '更新者'; +COMMENT ON COLUMN system_tenant_package.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant_package.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant_package IS '租户套餐表'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-03-30 17:53:17', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_package_seq; +CREATE SEQUENCE system_tenant_package_seq + START 112; + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +DROP TABLE IF EXISTS system_user_post; +CREATE TABLE system_user_post +( + id int8 NOT NULL, + user_id int8 NOT NULL DEFAULT 0, + post_id int8 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_post + ADD CONSTRAINT pk_system_user_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_post.id IS 'id'; +COMMENT ON COLUMN system_user_post.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_post.post_id IS '岗位ID'; +COMMENT ON COLUMN system_user_post.creator IS '创建者'; +COMMENT ON COLUMN system_user_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_post.updater IS '更新者'; +COMMENT ON COLUMN system_user_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_post IS '用户岗位表'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_post_seq; +CREATE SEQUENCE system_user_post_seq + START 125; + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +DROP TABLE IF EXISTS system_user_role; +CREATE TABLE system_user_role +( + id int8 NOT NULL, + user_id int8 NOT NULL, + role_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_role + ADD CONSTRAINT pk_system_user_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_role.id IS '自增编号'; +COMMENT ON COLUMN system_user_role.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_role.role_id IS '角色ID'; +COMMENT ON COLUMN system_user_role.creator IS '创建者'; +COMMENT ON COLUMN system_user_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_role.updater IS '更新者'; +COMMENT ON COLUMN system_user_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_role IS '用户和角色关联表'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_role_seq; +CREATE SEQUENCE system_user_role_seq + START 39; + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +DROP TABLE IF EXISTS system_users; +CREATE TABLE system_users +( + id int8 NOT NULL, + username varchar(30) NOT NULL, + password varchar(100) NULL DEFAULT '', + nickname varchar(30) NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + dept_id int8 NULL DEFAULT NULL, + post_ids varchar(255) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT '', + mobile varchar(11) NULL DEFAULT '', + sex int2 NULL DEFAULT 0, + avatar varchar(512) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + login_ip varchar(50) NULL DEFAULT '', + login_date timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_users + ADD CONSTRAINT pk_system_users PRIMARY KEY (id); + +COMMENT ON COLUMN system_users.id IS '用户ID'; +COMMENT ON COLUMN system_users.username IS '用户账号'; +COMMENT ON COLUMN system_users.password IS '密码'; +COMMENT ON COLUMN system_users.nickname IS '用户昵称'; +COMMENT ON COLUMN system_users.remark IS '备注'; +COMMENT ON COLUMN system_users.dept_id IS '部门ID'; +COMMENT ON COLUMN system_users.post_ids IS '岗位编号数组'; +COMMENT ON COLUMN system_users.email IS '用户邮箱'; +COMMENT ON COLUMN system_users.mobile IS '手机号码'; +COMMENT ON COLUMN system_users.sex IS '用户性别'; +COMMENT ON COLUMN system_users.avatar IS '头像地址'; +COMMENT ON COLUMN system_users.status IS '帐号状态(0正常 1停用)'; +COMMENT ON COLUMN system_users.login_ip IS '最后登录IP'; +COMMENT ON COLUMN system_users.login_date IS '最后登录时间'; +COMMENT ON COLUMN system_users.creator IS '创建者'; +COMMENT ON COLUMN system_users.create_time IS '创建时间'; +COMMENT ON COLUMN system_users.updater IS '更新者'; +COMMENT ON COLUMN system_users.update_time IS '更新时间'; +COMMENT ON COLUMN system_users.deleted IS '是否删除'; +COMMENT ON COLUMN system_users.tenant_id IS '租户编号'; +COMMENT ON TABLE system_users IS '用户信息表'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', '0', 118); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', '0', 119); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', '0', 120); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', '0', 122); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_users_seq; +CREATE SEQUENCE system_users_seq + START 132; + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo01_contact; +CREATE TABLE yudao_demo01_contact +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + avatar varchar(512) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo01_contact + ADD CONSTRAINT pk_yudao_demo01_contact PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo01_contact.id IS '编号'; +COMMENT ON COLUMN yudao_demo01_contact.name IS '名字'; +COMMENT ON COLUMN yudao_demo01_contact.sex IS '性别'; +COMMENT ON COLUMN yudao_demo01_contact.birthday IS '出生年'; +COMMENT ON COLUMN yudao_demo01_contact.description IS '简介'; +COMMENT ON COLUMN yudao_demo01_contact.avatar IS '头像'; +COMMENT ON COLUMN yudao_demo01_contact.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo01_contact.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo01_contact.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo01_contact.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo01_contact.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo01_contact IS '示例联系人表'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 2, '2023-11-07 00:00:00', '

天蚕土豆!呀

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq; +CREATE SEQUENCE yudao_demo01_contact_seq + START 2; + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo02_category; +CREATE TABLE yudao_demo02_category +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + parent_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo02_category + ADD CONSTRAINT pk_yudao_demo02_category PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo02_category.id IS '编号'; +COMMENT ON COLUMN yudao_demo02_category.name IS '名字'; +COMMENT ON COLUMN yudao_demo02_category.parent_id IS '父级编号'; +COMMENT ON COLUMN yudao_demo02_category.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo02_category.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo02_category.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo02_category.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo02_category.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo02_category IS '示例分类表'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '番茄', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '怪怪', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '小番茄', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大番茄', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo02_category_seq; +CREATE SEQUENCE yudao_demo02_category_seq + START 7; + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_course; +CREATE TABLE yudao_demo03_course +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + score int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_course + ADD CONSTRAINT pk_yudao_demo03_course PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_course.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_course.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_course.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_course.score IS '分数'; +COMMENT ON COLUMN yudao_demo03_course.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_course.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_course.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_course.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_course.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_course IS '学生课程表'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_course_seq; +CREATE SEQUENCE yudao_demo03_course_seq + START 14; + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_grade; +CREATE TABLE yudao_demo03_grade +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + teacher varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_grade + ADD CONSTRAINT pk_yudao_demo03_grade PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_grade.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_grade.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_grade.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_grade.teacher IS '班主任'; +COMMENT ON COLUMN yudao_demo03_grade.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_grade.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_grade.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_grade.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_grade.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_grade IS '学生班级表'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq; +CREATE SEQUENCE yudao_demo03_grade_seq + START 10; + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_student; +CREATE TABLE yudao_demo03_student +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_student + ADD CONSTRAINT pk_yudao_demo03_student PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_student.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_student.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_student.sex IS '性别'; +COMMENT ON COLUMN yudao_demo03_student.birthday IS '出生日期'; +COMMENT ON COLUMN yudao_demo03_student.description IS '简介'; +COMMENT ON COLUMN yudao_demo03_student.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_student.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_student.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_student.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_student.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_student IS '学生表'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_student_seq; +CREATE SEQUENCE yudao_demo03_student_seq + START 10; + diff --git a/ruoyi-vue-pro-master/sql/mysql/quartz.sql b/ruoyi-vue-pro-master/sql/mysql/quartz.sql new file mode 100644 index 0000000..b4cfcc0 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/mysql/quartz.sql @@ -0,0 +1,363 @@ +/* + 注意:仅仅需要 Quartz 定时任务的场景,可选!!! + + Date: 30/04/2024 09:54:18 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for qrtz_blob_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_blob_triggers`; +CREATE TABLE `qrtz_blob_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `blob_data` blob NULL, + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + INDEX `sched_name` (`sched_name` ASC, `trigger_name` ASC, `trigger_group` ASC) USING BTREE, + CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_blob_triggers +-- ---------------------------- +-- @format:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for QRTZ_CALENDARS +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_calendars`; +CREATE TABLE `qrtz_calendars` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `calendar_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `calendar` blob NOT NULL, + PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_calendars +-- ---------------------------- +-- @format:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_cron_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_cron_triggers`; +CREATE TABLE `qrtz_cron_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `cron_expression` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `time_zone_id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_cron_triggers +-- ---------------------------- +-- @format:off +BEGIN; +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `qrtz_cron_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `cron_expression`, `time_zone_id`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_fired_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_fired_triggers`; +CREATE TABLE `qrtz_fired_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `entry_id` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `instance_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `fired_time` bigint NOT NULL, + `sched_time` bigint NOT NULL, + `priority` int NOT NULL, + `state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `job_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE, + INDEX `idx_qrtz_ft_trig_inst_name` (`sched_name` ASC, `instance_name` ASC) USING BTREE, + INDEX `idx_qrtz_ft_inst_job_req_rcvry` (`sched_name` ASC, `instance_name` ASC, `requests_recovery` ASC) USING BTREE, + INDEX `idx_qrtz_ft_j_g` (`sched_name` ASC, `job_name` ASC, `job_group` ASC) USING BTREE, + INDEX `idx_qrtz_ft_jg` (`sched_name` ASC, `job_group` ASC) USING BTREE, + INDEX `idx_qrtz_ft_t_g` (`sched_name` ASC, `trigger_name` ASC, `trigger_group` ASC) USING BTREE, + INDEX `idx_qrtz_ft_tg` (`sched_name` ASC, `trigger_group` ASC) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_fired_triggers +-- ---------------------------- +-- @format:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_job_details +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_job_details`; +CREATE TABLE `qrtz_job_details` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `job_class_name` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `is_durable` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `is_nonconcurrent` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `is_update_data` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `requests_recovery` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_data` blob NULL, + PRIMARY KEY (`sched_name`, `job_name`, `job_group`) USING BTREE, + INDEX `idx_qrtz_j_req_recovery` (`sched_name` ASC, `requests_recovery` ASC) USING BTREE, + INDEX `idx_qrtz_j_grp` (`sched_name` ASC, `job_group` ASC) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_job_details +-- ---------------------------- +-- @format:off +BEGIN; +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000137400104A4F425F48414E444C45525F4E414D45740010706179526566756E6453796E634A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000157400104A4F425F48414E444C45525F4E414D4574001774726164654F726465724175746F43616E63656C4A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000177400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F436F6D6D656E744A6F627800); +INSERT INTO `qrtz_job_details` (`sched_name`, `job_name`, `job_group`, `description`, `job_class_name`, `is_durable`, `is_nonconcurrent`, `is_update_data`, `requests_recovery`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000167400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F526563656976654A6F627800); +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_locks +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_locks`; +CREATE TABLE `qrtz_locks` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `lock_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_locks +-- ---------------------------- +-- @format:off +BEGIN; +INSERT INTO `qrtz_locks` (`sched_name`, `lock_name`) VALUES ('schedulerName', 'STATE_ACCESS'); +INSERT INTO `qrtz_locks` (`sched_name`, `lock_name`) VALUES ('schedulerName', 'TRIGGER_ACCESS'); +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_paused_trigger_grps +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; +CREATE TABLE `qrtz_paused_trigger_grps` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_paused_trigger_grps +-- ---------------------------- +-- @format:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for QRTZ_SCHEDULER_STATE +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_scheduler_state`; +CREATE TABLE `qrtz_scheduler_state` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `instance_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `last_checkin_time` bigint NOT NULL, + `checkin_interval` bigint NOT NULL, + PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_scheduler_state +-- ---------------------------- +-- @format:off +BEGIN; +INSERT INTO `qrtz_scheduler_state` (`sched_name`, `instance_name`, `last_checkin_time`, `checkin_interval`) VALUES ('schedulerName', 'MacBook-Pro.local1713489703551', 1713742509534, 15000); +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_simple_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simple_triggers`; +CREATE TABLE `qrtz_simple_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `repeat_count` bigint NOT NULL, + `repeat_interval` bigint NOT NULL, + `times_triggered` bigint NOT NULL, + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +-- @format:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_simprop_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_simprop_triggers`; +CREATE TABLE `qrtz_simprop_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `str_prop_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `str_prop_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `str_prop_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `int_prop_1` int NULL DEFAULT NULL, + `int_prop_2` int NULL DEFAULT NULL, + `long_prop_1` bigint NULL DEFAULT NULL, + `long_prop_2` bigint NULL DEFAULT NULL, + `dec_prop_1` decimal(13, 4) NULL DEFAULT NULL, + `dec_prop_2` decimal(13, 4) NULL DEFAULT NULL, + `bool_prop_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `bool_prop_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_simprop_triggers +-- ---------------------------- +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- Table structure for qrtz_triggers +-- ---------------------------- +DROP TABLE IF EXISTS `qrtz_triggers`; +CREATE TABLE `qrtz_triggers` +( + `sched_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `job_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `next_fire_time` bigint NULL DEFAULT NULL, + `prev_fire_time` bigint NULL DEFAULT NULL, + `priority` int NULL DEFAULT NULL, + `trigger_state` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `trigger_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `start_time` bigint NOT NULL, + `end_time` bigint NULL DEFAULT NULL, + `calendar_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `misfire_instr` smallint NULL DEFAULT NULL, + `job_data` blob NULL, + PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, + INDEX `idx_qrtz_t_j` (`sched_name` ASC, `job_name` ASC, `job_group` ASC) USING BTREE, + INDEX `idx_qrtz_t_jg` (`sched_name` ASC, `job_group` ASC) USING BTREE, + INDEX `idx_qrtz_t_c` (`sched_name` ASC, `calendar_name` ASC) USING BTREE, + INDEX `idx_qrtz_t_g` (`sched_name` ASC, `trigger_group` ASC) USING BTREE, + INDEX `idx_qrtz_t_state` (`sched_name` ASC, `trigger_state` ASC) USING BTREE, + INDEX `idx_qrtz_t_n_state` (`sched_name` ASC, `trigger_name` ASC, `trigger_group` ASC, `trigger_state` + ASC) USING BTREE, + INDEX `idx_qrtz_t_n_g_state` (`sched_name` ASC, `trigger_group` ASC, `trigger_state` ASC) USING BTREE, + INDEX `idx_qrtz_t_next_fire_time` (`sched_name` ASC, `next_fire_time` ASC) USING BTREE, + INDEX `idx_qrtz_t_nft_st` (`sched_name` ASC, `trigger_state` ASC, `next_fire_time` ASC) USING BTREE, + INDEX `idx_qrtz_t_nft_misfire` (`sched_name` ASC, `misfire_instr` ASC, `next_fire_time` ASC) USING BTREE, + INDEX `idx_qrtz_t_nft_st_misfire` (`sched_name` ASC, `misfire_instr` ASC, `next_fire_time` ASC, `trigger_state` + ASC) USING BTREE, + INDEX `idx_qrtz_t_nft_st_misfire_grp` (`sched_name` ASC, `misfire_instr` ASC, `next_fire_time` ASC, `trigger_group` + ASC, `trigger_state` ASC) USING BTREE, + CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB + CHARACTER SET = utf8mb4 + COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of qrtz_triggers +-- ---------------------------- +-- @format:off +BEGIN; +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', 'accessLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696301981000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 1695909720000, -1, 5, 'PAUSED', 'CRON', 1695909706000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', 'errorLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302043000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', 'jobLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302092000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', 'payOrderExpireJob', 'DEFAULT', NULL, 1690011600000, -1, 5, 'PAUSED', 'CRON', 1690011553000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', 'payOrderSyncJob', 'DEFAULT', NULL, 1690011600000, 1690011540000, 5, 'PAUSED', 'CRON', 1690007785000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', 'payRefundSyncJob', 'DEFAULT', NULL, 1690117560000, 1690117500000, 5, 'PAUSED', 'CRON', 1690117424000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 1695727440000, 1695727380000, 5, 'PAUSED', 'CRON', 1695656605000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 1695783840000, 1695783780000, 5, 'PAUSED', 'CRON', 1695742709000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`, `job_name`, `job_group`, `description`, `next_fire_time`, `prev_fire_time`, `priority`, `trigger_state`, `trigger_type`, `start_time`, `end_time`, `calendar_name`, `misfire_instr`, `job_data`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 1695742740000, 1695742680000, 5, 'PAUSED', 'CRON', 1695727433000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +COMMIT; +-- @formatter:on + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/sql/mysql/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/mysql/ruoyi-vue-pro.sql new file mode 100644 index 0000000..a4f6425 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/mysql/ruoyi-vue-pro.sql @@ -0,0 +1,3913 @@ +/* + Navicat Premium Data Transfer + + Source Server : 127.0.0.1 MySQL + Source Server Type : MySQL + Source Server Version : 80200 (8.2.0) + Source Host : 127.0.0.1:3306 + Source Schema : ruoyi-vue-pro + + Target Server Type : MySQL + Target Server Version : 80200 (8.2.0) + File Encoding : 65001 + + Date: 30/04/2024 09:54:18 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for QRTZ_BLOB_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; +CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `BLOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `SCHED_NAME`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, + CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_BLOB_TRIGGERS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_CALENDARS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_CALENDARS`; +CREATE TABLE `QRTZ_CALENDARS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `CALENDAR` blob NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_CALENDARS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_CRON_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`; +CREATE TABLE `QRTZ_CRON_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_CRON_TRIGGERS +-- ---------------------------- +BEGIN; +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', '0 0/1 * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_FIRED_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`; +CREATE TABLE `QRTZ_FIRED_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `FIRED_TIME` bigint NOT NULL, + `SCHED_TIME` bigint NOT NULL, + `PRIORITY` int NOT NULL, + `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE, + INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC) USING BTREE, + INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME` ASC, `INSTANCE_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE, + INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_FIRED_TRIGGERS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_JOB_DETAILS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`; +CREATE TABLE `QRTZ_JOB_DETAILS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME` ASC, `REQUESTS_RECOVERY` ASC) USING BTREE, + INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_JOB_DETAILS +-- ---------------------------- +BEGIN; +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000127400104A4F425F48414E444C45525F4E414D457400117061794F726465724578706972654A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000117400104A4F425F48414E444C45525F4E414D4574000F7061794F7264657253796E634A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000137400104A4F425F48414E444C45525F4E414D45740010706179526566756E6453796E634A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000157400104A4F425F48414E444C45525F4E414D4574001774726164654F726465724175746F43616E63656C4A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000177400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F436F6D6D656E744A6F627800); +INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000167400104A4F425F48414E444C45525F4E414D4574001874726164654F726465724175746F526563656976654A6F627800); +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_LOCKS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_LOCKS`; +CREATE TABLE `QRTZ_LOCKS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_LOCKS +-- ---------------------------- +BEGIN; +INSERT INTO `QRTZ_LOCKS` (`SCHED_NAME`, `LOCK_NAME`) VALUES ('schedulerName', 'STATE_ACCESS'); +INSERT INTO `QRTZ_LOCKS` (`SCHED_NAME`, `LOCK_NAME`) VALUES ('schedulerName', 'TRIGGER_ACCESS'); +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`; +CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SCHEDULER_STATE +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`; +CREATE TABLE `QRTZ_SCHEDULER_STATE` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `LAST_CHECKIN_TIME` bigint NOT NULL, + `CHECKIN_INTERVAL` bigint NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_SCHEDULER_STATE +-- ---------------------------- +BEGIN; +INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'MacBook-Pro.local1713489703551', 1713742509534, 15000); +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`; +CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `REPEAT_COUNT` bigint NOT NULL, + `REPEAT_INTERVAL` bigint NOT NULL, + `TIMES_TRIGGERED` bigint NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`; +CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `INT_PROP_1` int NULL DEFAULT NULL, + `INT_PROP_2` int NULL DEFAULT NULL, + `LONG_PROP_1` bigint NULL DEFAULT NULL, + `LONG_PROP_2` bigint NULL DEFAULT NULL, + `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL, + `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL, + `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_TRIGGERS`; +CREATE TABLE `QRTZ_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `NEXT_FIRE_TIME` bigint NULL DEFAULT NULL, + `PREV_FIRE_TIME` bigint NULL DEFAULT NULL, + `PRIORITY` int NULL DEFAULT NULL, + `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `START_TIME` bigint NOT NULL, + `END_TIME` bigint NULL DEFAULT NULL, + `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + `MISFIRE_INSTR` smallint NULL DEFAULT NULL, + `JOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_T_J`(`SCHED_NAME` ASC, `JOB_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME` ASC, `JOB_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_C`(`SCHED_NAME` ASC, `CALENDAR_NAME` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_G`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME` ASC, `TRIGGER_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME` ASC, `TRIGGER_STATE` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_STATE` ASC) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME` ASC, `MISFIRE_INSTR` ASC, `NEXT_FIRE_TIME` ASC, `TRIGGER_GROUP` ASC, `TRIGGER_STATE` ASC) USING BTREE, + CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +-- ---------------------------- +-- Records of QRTZ_TRIGGERS +-- ---------------------------- +BEGIN; +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', 'accessLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696301981000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 1695909720000, -1, 5, 'PAUSED', 'CRON', 1695909706000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', 'errorLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302043000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', 'jobLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302092000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderExpireJob', 'DEFAULT', 'payOrderExpireJob', 'DEFAULT', NULL, 1690011600000, -1, 5, 'PAUSED', 'CRON', 1690011553000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payOrderSyncJob', 'DEFAULT', 'payOrderSyncJob', 'DEFAULT', NULL, 1690011600000, 1690011540000, 5, 'PAUSED', 'CRON', 1690007785000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payRefundSyncJob', 'DEFAULT', 'payRefundSyncJob', 'DEFAULT', NULL, 1690117560000, 1690117500000, 5, 'PAUSED', 'CRON', 1690117424000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCancelJob', 'DEFAULT', 'tradeOrderAutoCancelJob', 'DEFAULT', NULL, 1695727440000, 1695727380000, 5, 'PAUSED', 'CRON', 1695656605000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoCommentJob', 'DEFAULT', 'tradeOrderAutoCommentJob', 'DEFAULT', NULL, 1695783840000, 1695783780000, 5, 'PAUSED', 'CRON', 1695742709000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'tradeOrderAutoReceiveJob', 'DEFAULT', 'tradeOrderAutoReceiveJob', 'DEFAULT', NULL, 1695742740000, 1695742680000, 5, 'PAUSED', 'CRON', 1695727433000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); +COMMIT; + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +DROP TABLE IF EXISTS `infra_api_access_log`; +CREATE TABLE `infra_api_access_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键', + `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '链路追踪编号', + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号', + `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', + `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', + `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求方法名', + `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求地址', + `request_params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '请求参数', + `response_body` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '响应结果', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户 IP', + `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浏览器 UA', + `operate_module` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '操作模块', + `operate_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '操作名', + `operate_type` tinyint NULL DEFAULT 0 COMMENT '操作分类', + `begin_time` datetime NOT NULL COMMENT '开始请求时间', + `end_time` datetime NOT NULL COMMENT '结束请求时间', + `duration` int NOT NULL COMMENT '执行时长', + `result_code` int NOT NULL DEFAULT 0 COMMENT '结果码', + `result_msg` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '结果提示', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_create_time`(`create_time` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 35934 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表'; + +-- ---------------------------- +-- Records of infra_api_access_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +DROP TABLE IF EXISTS `infra_api_error_log`; +CREATE TABLE `infra_api_error_log` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '编号', + `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '链路追踪编号\n *\n * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。', + `user_id` int NOT NULL DEFAULT 0 COMMENT '用户编号', + `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', + `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名\n *\n * 目前读取 spring.application.name', + `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求方法名', + `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求地址', + `request_params` varchar(8000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求参数', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户 IP', + `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浏览器 UA', + `exception_time` datetime NOT NULL COMMENT '异常发生时间', + `exception_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '异常名\n *\n * {@link Throwable#getClass()} 的类全名', + `exception_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的消息\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}', + `exception_root_cause_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常导致的根消息\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}', + `exception_stack_trace` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常的栈轨迹\n *\n * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}', + `exception_class_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类全名\n *\n * {@link StackTraceElement#getClassName()}', + `exception_file_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的类文件\n *\n * {@link StackTraceElement#getFileName()}', + `exception_method_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '异常发生的方法名\n *\n * {@link StackTraceElement#getMethodName()}', + `exception_line_number` int NOT NULL COMMENT '异常发生的方法所在行\n *\n * {@link StackTraceElement#getLineNumber()}', + `process_status` tinyint NOT NULL COMMENT '处理状态', + `process_time` datetime NULL DEFAULT NULL COMMENT '处理时间', + `process_user_id` int NULL DEFAULT 0 COMMENT '处理用户编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 16530 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; + +-- ---------------------------- +-- Records of infra_api_error_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +DROP TABLE IF EXISTS `infra_codegen_column`; +CREATE TABLE `infra_codegen_column` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_id` bigint NOT NULL COMMENT '表编号', + `column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '字段名', + `data_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '字段类型', + `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '字段描述', + `nullable` bit(1) NOT NULL COMMENT '是否允许为空', + `primary_key` bit(1) NOT NULL COMMENT '是否主键', + `ordinal_position` int NOT NULL COMMENT '排序', + `java_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 属性类型', + `java_field` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 属性名', + `dict_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '字典类型', + `example` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '数据示例', + `create_operation` bit(1) NOT NULL COMMENT '是否为 Create 创建操作的字段', + `update_operation` bit(1) NOT NULL COMMENT '是否为 Update 更新操作的字段', + `list_operation` bit(1) NOT NULL COMMENT '是否为 List 查询操作的字段', + `list_operation_condition` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '=' COMMENT 'List 查询操作的条件类型', + `list_operation_result` bit(1) NOT NULL COMMENT '是否为 List 查询操作的返回字段', + `html_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '显示类型', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2305 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; + +-- ---------------------------- +-- Records of infra_codegen_column +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +DROP TABLE IF EXISTS `infra_codegen_table`; +CREATE TABLE `infra_codegen_table` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `data_source_config_id` bigint NOT NULL COMMENT '数据源配置的编号', + `scene` tinyint NOT NULL DEFAULT 1 COMMENT '生成场景', + `table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '表名称', + `table_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '表描述', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `module_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模块名', + `business_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '业务名', + `class_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '类名称', + `class_comment` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '类描述', + `author` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '作者', + `template_type` tinyint NOT NULL DEFAULT 1 COMMENT '模板类型', + `front_type` tinyint NOT NULL COMMENT '前端类型', + `parent_menu_id` bigint NULL DEFAULT NULL COMMENT '父菜单编号', + `master_table_id` bigint NULL DEFAULT NULL COMMENT '主表的编号', + `sub_join_column_id` bigint NULL DEFAULT NULL COMMENT '子表关联主表的字段编号', + `sub_join_many` bit(1) NULL DEFAULT NULL COMMENT '主表与子表是否一对多', + `tree_parent_column_id` bigint NULL DEFAULT NULL COMMENT '树表的父字段编号', + `tree_name_column_id` bigint NULL DEFAULT NULL COMMENT '树表的名字字段编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 176 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; + +-- ---------------------------- +-- Records of infra_codegen_table +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +DROP TABLE IF EXISTS `infra_config`; +CREATE TABLE `infra_config` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '参数主键', + `category` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '参数分组', + `type` tinyint NOT NULL COMMENT '参数类型', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '参数名称', + `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '参数键名', + `value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '参数键值', + `visible` bit(1) NOT NULL COMMENT '是否可见', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '参数配置表'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +BEGIN; +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'biz', 1, '用户管理-账号初始密码', 'sys.user.init-password', '123456', b'0', '初始化密码 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-04-03 17:22:28', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 'url', 2, 'MySQL 监控的地址', 'url.druid', '', b'1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 'url', 2, 'SkyWalking 监控的地址', 'url.skywalking', '', b'1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 'url', 2, 'Spring Boot Admin 监控的地址', 'url.spring-boot-admin', '', b'1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (10, 'url', 2, 'Swagger 接口文档的地址', 'url.swagger', '', b'1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (11, 'ui', 2, '腾讯地图 key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', b'1', '腾讯地图 key', '1', '2023-06-03 19:16:27', '1', '2023-06-03 19:16:27', b'0'); +INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', b'1', 'test6', '1', '2023-12-03 09:55:16', '1', '2023-12-03 09:55:27', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +DROP TABLE IF EXISTS `infra_data_source_config`; +CREATE TABLE `infra_data_source_config` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '参数名称', + `url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '数据源连接', + `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '密码', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '数据源配置表'; + +-- ---------------------------- +-- Records of infra_data_source_config +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +DROP TABLE IF EXISTS `infra_file`; +CREATE TABLE `infra_file` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件编号', + `config_id` bigint NULL DEFAULT NULL COMMENT '配置编号', + `name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件名', + `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件路径', + `url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 URL', + `type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件类型', + `size` int NOT NULL COMMENT '文件大小', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1307 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; + +-- ---------------------------- +-- Records of infra_file +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +DROP TABLE IF EXISTS `infra_file_config`; +CREATE TABLE `infra_file_config` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置名', + `storage` tinyint NOT NULL COMMENT '存储器', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `master` bit(1) NOT NULL COMMENT '是否为主配置', + `config` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '存储配置', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +BEGIN; +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', b'0'); +INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器', 20, '', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +DROP TABLE IF EXISTS `infra_file_content`; +CREATE TABLE `infra_file_content` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `config_id` bigint NOT NULL COMMENT '配置编号', + `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件路径', + `content` mediumblob NOT NULL COMMENT '文件内容', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 283 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; + +-- ---------------------------- +-- Records of infra_file_content +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +DROP TABLE IF EXISTS `infra_job`; +CREATE TABLE `infra_job` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务编号', + `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务名称', + `status` tinyint NOT NULL COMMENT '任务状态', + `handler_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '处理器的名字', + `handler_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '处理器的参数', + `cron_expression` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'CRON 表达式', + `retry_count` int NOT NULL DEFAULT 0 COMMENT '重试次数', + `retry_interval` int NOT NULL DEFAULT 0 COMMENT '重试间隔', + `monitor_timeout` int NOT NULL DEFAULT 0 COMMENT '监控超时时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +BEGIN; +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', b'0'); +INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `infra_job_log`; +CREATE TABLE `infra_job_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志编号', + `job_id` bigint NOT NULL COMMENT '任务编号', + `handler_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '处理器的名字', + `handler_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '处理器的参数', + `execute_index` tinyint NOT NULL DEFAULT 1 COMMENT '第几次执行', + `begin_time` datetime NOT NULL COMMENT '开始执行时间', + `end_time` datetime NULL DEFAULT NULL COMMENT '结束执行时间', + `duration` int NULL DEFAULT NULL COMMENT '执行时长', + `status` tinyint NOT NULL COMMENT '任务状态', + `result` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '结果数据', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 395 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; + +-- ---------------------------- +-- Records of infra_job_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +DROP TABLE IF EXISTS `system_dept`; +CREATE TABLE `system_dept` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门id', + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '部门名称', + `parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父部门id', + `sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序', + `leader_user_id` bigint NULL DEFAULT NULL COMMENT '负责人', + `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱', + `status` tinyint NOT NULL COMMENT '部门状态(0正常 1停用)', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 114 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '部门表'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +BEGIN; +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, '运维部门', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', b'0', 121); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', b'0', 122); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, '产品部门', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', b'0', 1); +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, '支持部门', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2023-12-02 09:47:38', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS `system_dict_data`; +CREATE TABLE `system_dict_data` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典编码', + `sort` int NOT NULL DEFAULT 0 COMMENT '字典排序', + `label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典标签', + `value` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典键值', + `dict_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典类型', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态(0正常 1停用)', + `color_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '颜色类型', + `css_class` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT 'css 样式', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1537 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +BEGIN; +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (13, 2, '自定义', '2', 'infra_config_type', 0, 'primary', '', '参数类型 - 自定义', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (14, 1, '通知', '1', 'system_notice_type', 0, 'success', '', '通知', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, 2, '公告', '2', 'system_notice_type', 0, 'info', '', '公告', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (16, 0, '其它', '0', 'infra_operate_type', 0, 'default', '', '其它操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, 1, '查询', '1', 'infra_operate_type', 0, 'info', '', '查询操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, 2, '新增', '2', 'infra_operate_type', 0, 'primary', '', '新增操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, 3, '修改', '3', 'infra_operate_type', 0, 'warning', '', '修改操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (20, 4, '删除', '4', 'infra_operate_type', 0, 'danger', '', '删除操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, 5, '导出', '5', 'infra_operate_type', 0, 'default', '', '导出操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (23, 6, '导入', '6', 'infra_operate_type', 0, 'default', '', '导入操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, 1, '开启', '0', 'common_status', 0, 'primary', '', '开启状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 2, '关闭', '1', 'common_status', 0, 'info', '', '关闭状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, 1, '目录', '1', 'system_menu_type', 0, '', '', '目录', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 2, '菜单', '2', 'system_menu_type', 0, '', '', '菜单', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (31, 3, '按钮', '3', 'system_menu_type', 0, '', '', '按钮', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (32, 1, '内置', '1', 'system_role_type', 0, 'danger', '', '内置角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (33, 2, '自定义', '2', 'system_role_type', 0, 'primary', '', '自定义角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, 1, '全部数据权限', '1', 'system_data_scope', 0, '', '', '全部数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, 2, '指定部门数据权限', '2', 'system_data_scope', 0, '', '', '指定部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (42, 30, '验证码不存在', '30', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不存在', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (43, 31, '验证码不正确', '31', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (44, 100, '未知异常', '100', 'system_login_result', 0, 'danger', '', '登陆结果 - 未知异常', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (45, 1, '是', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 是否类型 - 是', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (46, 1, '否', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 是否类型 - 否', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (50, 1, '单表(增删改查)', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (51, 2, '树表(增删改查)', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (53, 0, '初始化中', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (57, 0, '运行中', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (58, 1, '成功', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (59, 2, '失败', '2', 'infra_job_log_status', 0, 'warning', '', '失败', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (60, 1, '会员', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (61, 2, '管理员', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2022-02-16 10:22:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (69, 0, '营销', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (70, 0, '初始化', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (71, 1, '发送成功', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (72, 2, '发送失败', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (73, 3, '不发送', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (74, 0, '等待结果', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (116, 10, '支付宝 PC 网站支付', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '支付宝 PC 网站支付', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1151, 10, '本地磁盘', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1152, 11, 'FTP 服务器', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1153, 12, 'SFTP 服务器', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1154, 20, 'S3 对象存储', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1155, 103, '短信登录', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '密码模式', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '授权码模式', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '简化模式', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '客户端模式', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '刷新模式', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1162, 1, '销售中', '1', 'product_spu_status', 0, 'success', '', '商品 SPU 状态 - 销售中', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1163, 0, '仓库中', '0', 'product_spu_status', 0, 'info', '', '商品 SPU 状态 - 仓库中', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1164, 0, '回收站', '-1', 'product_spu_status', 0, 'default', '', '商品 SPU 状态 - 回收站', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1165, 1, '满减', '1', 'promotion_discount_type', 0, 'success', '', '优惠类型 - 满减', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1169, 1, '通用劵', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1170, 2, '商品劵', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1171, 1, '未使用', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1174, 1, '直接领取', '1', 'promotion_coupon_take_type', 0, 'primary', '', '优惠劵的领取方式 - 直接领取', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1175, 2, '指定发放', '2', 'promotion_coupon_take_type', 0, 'success', '', '优惠劵的领取方式 - 指定发放', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1176, 10, '未开始', '10', 'promotion_activity_status', 0, 'primary', '', '促销活动的状态枚举 - 未开始', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1177, 20, '进行中', '20', 'promotion_activity_status', 0, 'success', '', '促销活动的状态枚举 - 进行中', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1178, 30, '已结束', '30', 'promotion_activity_status', 0, 'info', '', '促销活动的状态枚举 - 已结束', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1179, 40, '已关闭', '40', 'promotion_activity_status', 0, 'warning', '', '促销活动的状态枚举 - 已关闭', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1180, 10, '满 N 元', '10', 'promotion_condition_type', 0, 'primary', '', '营销的条件类型 - 满 N 元', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1181, 20, '满 N 件', '20', 'promotion_condition_type', 0, 'success', '', '营销的条件类型 - 满 N 件', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1182, 10, '申请售后', '10', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 申请售后', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1183, 20, '商品待退货', '20', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商品待退货', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1184, 30, '商家待收货', '30', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商家待收货', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1185, 40, '等待退款', '40', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 等待退款', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1186, 50, '退款成功', '50', 'trade_after_sale_status', 0, 'default', '', '交易售后状态 - 退款成功', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1187, 61, '买家取消', '61', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 买家取消', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1188, 62, '商家拒绝', '62', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒绝', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1189, 63, '商家拒收货', '63', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒收货', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1190, 10, '售中退款', '10', 'trade_after_sale_type', 0, 'success', '', '交易售后的类型 - 售中退款', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1191, 20, '售后退款', '20', 'trade_after_sale_type', 0, 'primary', '', '交易售后的类型 - 售后退款', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1192, 10, '仅退款', '10', 'trade_after_sale_way', 0, 'primary', '', '交易售后的方式 - 仅退款', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1193, 20, '退货退款', '20', 'trade_after_sale_way', 0, 'success', '', '交易售后的方式 - 退货退款', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1194, 10, '微信小程序', '10', 'terminal', 0, 'default', '', '终端 - 微信小程序', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1195, 20, 'H5 网页', '20', 'terminal', 0, 'default', '', '终端 - H5 网页', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1196, 11, '微信公众号', '11', 'terminal', 0, 'default', '', '终端 - 微信公众号', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1197, 31, '苹果 App', '31', 'terminal', 0, 'default', '', '终端 - 苹果 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1206, 30, '已完成', '30', 'trade_order_status', 0, 'success', '', '交易订单状态 - 已完成', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1207, 40, '已取消', '40', 'trade_order_status', 0, 'danger', '', '交易订单状态 - 已取消', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1208, 0, '未售后', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '交易订单项的售后状态 - 未售后', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1209, 1, '售后中', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '交易订单项的售后状态 - 售后中', '1', '2022-12-10 20:59:21', '1', '2022-12-10 20:59:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1210, 2, '已退款', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '交易订单项的售后状态 - 已退款', '1', '2022-12-10 20:59:46', '1', '2022-12-10 20:59:46', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1211, 1, '完全匹配', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '公众号自动回复的请求关键字匹配模式 - 完全匹配', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1212, 2, '半匹配', '2', 'mp_auto_reply_request_match', 0, 'success', '', '公众号自动回复的请求关键字匹配模式 - 半匹配', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1213, 1, '文本', 'text', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 文本', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1214, 2, '图片', 'image', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图片', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1215, 3, '语音', 'voice', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 语音', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1216, 4, '视频', 'video', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1217, 5, '小视频', 'shortvideo', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 小视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1218, 6, '图文', 'news', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图文', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1219, 7, '音乐', 'music', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 音乐', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1220, 8, '地理位置', 'location', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 地理位置', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1221, 9, '链接', 'link', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 链接', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1222, 10, '事件', 'event', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 事件', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1223, 0, '初始化', '0', 'system_mail_send_status', 0, 'primary', '', '邮件发送状态 - 初始化\n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1335, 11, '订单积分抵扣', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1336, 1, '签到', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1341, 20, '已退款', '20', 'pay_order_status', 0, 'danger', '', '已退款', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1342, 21, '请求成功,但是结果失败', '21', 'pay_notify_status', 0, 'warning', '', '请求成功,但是结果失败', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1343, 22, '请求失败', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1344, 4, '微信扫码支付', 'wx_native', 'pay_channel_code', 0, 'success', '', '微信扫码支付', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1345, 5, '微信条码支付', 'wx_bar', 'pay_channel_code', 0, 'success', '', '微信条码支付\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1346, 1, '支付单', '1', 'pay_notify_type', 0, 'primary', '', '支付单', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1349, 12, '订单积分抵扣(整单取消)', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1352, 11, '下单奖励', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1353, 12, '下单奖励(整单取消)', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1358, 3, '品类劵', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1359, 1, '人人分销', '1', 'brokerage_enabled_condition', 0, '', '', '所有用户都可以分销', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1360, 2, '指定分销', '2', 'brokerage_enabled_condition', 0, '', '', '仅可后台手动设置推广员', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1361, 1, '首次绑定', '1', 'brokerage_bind_mode', 0, '', '', '只要用户没有推广人,随时都可以绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1362, 2, '注册绑定', '2', 'brokerage_bind_mode', 0, '', '', '仅新用户注册时才能绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1370, 3, '申请提现驳回', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1371, 0, '待结算', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1372, 1, '已结算', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1373, 2, '已取消', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1374, 0, '审核中', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1375, 10, '审核通过', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1376, 11, '提现成功', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1377, 20, '审核不通过', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1378, 21, '提现失败', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1379, 0, '工商银行', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1380, 1, '建设银行', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1381, 2, '农业银行', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1382, 3, '中国银行', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1383, 4, '交通银行', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1384, 5, '招商银行', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1385, 21, '钱包', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1398, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1399, 6, '支付宝', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1400, 7, '微信支付', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1401, 8, '其他', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1403, 2, '金融业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1404, 3, '房地产', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1405, 4, '商业服务', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1406, 5, '运输/物流', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1407, 6, '生产', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1408, 7, '政府', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1409, 8, '文化传媒', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1447, 1, '负责人', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1448, 2, '只读', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1449, 3, '读写', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1450, 0, '未提交', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1451, 10, '审批中', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1452, 20, '审核通过', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1453, 30, '审核不通过', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1454, 40, '已取消', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1456, 1, '支票', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1457, 2, '现金', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1458, 3, '邮政汇款', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1459, 4, '电汇', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1460, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1461, 1, '个', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1462, 2, '块', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1463, 3, '只', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1464, 4, '把', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1465, 5, '枚', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1466, 6, '瓶', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1467, 7, '盒', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1468, 8, '台', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1469, 9, '吨', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1470, 10, '千克', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1471, 11, '米', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1472, 12, '箱', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1473, 13, '套', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1474, 1, '打电话', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1475, 2, '发短信', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1476, 3, '上门拜访', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1477, 4, '微信沟通', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1478, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1479, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1480, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1481, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1482, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1483, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1484, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1485, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1486, 10, '其它入库', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1487, 11, '其它入库(作废)', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1488, 20, '其它出库', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1489, 21, '其它出库(作废)', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1490, 10, '未审核', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1491, 20, '已审核', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1492, 30, '调拨入库', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1493, 31, '调拨入库(作废)', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1494, 32, '调拨出库', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1495, 33, '调拨出库(作废)', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1496, 40, '盘盈入库', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1497, 41, '盘盈入库(作废)', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1498, 42, '盘亏出库', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1499, 43, '盘亏出库(作废)', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1500, 50, '销售出库', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1501, 51, '销售出库(作废)', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1502, 60, '销售退货入库', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1503, 61, '销售退货入库(作废)', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1504, 70, '采购入库', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1529, 1, '天', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1530, 2, '周', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS `system_dict_type`; +CREATE TABLE `system_dict_type` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典主键', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典名称', + `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '字典类型', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态(0正常 1停用)', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +BEGIN; +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (9, '操作类型', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (104, '登陆结果', 'system_login_result', 0, '登陆结果', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (106, '代码生成模板类型', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (107, '定时任务状态', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (108, '定时任务日志状态', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (110, 'API 异常数据的处理状态', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (111, '短信渠道编码', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (147, 'OAuth 2.0 授权类型', 'system_oauth2_grant_type', 0, 'OAuth 2.0 授权类型(模式)', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (149, '商品 SPU 状态', 'product_spu_status', 0, '商品 SPU 状态', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (150, '优惠类型', 'promotion_discount_type', 0, '优惠类型', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (151, '优惠劵模板的有限期类型', 'promotion_coupon_template_validity_type', 0, '优惠劵模板的有限期类型', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (152, '营销的商品范围', 'promotion_product_scope', 0, '营销的商品范围', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (153, '优惠劵的状态', 'promotion_coupon_status', 0, '优惠劵的状态', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (154, '优惠劵的领取方式', 'promotion_coupon_take_type', 0, '优惠劵的领取方式', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (155, '促销活动的状态', 'promotion_activity_status', 0, '促销活动的状态', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (156, '营销的条件类型', 'promotion_condition_type', 0, '营销的条件类型', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (157, '交易售后状态', 'trade_after_sale_status', 0, '交易售后状态', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (158, '交易售后的类型', 'trade_after_sale_type', 0, '交易售后的类型', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (159, '交易售后的方式', 'trade_after_sale_way', 0, '交易售后的方式', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (160, '终端', 'terminal', 0, '终端', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (161, '交易订单的类型', 'trade_order_type', 0, '交易订单的类型', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (162, '交易订单的状态', 'trade_order_status', 0, '交易订单的状态', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (163, '交易订单项的售后状态', 'trade_order_item_after_sale_status', 0, '交易订单项的售后状态', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (168, '代码生成的前端类型', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (176, '分佣模式', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (177, '分销关系绑定模式', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (178, '佣金提现类型', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (179, '佣金记录业务类型', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (180, '佣金记录状态', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (181, '佣金提现状态', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (185, '回款-回款方式', 'crm_receivable_return_type', 0, '回款-回款方式', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (186, 'CRM 客户行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (605, 'CRM 数据权限的级别', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (606, 'CRM 审批状态', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (607, 'CRM 产品单位', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (608, 'CRM 跟进方式', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (609, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', b'0', '1970-01-01 00:00:00'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +DROP TABLE IF EXISTS `system_login_log`; +CREATE TABLE `system_login_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '访问ID', + `log_type` bigint NOT NULL COMMENT '日志类型', + `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '链路追踪编号', + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号', + `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', + `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '用户账号', + `result` tinyint NOT NULL COMMENT '登陆结果', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户 IP', + `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浏览器 UA', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3104 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; + +-- ---------------------------- +-- Records of system_login_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +DROP TABLE IF EXISTS `system_mail_account`; +CREATE TABLE `system_mail_account` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮箱', + `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码', + `host` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SMTP 服务器域名', + `port` int NOT NULL COMMENT 'SMTP 服务器端口', + `ssl_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否开启 SSL', + `starttls_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否开启 STARTTLS', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮箱账号表'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +BEGIN; +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, b'0', b'0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', b'0'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, b'1', b'0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', b'0'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, b'0', b'0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', b'1'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, b'1', b'0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', b'1'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +DROP TABLE IF EXISTS `system_mail_log`; +CREATE TABLE `system_mail_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户编号', + `user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型', + `to_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '接收邮箱地址', + `account_id` bigint NOT NULL COMMENT '邮箱账号编号', + `from_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送邮箱地址', + `template_id` bigint NOT NULL COMMENT '模板编号', + `template_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码', + `template_nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '模版发送人名称', + `template_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮件标题', + `template_content` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮件内容', + `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮件参数', + `send_status` tinyint NOT NULL DEFAULT 0 COMMENT '发送状态', + `send_time` datetime NULL DEFAULT NULL COMMENT '发送时间', + `send_message_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发送返回的消息 ID', + `send_exception` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发送异常', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 356 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表'; + +-- ---------------------------- +-- Records of system_mail_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +DROP TABLE IF EXISTS `system_mail_template`; +CREATE TABLE `system_mail_template` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板名称', + `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码', + `account_id` bigint NOT NULL COMMENT '发送的邮箱账号编号', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发送人名称', + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板标题', + `content` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板内容', + `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '参数数组', + `status` tinyint NOT NULL COMMENT '开启状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件模版表'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +BEGIN; +INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '

您的验证码是{code},名字是{name}

', '[\"code\",\"name\"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', b'0'); +INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', '[\"key01\",\"key02\"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', b'0'); +INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +DROP TABLE IF EXISTS `system_menu`; +CREATE TABLE `system_menu` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单ID', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '菜单名称', + `permission` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '权限标识', + `type` tinyint NOT NULL COMMENT '菜单类型', + `sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序', + `parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父菜单ID', + `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '路由地址', + `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '#' COMMENT '菜单图标', + `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '组件路径', + `component_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '组件名', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '菜单状态', + `visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否可见', + `keep_alive` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否缓存', + `always_show` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否总是显示', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2758 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +BEGIN; +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, b'1', b'1', b'1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, b'1', b'1', b'1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, b'1', b'1', b'1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, b'1', b'1', b'1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, b'1', b'1', b'1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, b'1', b'1', b'1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, b'1', b'1', b'1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, b'1', b'1', b'1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, b'1', b'1', b'1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, b'1', b'1', b'1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, b'1', b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1281, '报表管理', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, b'1', b'1', b'1', '1', '2022-07-10 20:26:36', '1', '2024-02-29 12:33:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, '商品中心', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2035, '优惠劵模板更新', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2036, '优惠劵模板删除', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2051, '限时折扣活动删除', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2052, '限时折扣活动关闭', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2059, '秒杀商品', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, b'1', b'1', b'1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2060, '秒杀活动查询', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2061, '秒杀活动创建', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2062, '秒杀活动更新', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2063, '秒杀活动删除', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2066, '秒杀时段', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2067, '秒杀时段查询', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, b'1', b'1', b'1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2072, '订单中心', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2073, '售后退款', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, b'1', b'1', b'1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2075, '秒杀活动关闭', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, b'1', b'1', b'1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2076, '订单列表', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, b'1', b'1', b'1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, b'1', b'1', b'1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, b'1', b'1', b'1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2086, '新增账号', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2087, '修改账号', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2088, '查询账号', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2089, '删除账号', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2090, '生成二维码', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2091, '清空 API 配额', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2092, '数据统计', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, b'1', b'1', b'1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2093, '标签管理', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, b'1', b'1', b'1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2094, '查询标签', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2095, '新增标签', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2096, '修改标签', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2097, '删除标签', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2098, '同步标签', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2099, '粉丝管理', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, b'1', b'1', b'1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2100, '查询粉丝', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2101, '修改粉丝', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2102, '同步粉丝', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2103, '消息管理', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, b'1', b'1', b'1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2104, '图文发表记录', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, b'1', b'1', b'1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2105, '查询发布列表', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2106, '发布草稿', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2107, '删除发布记录', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2108, '图文草稿箱', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, b'1', b'1', b'1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2109, '新建草稿', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2110, '修改草稿', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2111, '查询草稿', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2112, '删除草稿', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2113, '素材管理', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, b'1', b'1', b'1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2114, '上传临时素材', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2115, '上传永久素材', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2116, '删除素材', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2117, '上传图文图片', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2118, '查询素材', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2119, '菜单管理', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, b'1', b'1', b'1', '1', '2023-01-14 17:43:54', '1', '2024-02-29 12:42:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2120, '自动回复', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, b'1', b'1', b'1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2121, '查询回复', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2122, '新增回复', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2123, '修改回复', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2124, '删除回复', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2125, '查询菜单', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2126, '保存菜单', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, b'1', b'1', b'1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, b'1', b'1', b'1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, b'1', b'1', b'1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, b'1', b'1', b'1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2159, 'Boot 开发文档', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:46:28', '1', '2023-12-02 21:32:20', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2161, '接入示例', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, b'1', b'1', b'1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2164, '配送管理', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, b'1', b'1', b'1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, b'1', b'1', b'1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, b'1', b'1', b'1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, b'1', b'1', b'1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2183, '自提门店删除', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, b'1', b'1', b'1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2287, '会员积分', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, b'1', b'1', b'1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2301, '回调通知', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2303, '拼团活动', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2304, '拼团商品', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, b'1', b'1', b'1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2305, '拼团活动查询', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2306, '拼团活动创建', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2307, '拼团活动更新', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2308, '拼团活动删除', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2309, '拼团活动关闭', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2310, '砍价活动', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2311, '砍价商品', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, b'1', b'1', b'1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2312, '砍价活动查询', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2313, '砍价活动创建', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2321, '会员标签查询', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, b'1', b'1', b'1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2330, '会员分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, b'1', b'1', b'1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2342, '交易配置', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2343, '交易中心配置查询', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2344, '交易中心配置保存', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2345, '分销管理', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2346, '分销用户', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2347, '分销用户查询', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2348, '分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2349, '分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2350, '分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2351, '分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2352, '分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2353, '佣金记录', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2354, '佣金记录查询', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2355, '佣金提现', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2356, '佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2357, '佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2358, '统计中心', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2359, '交易统计', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2360, '交易统计查询', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, b'1', b'1', b'1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, b'1', b'1', b'1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2368, '助力记录查询', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, b'1', b'1', b'1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, b'1', b'1', b'1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2379, '分类创建', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2380, '分类更新', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2381, '分类删除', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2382, '文章列表', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2383, '文章管理查询', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2384, '文章管理创建', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2385, '文章管理更新', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, b'1', b'1', b'1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, b'1', b'1', b'1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, b'1', b'1', b'1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, b'1', b'1', b'1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2391, '客户管理', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2397, 'CRM 系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, b'1', b'1', b'1', '1', '2023-10-29 17:08:30', '1', '2024-02-04 15:37:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2398, '合同管理', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2404, '线索管理', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2410, '商机管理', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2416, '联系人管理', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2422, '回款管理', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2428, '回款计划', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, b'1', b'1', b'1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, b'1', b'1', b'1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, b'1', b'1', b'1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, b'1', b'1', b'1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2516, '客户公海配置', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, b'1', b'1', b'1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2517, '客户公海配置保存', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2518, '客户限制配置', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2519, '客户限制配置查询', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2520, '客户限制配置创建', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2521, '客户限制配置更新', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, b'1', b'1', b'1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, b'1', b'1', b'1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, b'1', b'1', b'1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2529, '产品更新', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2530, '产品删除', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2531, '产品导出', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2532, '产品分类配置', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, b'1', b'1', b'1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2533, '产品分类查询', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2534, '产品分类创建', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2535, '产品分类更新', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2536, '产品分类删除', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2543, '关联商机', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2544, '取关商机', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2545, '商品统计', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, b'1', b'1', b'1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2546, '客户公海', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, b'1', b'1', b'1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2547, '订单查询', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2548, '订单更新', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2549, '支付&退款案例', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, b'1', b'1', b'1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2550, '转账案例', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, b'1', b'1', b'1', '1', '2024-01-18 23:51:16', '1', '2024-01-18 23:51:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2551, '钱包管理', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2552, '充值套餐', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2553, '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2554, '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2555, '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2556, '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2557, '钱包余额', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, b'1', b'1', b'1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, b'1', b'1', b'1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, b'1', b'1', b'1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, b'1', b'1', b'1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2565, '产品信息', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2566, '产品查询', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2567, '产品创建', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2568, '产品更新', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2569, '产品删除', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2570, '产品导出', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2571, '产品分类', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2572, '分类查询', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2573, '分类创建', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2574, '分类更新', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2575, '分类删除', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2576, '分类导出', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2577, '产品单位', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2578, '单位查询', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2579, '单位创建', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2580, '单位更新', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2581, '单位删除', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2582, '单位导出', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2583, '库存管理', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, b'1', b'1', b'1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2584, '仓库信息', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2585, '仓库查询', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2586, '仓库创建', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2587, '仓库更新', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2588, '仓库删除', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2589, '仓库导出', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2590, '产品库存', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, b'1', b'1', b'1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2591, '库存查询', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2592, '库存导出', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2593, '出入库明细', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, b'1', b'1', b'1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2594, '库存明细查询', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2595, '库存明细导出', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2596, '其它入库', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2597, '其它入库单查询', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2598, '其它入库单创建', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2599, '其它入库单更新', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2600, '其它入库单删除', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2601, '其它入库单导出', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2602, '采购管理', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, b'1', b'1', b'1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2603, '供应商信息', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2604, '供应商查询', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2605, '供应商创建', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2606, '供应商更新', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2607, '供应商删除', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2608, '供应商导出', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2609, '其它入库单审批', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2610, '其它出库', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2611, '其它出库单查询', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2612, '其它出库单创建', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2613, '其它出库单更新', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2614, '其它出库单删除', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2615, '其它出库单导出', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2616, '其它出库单审批', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2617, '销售管理', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, b'1', b'1', b'1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2618, '客户信息', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2619, '客户查询', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2620, '客户创建', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2621, '客户更新', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2622, '客户删除', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2623, '客户导出', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2624, '库存调拨', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2625, '库存调度单查询', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2626, '库存调度单创建', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2627, '库存调度单更新', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2628, '库存调度单删除', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2629, '库存调度单导出', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2630, '库存调度单审批', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2631, '库存盘点', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2632, '库存盘点单查询', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2633, '库存盘点单创建', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2634, '库存盘点单更新', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2635, '库存盘点单删除', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2636, '库存盘点单导出', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2637, '库存盘点单审批', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2638, '销售订单', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2639, '销售订单查询', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2640, '销售订单创建', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2641, '销售订单更新', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2642, '销售订单删除', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2643, '销售订单导出', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2644, '销售订单审批', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2645, '财务管理', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, b'1', b'1', b'1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2646, '结算账户', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2647, '结算账户查询', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2648, '结算账户创建', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2649, '结算账户更新', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2650, '结算账户删除', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2651, '结算账户导出', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2652, '销售出库', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2653, '销售出库查询', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2654, '销售出库创建', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2655, '销售出库更新', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2656, '销售出库删除', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2657, '销售出库导出', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2658, '销售出库审批', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2659, '销售退货', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2660, '销售退货查询', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2661, '销售退货创建', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2662, '销售退货更新', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2663, '销售退货删除', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2664, '销售退货导出', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2665, '销售退货审批', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2666, '采购订单', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2667, '采购订单查询', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2668, '采购订单创建', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2669, '采购订单更新', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2670, '采购订单删除', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2671, '采购订单导出', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2672, '采购订单审批', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2673, '采购入库', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2674, '采购入库查询', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2675, '采购入库创建', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2676, '采购入库更新', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2677, '采购入库删除', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2678, '采购入库导出', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2679, '采购入库审批', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2680, '采购退货', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2681, '采购退货查询', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2682, '采购退货创建', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2683, '采购退货更新', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2684, '采购退货删除', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2685, '采购退货导出', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2686, '采购退货审批', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2687, '付款单', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2688, '付款单查询', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2689, '付款单创建', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2690, '付款单更新', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2691, '付款单删除', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2692, '付款单导出', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2693, '付款单审批', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2694, '收款单', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2695, '收款单查询', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2696, '收款单创建', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2697, '收款单更新', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2698, '收款单删除', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2699, '收款单导出', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2700, '收款单审批', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2701, '待办事项', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, b'1', b'1', b'1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2702, 'ERP 首页', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, b'1', b'1', b'1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2703, '商机状态配置', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, b'1', b'1', b'1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2704, '商机状态查询', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2705, '商机状态创建', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2706, '商机状态更新', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2707, '商机状态删除', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2708, '合同配置', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, b'1', b'1', b'1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, b'1', b'1', b'1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, b'1', b'0', b'1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, b'1', b'1', b'1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, b'1', b'1', b'1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, b'1', b'1', b'1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, b'1', b'1', b'1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, b'1', b'1', b'1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, b'1', b'1', b'1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, b'1', b'1', b'1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +DROP TABLE IF EXISTS `system_notice`; +CREATE TABLE `system_notice` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '公告ID', + `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '公告标题', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '公告内容', + `type` tinyint NOT NULL COMMENT '公告类型(1通知 2公告)', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '公告状态(0正常 1关闭)', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '通知公告表'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +BEGIN; +INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', b'0', 1); +INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

\"\"11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', b'0', 1); +INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', b'0', 121); +COMMIT; + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +DROP TABLE IF EXISTS `system_notify_message`; +CREATE TABLE `system_notify_message` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `user_id` bigint NOT NULL COMMENT '用户id', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `template_id` bigint NOT NULL COMMENT '模版编号', + `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码', + `template_nickname` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版发送人名称', + `template_content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版内容', + `template_type` int NOT NULL COMMENT '模版类型', + `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版参数', + `read_status` bit(1) NOT NULL COMMENT '是否已读', + `read_time` datetime NULL DEFAULT NULL COMMENT '阅读时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信消息表'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +BEGIN; +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{\"name\":\"1\",\"what\":\"2\"}', b'1', '2023-02-10 00:47:04', '1', '2023-01-28 11:44:08', '1', '2023-02-10 00:47:04', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{\"name\":\"1\",\"what\":\"2\"}', b'1', '2023-02-10 00:47:04', '1', '2023-01-28 11:45:04', '1', '2023-02-10 00:47:04', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{\"name\":\"哈哈\"}', b'0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{\"name\":\"芋艿\",\"what\":\"写代码\"}', b'1', '2023-02-10 00:47:04', '1', '2023-01-28 22:21:42', '1', '2023-02-10 00:47:04', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{\"name\":\"芋艿\",\"what\":\"写代码\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 1, 2, 1, 'test', '123', '我是 2,我开始 3 了', 1, '{\"name\":\"2\",\"what\":\"3\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{\"name\":\"123\"}', b'1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, '{\"reason\":null,\"createTime\":\"2023-09-28 08:35:46\",\"price\":\"0.09\"}', b'0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', b'0', 1); +INSERT INTO `system_notify_message` (`id`, `user_id`, `user_type`, `template_id`, `template_code`, `template_nickname`, `template_content`, `template_type`, `template_params`, `read_status`, `read_time`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, '{\"reason\":null,\"createTime\":\"2023-09-30 20:59:40\",\"price\":\"1.00\"}', b'0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +DROP TABLE IF EXISTS `system_notify_template`; +CREATE TABLE `system_notify_template` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板名称', + `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版编码', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送人名称', + `content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模版内容', + `type` tinyint NOT NULL COMMENT '类型', + `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '参数数组', + `status` tinyint NOT NULL COMMENT '状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '站内信模板表'; + +-- ---------------------------- +-- Records of system_notify_template +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +DROP TABLE IF EXISTS `system_oauth2_access_token`; +CREATE TABLE `system_oauth2_access_token` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `user_info` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户信息', + `access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '访问令牌', + `refresh_token` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '刷新令牌', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '授权范围', + `expires_time` datetime NOT NULL COMMENT '过期时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_access_token`(`access_token` ASC) USING BTREE, + INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; + +-- ---------------------------- +-- Records of system_oauth2_access_token +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +DROP TABLE IF EXISTS `system_oauth2_approve`; +CREATE TABLE `system_oauth2_approve` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '授权范围', + `approved` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否接受', + `expires_time` datetime NOT NULL COMMENT '过期时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 82 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 批准表'; + +-- ---------------------------- +-- Records of system_oauth2_approve +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +DROP TABLE IF EXISTS `system_oauth2_client`; +CREATE TABLE `system_oauth2_client` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', + `logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用图标', + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '应用描述', + `status` tinyint NOT NULL COMMENT '状态', + `access_token_validity_seconds` int NOT NULL COMMENT '访问令牌的有效期', + `refresh_token_validity_seconds` int NOT NULL COMMENT '刷新令牌的有效期', + `redirect_uris` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '可重定向的 URI 地址', + `authorized_grant_types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '授权类型', + `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '授权范围', + `auto_approve_scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '自动通过的授权范围', + `authorities` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '权限', + `resource_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '资源', + `additional_information` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '附加信息', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 客户端表'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +BEGIN; +INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '我是描述', 0, 1800, 2592000, '[\"https://www.iocoder.cn\",\"https://doc.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[\"user.read\",\"user.write\"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2024-02-22 16:31:52', b'0'); +INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '啦啦啦啦', 0, 1800, 43200, '[\"https://www.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\"]', '[\"user_info\",\"projects\"]', '[\"user_info\"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2023-12-02 21:01:01', b'0'); +INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"authorization_code\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2022-09-29 13:28:31', b'0'); +INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"password\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2022-10-04 20:31:21', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +DROP TABLE IF EXISTS `system_oauth2_code`; +CREATE TABLE `system_oauth2_code` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '授权码', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '授权范围', + `expires_time` datetime NOT NULL COMMENT '过期时间', + `redirect_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '可重定向的 URI 地址', + `state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '状态', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 147 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 授权码表'; + +-- ---------------------------- +-- Records of system_oauth2_code +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +DROP TABLE IF EXISTS `system_oauth2_refresh_token`; +CREATE TABLE `system_oauth2_refresh_token` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `refresh_token` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '刷新令牌', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '授权范围', + `expires_time` datetime NOT NULL COMMENT '过期时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1483 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; + +-- ---------------------------- +-- Records of system_oauth2_refresh_token +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +DROP TABLE IF EXISTS `system_operate_log`; +CREATE TABLE `system_operate_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键', + `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '链路追踪编号', + `user_id` bigint NOT NULL COMMENT '用户编号', + `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作模块类型', + `sub_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作名', + `biz_id` bigint NOT NULL COMMENT '操作数据模块编号', + `action` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '操作内容', + `extra` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '拓展字段', + `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '请求方法名', + `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '请求地址', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户 IP', + `user_agent` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '浏览器 UA', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 9038 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; + +-- ---------------------------- +-- Records of system_operate_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +DROP TABLE IF EXISTS `system_post`; +CREATE TABLE `system_post` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '岗位ID', + `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '岗位编码', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '岗位名称', + `sort` int NOT NULL COMMENT '显示顺序', + `status` tinyint NOT NULL COMMENT '状态(0正常 1停用)', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '岗位信息表'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +BEGIN; +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', b'0', 1); +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', b'0', 1); +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 10:04:37', b'0', 1); +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 'HR', '人力资源', 5, 0, '', '1', '2024-03-24 20:45:40', '1', '2024-03-24 20:45:40', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +DROP TABLE IF EXISTS `system_role`; +CREATE TABLE `system_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称', + `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色权限字符串', + `sort` int NOT NULL COMMENT '显示顺序', + `data_scope` tinyint NOT NULL DEFAULT 1 COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + `data_scope_dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '数据范围(指定部门数组)', + `status` tinyint NOT NULL COMMENT '角色状态(0正常 1停用)', + `type` tinyint NOT NULL COMMENT '角色类型', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 153 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色信息表'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +BEGIN; +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', b'0', 1); +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', b'0', 1); +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', b'0', 1); +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '我想测试', '', '2021-01-06 13:49:35', '1', '2024-03-24 22:22:45', b'0', 1); +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121); +INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122); +COMMIT; + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `system_role_menu`; +CREATE TABLE `system_role_menu` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `role_id` bigint NOT NULL COMMENT '角色ID', + `menu_id` bigint NOT NULL COMMENT '菜单ID', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5779 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色和菜单关联表'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +BEGIN; +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1626, 101, 1196, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2083, 2, 1163, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2084, 2, 1164, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2085, 2, 1165, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2089, 2, 1175, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2090, 2, 1176, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2091, 2, 1177, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2142, 2, 1014, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2144, 2, 1016, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3013, 109, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3089, 111, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', b'0', 1); +INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS `system_sms_channel`; +CREATE TABLE `system_sms_channel` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `signature` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信签名', + `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渠道编码', + `status` tinyint NOT NULL COMMENT '开启状态', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `api_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信 API 的账号', + `api_secret` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信 API 的秘钥', + `callback_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信发送回调 URL', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信渠道'; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +BEGIN; +INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2023-12-02 22:10:17', b'0'); +INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', b'0'); +INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, '仅测试', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2023-12-02 22:10:08', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +DROP TABLE IF EXISTS `system_sms_code`; +CREATE TABLE `system_sms_code` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '手机号', + `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '验证码', + `create_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '创建 IP', + `scene` tinyint NOT NULL COMMENT '发送场景', + `today_index` tinyint NOT NULL COMMENT '今日发送的第几条', + `used` tinyint NOT NULL COMMENT '是否使用', + `used_time` datetime NULL DEFAULT NULL COMMENT '使用时间', + `used_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '使用 IP', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE, + INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号' +) ENGINE = InnoDB AUTO_INCREMENT = 614 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码'; + +-- ---------------------------- +-- Records of system_sms_code +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS `system_sms_log`; +CREATE TABLE `system_sms_log` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `channel_id` bigint NOT NULL COMMENT '短信渠道编号', + `channel_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信渠道编码', + `template_id` bigint NOT NULL COMMENT '模板编号', + `template_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码', + `template_type` tinyint NOT NULL COMMENT '短信类型', + `template_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信内容', + `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信参数', + `api_template_id` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信 API 的模板编号', + `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '手机号', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户编号', + `user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型', + `send_status` tinyint NOT NULL DEFAULT 0 COMMENT '发送状态', + `send_time` datetime NULL DEFAULT NULL COMMENT '发送时间', + `api_send_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信 API 发送结果的编码', + `api_send_msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信 API 发送失败的提示', + `api_request_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信 API 发送返回的唯一请求 ID', + `api_serial_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '短信 API 发送返回的序号', + `receive_status` tinyint NOT NULL DEFAULT 0 COMMENT '接收状态', + `receive_time` datetime NULL DEFAULT NULL COMMENT '接收时间', + `api_receive_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API 接收结果的编码', + `api_receive_msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'API 接收结果的说明', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 962 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; + +-- ---------------------------- +-- Records of system_sms_log +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS `system_sms_template`; +CREATE TABLE `system_sms_template` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `type` tinyint NOT NULL COMMENT '模板类型', + `status` tinyint NOT NULL COMMENT '开启状态', + `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板编码', + `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板名称', + `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板内容', + `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '参数数组', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `api_template_id` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信 API 的模板编号', + `channel_id` bigint NOT NULL COMMENT '短信渠道编号', + `channel_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信渠道编码', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信模板'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +BEGIN; +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '[\"operation\",\"code\"]', '测试备注', '4383920', 6, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2023-12-02 22:32:47', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '[\"code\"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '[\"name\"]', 'f哈哈哈', '4383920', 6, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2022-12-10 21:26:09', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '[\"name\",\"code\"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '[\"code\"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2022-12-10 21:25:59', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '[\"processInstanceName\",\"taskName\",\"startUserNickname\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '[\"processInstanceName\",\"reason\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (11, 2, 0, 'bpm_process_instance_approve', '【工作流】流程被通过', '您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', '[\"processInstanceName\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (12, 2, 0, 'demo', '演示模板', '我就是测试一下下', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2023-03-24 23:45:07', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (14, 1, 0, 'user-update-mobile', '会员用户 - 修改手机', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '[\"code\"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, 1, 0, 'user-update-password', '会员用户 - 修改密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '[\"code\"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', b'0'); +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (16, 1, 0, 'user-reset-password', '会员用户 - 重置密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '[\"code\"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +DROP TABLE IF EXISTS `system_social_client`; +CREATE TABLE `system_social_client` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', + `social_type` tinyint NOT NULL COMMENT '社交平台的类型', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', + `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `agent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '代理编号', + `status` tinyint NOT NULL COMMENT '状态', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交客户端表'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +BEGIN; +INSERT INTO `system_social_client` (`id`, `name`, `social_type`, `user_type`, `client_id`, `client_secret`, `agent_id`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '钉钉', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', b'1', 1); +INSERT INTO `system_social_client` (`id`, `name`, `social_type`, `user_type`, `client_id`, `client_secret`, `agent_id`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '钉钉(王土豆)', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', b'1', 121); +INSERT INTO `system_social_client` (`id`, `name`, `social_type`, `user_type`, `client_id`, `client_secret`, `agent_id`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, '微信公众号', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', b'1', 1); +INSERT INTO `system_social_client` (`id`, `name`, `social_type`, `user_type`, `client_id`, `client_secret`, `agent_id`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (43, '微信小程序', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', b'1', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +DROP TABLE IF EXISTS `system_social_user`; +CREATE TABLE `system_social_user` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键(自增策略)', + `type` tinyint NOT NULL COMMENT '社交平台的类型', + `openid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '社交 openid', + `token` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '社交 token', + `raw_token_info` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原始 Token 数据,一般是 JSON 格式', + `nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户昵称', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户头像', + `raw_user_info` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原始用户数据,一般是 JSON 格式', + `code` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '最后一次的认证 code', + `state` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '最后一次的认证 state', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 36 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表'; + +-- ---------------------------- +-- Records of system_social_user +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +DROP TABLE IF EXISTS `system_social_user_bind`; +CREATE TABLE `system_social_user_bind` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键(自增策略)', + `user_id` bigint NOT NULL COMMENT '用户编号', + `user_type` tinyint NOT NULL COMMENT '用户类型', + `social_type` tinyint NOT NULL COMMENT '社交平台的类型', + `social_user_id` bigint NOT NULL COMMENT '社交用户的编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 119 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表'; + +-- ---------------------------- +-- Records of system_social_user_bind +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `system_tenant`; +CREATE TABLE `system_tenant` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '租户编号', + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '租户名', + `contact_user_id` bigint NULL DEFAULT NULL COMMENT '联系人的用户编号', + `contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '联系人', + `contact_mobile` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系手机', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '租户状态(0正常 1停用)', + `website` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '绑定域名', + `package_id` bigint NOT NULL COMMENT '租户套餐编号', + `expire_time` datetime NOT NULL COMMENT '过期时间', + `account_count` int NOT NULL COMMENT '账号数量', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 162 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '租户表'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +BEGIN; +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', b'0'); +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', b'0'); +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +DROP TABLE IF EXISTS `system_tenant_package`; +CREATE TABLE `system_tenant_package` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '套餐编号', + `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '套餐名', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '租户状态(0正常 1停用)', + `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '备注', + `menu_ids` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联的菜单编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 112 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '租户套餐表'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +BEGIN; +INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-03-30 17:53:17', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `system_user_post`; +CREATE TABLE `system_user_post` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户ID', + `post_id` bigint NOT NULL DEFAULT 0 COMMENT '岗位ID', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 125 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户岗位表'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +BEGIN; +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `system_user_role`; +CREATE TABLE `system_user_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `user_id` bigint NOT NULL COMMENT '用户ID', + `role_id` bigint NOT NULL COMMENT '角色ID', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +BEGIN; +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', b'0', 121); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +DROP TABLE IF EXISTS `system_users`; +CREATE TABLE `system_users` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户账号', + `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '密码', + `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户昵称', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注', + `dept_id` bigint NULL DEFAULT NULL COMMENT '部门ID', + `post_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '岗位编号数组', + `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '用户邮箱', + `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '手机号码', + `sex` tinyint NULL DEFAULT 0 COMMENT '用户性别', + `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '头像地址', + `status` tinyint NOT NULL DEFAULT 0 COMMENT '帐号状态(0正常 1停用)', + `login_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '最后登录IP', + `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `idx_username`(`username` ASC, `update_time` ASC, `tenant_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 139 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +BEGIN; +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', b'0', 121); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', b'0', 121); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', b'0', 122); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +DROP TABLE IF EXISTS `yudao_demo01_contact`; +CREATE TABLE `yudao_demo01_contact` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字', + `sex` tinyint(1) NOT NULL COMMENT '性别', + `birthday` datetime NOT NULL COMMENT '出生年', + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '简介', + `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '示例联系人表'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +BEGIN; +INSERT INTO `yudao_demo01_contact` (`id`, `name`, `sex`, `birthday`, `description`, `avatar`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '土豆', 2, '2023-11-07 00:00:00', '

天蚕土豆!呀

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +DROP TABLE IF EXISTS `yudao_demo02_category`; +CREATE TABLE `yudao_demo02_category` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字', + `parent_id` bigint NOT NULL COMMENT '父级编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '示例分类表'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +BEGIN; +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '土豆', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', b'0', 1); +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '番茄', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', b'0', 1); +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, '怪怪', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', b'0', 1); +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '小番茄', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', b'0', 1); +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大番茄', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', b'0', 1); +INSERT INTO `yudao_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +DROP TABLE IF EXISTS `yudao_demo03_course`; +CREATE TABLE `yudao_demo03_course` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `student_id` bigint NOT NULL COMMENT '学生编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字', + `score` tinyint NOT NULL COMMENT '分数', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +BEGIN; +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', b'1', 1); +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +DROP TABLE IF EXISTS `yudao_demo03_grade`; +CREATE TABLE `yudao_demo03_grade` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `student_id` bigint NOT NULL COMMENT '学生编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字', + `teacher` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '班主任', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生班级表'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +BEGIN; +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1); +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1); +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', b'0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +DROP TABLE IF EXISTS `yudao_demo03_student`; +CREATE TABLE `yudao_demo03_student` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字', + `sex` tinyint NOT NULL COMMENT '性别', + `birthday` datetime NOT NULL COMMENT '出生日期', + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '简介', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生表'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +BEGIN; +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', b'0', 1); +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', b'0', 1); +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', b'0', 1); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/ruoyi-vue-pro-master/sql/opengauss/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/opengauss/ruoyi-vue-pro.sql new file mode 100644 index 0000000..9ff0033 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/opengauss/ruoyi-vue-pro.sql @@ -0,0 +1,4723 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : OpenGauss + + Date: 2024-06-05 07:41:22 +*/ + + +-- ---------------------------- +-- Table structure for dual +-- ---------------------------- +DROP TABLE IF EXISTS dual; +CREATE TABLE dual +( + id int2 +); + +COMMENT ON TABLE dual IS '数据库连接的表'; + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1); +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_access_log; +CREATE TABLE infra_api_access_log +( + id int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NULL DEFAULT '', + request_url varchar(255) NULL DEFAULT '', + request_params text NULL, + response_body text NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + operate_module varchar(50) NULL DEFAULT NULL, + operate_name varchar(50) NULL DEFAULT NULL, + operate_type int2 NULL DEFAULT 0, + begin_time timestamp NOT NULL, + end_time timestamp NOT NULL, + duration int4 NOT NULL, + result_code int4 NOT NULL DEFAULT 0, + result_msg varchar(512) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_access_log + ADD CONSTRAINT pk_infra_api_access_log PRIMARY KEY (id); + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time); + +COMMENT ON COLUMN infra_api_access_log.id IS '日志主键'; +COMMENT ON COLUMN infra_api_access_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN infra_api_access_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_access_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_access_log.application_name IS '应用名'; +COMMENT ON COLUMN infra_api_access_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_access_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_access_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_access_log.response_body IS '响应结果'; +COMMENT ON COLUMN infra_api_access_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_access_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_access_log.operate_module IS '操作模块'; +COMMENT ON COLUMN infra_api_access_log.operate_name IS '操作名'; +COMMENT ON COLUMN infra_api_access_log.operate_type IS '操作分类'; +COMMENT ON COLUMN infra_api_access_log.begin_time IS '开始请求时间'; +COMMENT ON COLUMN infra_api_access_log.end_time IS '结束请求时间'; +COMMENT ON COLUMN infra_api_access_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_api_access_log.result_code IS '结果码'; +COMMENT ON COLUMN infra_api_access_log.result_msg IS '结果提示'; +COMMENT ON COLUMN infra_api_access_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_access_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_access_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_access_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_access_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_access_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_access_log IS 'API 访问日志表'; + +DROP SEQUENCE IF EXISTS infra_api_access_log_seq; +CREATE SEQUENCE infra_api_access_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_error_log; +CREATE TABLE infra_api_error_log +( + id int4 NOT NULL, + trace_id varchar(64) NOT NULL, + user_id int4 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NOT NULL, + request_url varchar(255) NOT NULL, + request_params varchar(8000) NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + exception_time timestamp NOT NULL, + exception_name varchar(128) NULL DEFAULT '', + exception_message text NOT NULL, + exception_root_cause_message text NOT NULL, + exception_stack_trace text NOT NULL, + exception_class_name varchar(512) NOT NULL, + exception_file_name varchar(512) NOT NULL, + exception_method_name varchar(512) NOT NULL, + exception_line_number int4 NOT NULL, + process_status int2 NOT NULL, + process_time timestamp NULL DEFAULT NULL, + process_user_id int4 NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_error_log + ADD CONSTRAINT pk_infra_api_error_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_api_error_log.id IS '编号'; +COMMENT ON COLUMN infra_api_error_log.trace_id IS '链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。'; +COMMENT ON COLUMN infra_api_error_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_error_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_error_log.application_name IS '应用名 + * + * 目前读取 spring.application.name'; +COMMENT ON COLUMN infra_api_error_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_error_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_error_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_error_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_error_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_error_log.exception_time IS '异常发生时间'; +COMMENT ON COLUMN infra_api_error_log.exception_name IS '异常名 + * + * {@link Throwable#getClass()} 的类全名'; +COMMENT ON COLUMN infra_api_error_log.exception_message IS '异常导致的消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '异常导致的根消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '异常的栈轨迹 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}'; +COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '异常发生的类全名 + * + * {@link StackTraceElement#getClassName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '异常发生的类文件 + * + * {@link StackTraceElement#getFileName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()}'; +COMMENT ON COLUMN infra_api_error_log.process_status IS '处理状态'; +COMMENT ON COLUMN infra_api_error_log.process_time IS '处理时间'; +COMMENT ON COLUMN infra_api_error_log.process_user_id IS '处理用户编号'; +COMMENT ON COLUMN infra_api_error_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_error_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_error_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_error_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_error_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_error_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_error_log IS '系统异常日志'; + +DROP SEQUENCE IF EXISTS infra_api_error_log_seq; +CREATE SEQUENCE infra_api_error_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_column; +CREATE TABLE infra_codegen_column +( + id int8 NOT NULL, + table_id int8 NOT NULL, + column_name varchar(200) NOT NULL, + data_type varchar(100) NOT NULL, + column_comment varchar(500) NOT NULL, + nullable bool NOT NULL, + primary_key bool NOT NULL, + ordinal_position int4 NOT NULL, + java_type varchar(32) NOT NULL, + java_field varchar(64) NOT NULL, + dict_type varchar(200) NULL DEFAULT '', + example varchar(64) NULL DEFAULT NULL, + create_operation bool NOT NULL, + update_operation bool NOT NULL, + list_operation bool NOT NULL, + list_operation_condition varchar(32) NOT NULL DEFAULT '=', + list_operation_result bool NOT NULL, + html_type varchar(32) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_column + ADD CONSTRAINT pk_infra_codegen_column PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_column.id IS '编号'; +COMMENT ON COLUMN infra_codegen_column.table_id IS '表编号'; +COMMENT ON COLUMN infra_codegen_column.column_name IS '字段名'; +COMMENT ON COLUMN infra_codegen_column.data_type IS '字段类型'; +COMMENT ON COLUMN infra_codegen_column.column_comment IS '字段描述'; +COMMENT ON COLUMN infra_codegen_column.nullable IS '是否允许为空'; +COMMENT ON COLUMN infra_codegen_column.primary_key IS '是否主键'; +COMMENT ON COLUMN infra_codegen_column.ordinal_position IS '排序'; +COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java 属性类型'; +COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java 属性名'; +COMMENT ON COLUMN infra_codegen_column.dict_type IS '字典类型'; +COMMENT ON COLUMN infra_codegen_column.example IS '数据示例'; +COMMENT ON COLUMN infra_codegen_column.create_operation IS '是否为 Create 创建操作的字段'; +COMMENT ON COLUMN infra_codegen_column.update_operation IS '是否为 Update 更新操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation IS '是否为 List 查询操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List 查询操作的条件类型'; +COMMENT ON COLUMN infra_codegen_column.list_operation_result IS '是否为 List 查询操作的返回字段'; +COMMENT ON COLUMN infra_codegen_column.html_type IS '显示类型'; +COMMENT ON COLUMN infra_codegen_column.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_column.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_column.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_column.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_column.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_column IS '代码生成表字段定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_column_seq; +CREATE SEQUENCE infra_codegen_column_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_table; +CREATE TABLE infra_codegen_table +( + id int8 NOT NULL, + data_source_config_id int8 NOT NULL, + scene int2 NOT NULL DEFAULT 1, + table_name varchar(200) NULL DEFAULT '', + table_comment varchar(500) NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + module_name varchar(30) NOT NULL, + business_name varchar(30) NOT NULL, + class_name varchar(100) NULL DEFAULT '', + class_comment varchar(50) NOT NULL, + author varchar(50) NOT NULL, + template_type int2 NOT NULL DEFAULT 1, + front_type int2 NOT NULL, + parent_menu_id int8 NULL DEFAULT NULL, + master_table_id int8 NULL DEFAULT NULL, + sub_join_column_id int8 NULL DEFAULT NULL, + sub_join_many bool NULL DEFAULT NULL, + tree_parent_column_id int8 NULL DEFAULT NULL, + tree_name_column_id int8 NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_table + ADD CONSTRAINT pk_infra_codegen_table PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_table.id IS '编号'; +COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS '数据源配置的编号'; +COMMENT ON COLUMN infra_codegen_table.scene IS '生成场景'; +COMMENT ON COLUMN infra_codegen_table.table_name IS '表名称'; +COMMENT ON COLUMN infra_codegen_table.table_comment IS '表描述'; +COMMENT ON COLUMN infra_codegen_table.remark IS '备注'; +COMMENT ON COLUMN infra_codegen_table.module_name IS '模块名'; +COMMENT ON COLUMN infra_codegen_table.business_name IS '业务名'; +COMMENT ON COLUMN infra_codegen_table.class_name IS '类名称'; +COMMENT ON COLUMN infra_codegen_table.class_comment IS '类描述'; +COMMENT ON COLUMN infra_codegen_table.author IS '作者'; +COMMENT ON COLUMN infra_codegen_table.template_type IS '模板类型'; +COMMENT ON COLUMN infra_codegen_table.front_type IS '前端类型'; +COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '父菜单编号'; +COMMENT ON COLUMN infra_codegen_table.master_table_id IS '主表的编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS '子表关联主表的字段编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_many IS '主表与子表是否一对多'; +COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS '树表的父字段编号'; +COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS '树表的名字字段编号'; +COMMENT ON COLUMN infra_codegen_table.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_table.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_table.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_table.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_table.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_table IS '代码生成表定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_table_seq; +CREATE SEQUENCE infra_codegen_table_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_config; +CREATE TABLE infra_config +( + id int4 NOT NULL, + category varchar(50) NOT NULL, + type int2 NOT NULL, + name varchar(100) NULL DEFAULT '', + config_key varchar(100) NULL DEFAULT '', + value varchar(500) NULL DEFAULT '', + visible bool NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_config + ADD CONSTRAINT pk_infra_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_config.id IS '参数主键'; +COMMENT ON COLUMN infra_config.category IS '参数分组'; +COMMENT ON COLUMN infra_config.type IS '参数类型'; +COMMENT ON COLUMN infra_config.name IS '参数名称'; +COMMENT ON COLUMN infra_config.config_key IS '参数键名'; +COMMENT ON COLUMN infra_config.value IS '参数键值'; +COMMENT ON COLUMN infra_config.visible IS '是否可见'; +COMMENT ON COLUMN infra_config.remark IS '备注'; +COMMENT ON COLUMN infra_config.creator IS '创建者'; +COMMENT ON COLUMN infra_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_config.updater IS '更新者'; +COMMENT ON COLUMN infra_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_config IS '参数配置表'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, '用户管理-账号初始密码', 'sys.user.init-password', '123456', '0', '初始化密码 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-04-03 17:22:28', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL 监控的地址', 'url.druid', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking 监控的地址', 'url.skywalking', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin 监控的地址', 'url.spring-boot-admin', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger 接口文档的地址', 'url.swagger', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, 'ui', 2, '腾讯地图 key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', '1', '腾讯地图 key', '1', '2023-06-03 19:16:27', '1', '2023-06-03 19:16:27', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', '2023-12-03 09:55:16', '1', '2023-12-03 09:55:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_config_seq; +CREATE SEQUENCE infra_config_seq + START 13; + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_data_source_config; +CREATE TABLE infra_data_source_config +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + url varchar(1024) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_data_source_config + ADD CONSTRAINT pk_infra_data_source_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_data_source_config.id IS '主键编号'; +COMMENT ON COLUMN infra_data_source_config.name IS '参数名称'; +COMMENT ON COLUMN infra_data_source_config.url IS '数据源连接'; +COMMENT ON COLUMN infra_data_source_config.username IS '用户名'; +COMMENT ON COLUMN infra_data_source_config.password IS '密码'; +COMMENT ON COLUMN infra_data_source_config.creator IS '创建者'; +COMMENT ON COLUMN infra_data_source_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_data_source_config.updater IS '更新者'; +COMMENT ON COLUMN infra_data_source_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_data_source_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_data_source_config IS '数据源配置表'; + +DROP SEQUENCE IF EXISTS infra_data_source_config_seq; +CREATE SEQUENCE infra_data_source_config_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +DROP TABLE IF EXISTS infra_file; +CREATE TABLE infra_file +( + id int8 NOT NULL, + config_id int8 NULL DEFAULT NULL, + name varchar(256) NULL DEFAULT NULL, + path varchar(512) NOT NULL, + url varchar(1024) NOT NULL, + type varchar(128) NULL DEFAULT NULL, + size int4 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file + ADD CONSTRAINT pk_infra_file PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file.id IS '文件编号'; +COMMENT ON COLUMN infra_file.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file.name IS '文件名'; +COMMENT ON COLUMN infra_file.path IS '文件路径'; +COMMENT ON COLUMN infra_file.url IS '文件 URL'; +COMMENT ON COLUMN infra_file.type IS '文件类型'; +COMMENT ON COLUMN infra_file.size IS '文件大小'; +COMMENT ON COLUMN infra_file.creator IS '创建者'; +COMMENT ON COLUMN infra_file.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file.updater IS '更新者'; +COMMENT ON COLUMN infra_file.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file.deleted IS '是否删除'; +COMMENT ON TABLE infra_file IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_seq; +CREATE SEQUENCE infra_file_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_config; +CREATE TABLE infra_file_config +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + storage int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + master bool NOT NULL, + config varchar(4096) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_config + ADD CONSTRAINT pk_infra_file_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_config.id IS '编号'; +COMMENT ON COLUMN infra_file_config.name IS '配置名'; +COMMENT ON COLUMN infra_file_config.storage IS '存储器'; +COMMENT ON COLUMN infra_file_config.remark IS '备注'; +COMMENT ON COLUMN infra_file_config.master IS '是否为主配置'; +COMMENT ON COLUMN infra_file_config.config IS '存储配置'; +COMMENT ON COLUMN infra_file_config.creator IS '创建者'; +COMMENT ON COLUMN infra_file_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_config.updater IS '更新者'; +COMMENT ON COLUMN infra_file_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_config IS '文件配置表'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_file_config_seq; +CREATE SEQUENCE infra_file_config_seq + START 23; + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_content; +CREATE TABLE infra_file_content +( + id int8 NOT NULL, + config_id int8 NOT NULL, + path varchar(512) NOT NULL, + content bytea NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_content + ADD CONSTRAINT pk_infra_file_content PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_content.id IS '编号'; +COMMENT ON COLUMN infra_file_content.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file_content.path IS '文件路径'; +COMMENT ON COLUMN infra_file_content.content IS '文件内容'; +COMMENT ON COLUMN infra_file_content.creator IS '创建者'; +COMMENT ON COLUMN infra_file_content.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_content.updater IS '更新者'; +COMMENT ON COLUMN infra_file_content.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_content.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_content IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_content_seq; +CREATE SEQUENCE infra_file_content_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +DROP TABLE IF EXISTS infra_job; +CREATE TABLE infra_job +( + id int8 NOT NULL, + name varchar(32) NOT NULL, + status int2 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + cron_expression varchar(32) NOT NULL, + retry_count int4 NOT NULL DEFAULT 0, + retry_interval int4 NOT NULL DEFAULT 0, + monitor_timeout int4 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job + ADD CONSTRAINT pk_infra_job PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job.id IS '任务编号'; +COMMENT ON COLUMN infra_job.name IS '任务名称'; +COMMENT ON COLUMN infra_job.status IS '任务状态'; +COMMENT ON COLUMN infra_job.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job.cron_expression IS 'CRON 表达式'; +COMMENT ON COLUMN infra_job.retry_count IS '重试次数'; +COMMENT ON COLUMN infra_job.retry_interval IS '重试间隔'; +COMMENT ON COLUMN infra_job.monitor_timeout IS '监控超时时间'; +COMMENT ON COLUMN infra_job.creator IS '创建者'; +COMMENT ON COLUMN infra_job.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job.updater IS '更新者'; +COMMENT ON COLUMN infra_job.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job.deleted IS '是否删除'; +COMMENT ON TABLE infra_job IS '定时任务表'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_job_seq; +CREATE SEQUENCE infra_job_seq + START 28; + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_job_log; +CREATE TABLE infra_job_log +( + id int8 NOT NULL, + job_id int8 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + execute_index int2 NOT NULL DEFAULT 1, + begin_time timestamp NOT NULL, + end_time timestamp NULL DEFAULT NULL, + duration int4 NULL DEFAULT NULL, + status int2 NOT NULL, + result varchar(4000) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job_log + ADD CONSTRAINT pk_infra_job_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job_log.id IS '日志编号'; +COMMENT ON COLUMN infra_job_log.job_id IS '任务编号'; +COMMENT ON COLUMN infra_job_log.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job_log.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job_log.execute_index IS '第几次执行'; +COMMENT ON COLUMN infra_job_log.begin_time IS '开始执行时间'; +COMMENT ON COLUMN infra_job_log.end_time IS '结束执行时间'; +COMMENT ON COLUMN infra_job_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_job_log.status IS '任务状态'; +COMMENT ON COLUMN infra_job_log.result IS '结果数据'; +COMMENT ON COLUMN infra_job_log.creator IS '创建者'; +COMMENT ON COLUMN infra_job_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job_log.updater IS '更新者'; +COMMENT ON COLUMN infra_job_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job_log.deleted IS '是否删除'; +COMMENT ON TABLE infra_job_log IS '定时任务日志表'; + +DROP SEQUENCE IF EXISTS infra_job_log_seq; +CREATE SEQUENCE infra_job_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +DROP TABLE IF EXISTS system_dept; +CREATE TABLE system_dept +( + id int8 NOT NULL, + name varchar(30) NULL DEFAULT '', + parent_id int8 NOT NULL DEFAULT 0, + sort int4 NOT NULL DEFAULT 0, + leader_user_id int8 NULL DEFAULT NULL, + phone varchar(11) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dept + ADD CONSTRAINT pk_system_dept PRIMARY KEY (id); + +COMMENT ON COLUMN system_dept.id IS '部门id'; +COMMENT ON COLUMN system_dept.name IS '部门名称'; +COMMENT ON COLUMN system_dept.parent_id IS '父部门id'; +COMMENT ON COLUMN system_dept.sort IS '显示顺序'; +COMMENT ON COLUMN system_dept.leader_user_id IS '负责人'; +COMMENT ON COLUMN system_dept.phone IS '联系电话'; +COMMENT ON COLUMN system_dept.email IS '邮箱'; +COMMENT ON COLUMN system_dept.status IS '部门状态(0正常 1停用)'; +COMMENT ON COLUMN system_dept.creator IS '创建者'; +COMMENT ON COLUMN system_dept.create_time IS '创建时间'; +COMMENT ON COLUMN system_dept.updater IS '更新者'; +COMMENT ON COLUMN system_dept.update_time IS '更新时间'; +COMMENT ON COLUMN system_dept.deleted IS '是否删除'; +COMMENT ON COLUMN system_dept.tenant_id IS '租户编号'; +COMMENT ON TABLE system_dept IS '部门表'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, '运维部门', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', '0', 121); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', '0', 122); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, '产品部门', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, '支持部门', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2023-12-02 09:47:38', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dept_seq; +CREATE SEQUENCE system_dept_seq + START 114; + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_data; +CREATE TABLE system_dict_data +( + id int8 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + label varchar(100) NULL DEFAULT '', + value varchar(100) NULL DEFAULT '', + dict_type varchar(100) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + color_type varchar(100) NULL DEFAULT '', + css_class varchar(100) NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dict_data + ADD CONSTRAINT pk_system_dict_data PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_data.id IS '字典编码'; +COMMENT ON COLUMN system_dict_data.sort IS '字典排序'; +COMMENT ON COLUMN system_dict_data.label IS '字典标签'; +COMMENT ON COLUMN system_dict_data.value IS '字典键值'; +COMMENT ON COLUMN system_dict_data.dict_type IS '字典类型'; +COMMENT ON COLUMN system_dict_data.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_data.color_type IS '颜色类型'; +COMMENT ON COLUMN system_dict_data.css_class IS 'css 样式'; +COMMENT ON COLUMN system_dict_data.remark IS '备注'; +COMMENT ON COLUMN system_dict_data.creator IS '创建者'; +COMMENT ON COLUMN system_dict_data.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_data.updater IS '更新者'; +COMMENT ON COLUMN system_dict_data.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_data.deleted IS '是否删除'; +COMMENT ON TABLE system_dict_data IS '字典数据表'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, '自定义', '2', 'infra_config_type', 0, 'primary', '', '参数类型 - 自定义', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '通知', '1', 'system_notice_type', 0, 'success', '', '通知', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '公告', '2', 'system_notice_type', 0, 'info', '', '公告', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '其它', '0', 'infra_operate_type', 0, 'default', '', '其它操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, '查询', '1', 'infra_operate_type', 0, 'info', '', '查询操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '新增', '2', 'infra_operate_type', 0, 'primary', '', '新增操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '修改', '3', 'infra_operate_type', 0, 'warning', '', '修改操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, '删除', '4', 'infra_operate_type', 0, 'danger', '', '删除操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '导出', '5', 'infra_operate_type', 0, 'default', '', '导出操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '导入', '6', 'infra_operate_type', 0, 'default', '', '导入操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '开启', '0', 'common_status', 0, 'primary', '', '开启状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, '关闭', '1', 'common_status', 0, 'info', '', '关闭状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, '目录', '1', 'system_menu_type', 0, '', '', '目录', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '菜单', '2', 'system_menu_type', 0, '', '', '菜单', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, '按钮', '3', 'system_menu_type', 0, '', '', '按钮', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '内置', '1', 'system_role_type', 0, 'danger', '', '内置角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, '自定义', '2', 'system_role_type', 0, 'primary', '', '自定义角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, '全部数据权限', '1', 'system_data_scope', 0, '', '', '全部数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, '指定部门数据权限', '2', 'system_data_scope', 0, '', '', '指定部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '验证码不存在', '30', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不存在', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '验证码不正确', '31', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, '未知异常', '100', 'system_login_result', 0, 'danger', '', '登陆结果 - 未知异常', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '是', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 是否类型 - 是', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '否', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 是否类型 - 否', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, '单表(增删改查)', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, '树表(增删改查)', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, '初始化中', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '运行中', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, '成功', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, '失败', '2', 'infra_job_log_status', 0, 'warning', '', '失败', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, '会员', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, '管理员', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2022-02-16 10:22:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, '营销', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, '初始化', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, '发送成功', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, '发送失败', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '不发送', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, '等待结果', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '支付宝 PC 网站支付', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '支付宝 PC 网站支付', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, '本地磁盘', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP 服务器', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP 服务器', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 对象存储', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, '短信登录', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '密码模式', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '授权码模式', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '简化模式', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '客户端模式', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '刷新模式', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '销售中', '1', 'product_spu_status', 0, 'success', '', '商品 SPU 状态 - 销售中', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, '仓库中', '0', 'product_spu_status', 0, 'info', '', '商品 SPU 状态 - 仓库中', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, '回收站', '-1', 'product_spu_status', 0, 'default', '', '商品 SPU 状态 - 回收站', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '满减', '1', 'promotion_discount_type', 0, 'success', '', '优惠类型 - 满减', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, '通用劵', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, '商品劵', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, '未使用', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, '直接领取', '1', 'promotion_coupon_take_type', 0, 'primary', '', '优惠劵的领取方式 - 直接领取', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, '指定发放', '2', 'promotion_coupon_take_type', 0, 'success', '', '优惠劵的领取方式 - 指定发放', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, '未开始', '10', 'promotion_activity_status', 0, 'primary', '', '促销活动的状态枚举 - 未开始', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '进行中', '20', 'promotion_activity_status', 0, 'success', '', '促销活动的状态枚举 - 进行中', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, '已结束', '30', 'promotion_activity_status', 0, 'info', '', '促销活动的状态枚举 - 已结束', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, '已关闭', '40', 'promotion_activity_status', 0, 'warning', '', '促销活动的状态枚举 - 已关闭', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, '满 N 元', '10', 'promotion_condition_type', 0, 'primary', '', '营销的条件类型 - 满 N 元', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, '满 N 件', '20', 'promotion_condition_type', 0, 'success', '', '营销的条件类型 - 满 N 件', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, '申请售后', '10', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 申请售后', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, '商品待退货', '20', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商品待退货', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '商家待收货', '30', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商家待收货', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, '等待退款', '40', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 等待退款', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '退款成功', '50', 'trade_after_sale_status', 0, 'default', '', '交易售后状态 - 退款成功', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, '买家取消', '61', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 买家取消', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '商家拒绝', '62', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒绝', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '商家拒收货', '63', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒收货', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '售中退款', '10', 'trade_after_sale_type', 0, 'success', '', '交易售后的类型 - 售中退款', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, '售后退款', '20', 'trade_after_sale_type', 0, 'primary', '', '交易售后的类型 - 售后退款', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '仅退款', '10', 'trade_after_sale_way', 0, 'primary', '', '交易售后的方式 - 仅退款', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '退货退款', '20', 'trade_after_sale_way', 0, 'success', '', '交易售后的方式 - 退货退款', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '微信小程序', '10', 'terminal', 0, 'default', '', '终端 - 微信小程序', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 网页', '20', 'terminal', 0, 'default', '', '终端 - H5 网页', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '微信公众号', '11', 'terminal', 0, 'default', '', '终端 - 微信公众号', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, '苹果 App', '31', 'terminal', 0, 'default', '', '终端 - 苹果 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '已完成', '30', 'trade_order_status', 0, 'success', '', '交易订单状态 - 已完成', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, '已取消', '40', 'trade_order_status', 0, 'danger', '', '交易订单状态 - 已取消', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, '未售后', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '交易订单项的售后状态 - 未售后', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, '售后中', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '交易订单项的售后状态 - 售后中', '1', '2022-12-10 20:59:21', '1', '2022-12-10 20:59:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, '已退款', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '交易订单项的售后状态 - 已退款', '1', '2022-12-10 20:59:46', '1', '2022-12-10 20:59:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, '完全匹配', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '公众号自动回复的请求关键字匹配模式 - 完全匹配', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, '半匹配', '2', 'mp_auto_reply_request_match', 0, 'success', '', '公众号自动回复的请求关键字匹配模式 - 半匹配', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, '文本', 'text', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 文本', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, '图片', 'image', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图片', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '语音', 'voice', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 语音', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, '视频', 'video', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, '小视频', 'shortvideo', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 小视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, '图文', 'news', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图文', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '音乐', 'music', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 音乐', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, '地理位置', 'location', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 地理位置', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '链接', 'link', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 链接', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '事件', 'event', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 事件', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, '初始化', '0', 'system_mail_send_status', 0, 'primary', '', '邮件发送状态 - 初始化\n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, '订单积分抵扣', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, '签到', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '已退款', '20', 'pay_order_status', 0, 'danger', '', '已退款', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, '请求成功,但是结果失败', '21', 'pay_notify_status', 0, 'warning', '', '请求成功,但是结果失败', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, '请求失败', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '微信扫码支付', 'wx_native', 'pay_channel_code', 0, 'success', '', '微信扫码支付', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '微信条码支付', 'wx_bar', 'pay_channel_code', 0, 'success', '', '微信条码支付\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '支付单', '1', 'pay_notify_type', 0, 'primary', '', '支付单', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, '订单积分抵扣(整单取消)', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, '下单奖励', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, '下单奖励(整单取消)', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, '品类劵', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '人人分销', '1', 'brokerage_enabled_condition', 0, '', '', '所有用户都可以分销', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, '指定分销', '2', 'brokerage_enabled_condition', 0, '', '', '仅可后台手动设置推广员', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '首次绑定', '1', 'brokerage_bind_mode', 0, '', '', '只要用户没有推广人,随时都可以绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, '注册绑定', '2', 'brokerage_bind_mode', 0, '', '', '仅新用户注册时才能绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, '申请提现驳回', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '待结算', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, '已结算', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, '已取消', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '审核中', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, '审核通过', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, '提现成功', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '审核不通过', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, '提现失败', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '工商银行', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '建设银行', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, '农业银行', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, '中国银行', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, '交通银行', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '招商银行', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, '钱包', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '支付宝', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '微信支付', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '其他', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, '金融业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, '房地产', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, '商业服务', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '运输/物流', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '生产', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '政府', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, '文化传媒', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '负责人', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, '只读', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, '读写', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, '未提交', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '审批中', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, '审核通过', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '审核不通过', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, '已取消', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '支票', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, '现金', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '邮政汇款', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '电汇', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '个', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '块', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, '只', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '把', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, '枚', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, '瓶', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '盒', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '台', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '吨', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, '千克', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '米', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '箱', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '套', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '打电话', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '发短信', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, '上门拜访', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '微信沟通', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '其它入库', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '其它入库(作废)', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '其它出库', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '其它出库(作废)', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, '未审核', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '已审核', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '调拨入库', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '调拨入库(作废)', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '调拨出库', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '调拨出库(作废)', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, '盘盈入库', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, '盘盈入库(作废)', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '盘亏出库', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '盘亏出库(作废)', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '销售出库', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '销售出库(作废)', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '销售退货入库', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '销售退货入库(作废)', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, '采购入库', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '天', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '周', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_data_seq; +CREATE SEQUENCE system_dict_data_seq + START 1537; + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_type; +CREATE TABLE system_dict_type +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + type varchar(100) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + deleted_time timestamp NULL DEFAULT NULL +); + +ALTER TABLE system_dict_type + ADD CONSTRAINT pk_system_dict_type PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_type.id IS '字典主键'; +COMMENT ON COLUMN system_dict_type.name IS '字典名称'; +COMMENT ON COLUMN system_dict_type.type IS '字典类型'; +COMMENT ON COLUMN system_dict_type.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_type.remark IS '备注'; +COMMENT ON COLUMN system_dict_type.creator IS '创建者'; +COMMENT ON COLUMN system_dict_type.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_type.updater IS '更新者'; +COMMENT ON COLUMN system_dict_type.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_type.deleted IS '是否删除'; +COMMENT ON COLUMN system_dict_type.deleted_time IS '删除时间'; +COMMENT ON TABLE system_dict_type IS '字典类型表'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '操作类型', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '登陆结果', 'system_login_result', 0, '登陆结果', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, '代码生成模板类型', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, '定时任务状态', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, '定时任务日志状态', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 异常数据的处理状态', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '短信渠道编码', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 授权类型', 'system_oauth2_grant_type', 0, 'OAuth 2.0 授权类型(模式)', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, '商品 SPU 状态', 'product_spu_status', 0, '商品 SPU 状态', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, '优惠类型', 'promotion_discount_type', 0, '优惠类型', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, '优惠劵模板的有限期类型', 'promotion_coupon_template_validity_type', 0, '优惠劵模板的有限期类型', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, '营销的商品范围', 'promotion_product_scope', 0, '营销的商品范围', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, '优惠劵的状态', 'promotion_coupon_status', 0, '优惠劵的状态', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, '优惠劵的领取方式', 'promotion_coupon_take_type', 0, '优惠劵的领取方式', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '促销活动的状态', 'promotion_activity_status', 0, '促销活动的状态', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, '营销的条件类型', 'promotion_condition_type', 0, '营销的条件类型', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, '交易售后状态', 'trade_after_sale_status', 0, '交易售后状态', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, '交易售后的类型', 'trade_after_sale_type', 0, '交易售后的类型', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, '交易售后的方式', 'trade_after_sale_way', 0, '交易售后的方式', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, '终端', 'terminal', 0, '终端', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '交易订单的类型', 'trade_order_type', 0, '交易订单的类型', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '交易订单的状态', 'trade_order_status', 0, '交易订单的状态', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '交易订单项的售后状态', 'trade_order_item_after_sale_status', 0, '交易订单项的售后状态', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, '代码生成的前端类型', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, '分佣模式', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, '分销关系绑定模式', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, '佣金提现类型', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, '佣金记录业务类型', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, '佣金记录状态', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, '佣金提现状态', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, '回款-回款方式', 'crm_receivable_return_type', 0, '回款-回款方式', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM 客户行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM 数据权限的级别', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM 审批状态', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM 产品单位', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM 跟进方式', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', '0', '1970-01-01 00:00:00'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_type_seq; +CREATE SEQUENCE system_dict_type_seq + START 620; + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +DROP TABLE IF EXISTS system_login_log; +CREATE TABLE system_login_log +( + id int8 NOT NULL, + log_type int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + username varchar(50) NULL DEFAULT '', + result int2 NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_login_log + ADD CONSTRAINT pk_system_login_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_login_log.id IS '访问ID'; +COMMENT ON COLUMN system_login_log.log_type IS '日志类型'; +COMMENT ON COLUMN system_login_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_login_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_login_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_login_log.username IS '用户账号'; +COMMENT ON COLUMN system_login_log.result IS '登陆结果'; +COMMENT ON COLUMN system_login_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_login_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_login_log.creator IS '创建者'; +COMMENT ON COLUMN system_login_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_login_log.updater IS '更新者'; +COMMENT ON COLUMN system_login_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_login_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_login_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_login_log IS '系统访问记录'; + +DROP SEQUENCE IF EXISTS system_login_log_seq; +CREATE SEQUENCE system_login_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_account; +CREATE TABLE system_mail_account +( + id int8 NOT NULL, + mail varchar(255) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + host varchar(255) NOT NULL, + port int4 NOT NULL, + ssl_enable bool NOT NULL DEFAULT '0', + starttls_enable bool NOT NULL DEFAULT '0', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_account + ADD CONSTRAINT pk_system_mail_account PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_account.id IS '主键'; +COMMENT ON COLUMN system_mail_account.mail IS '邮箱'; +COMMENT ON COLUMN system_mail_account.username IS '用户名'; +COMMENT ON COLUMN system_mail_account.password IS '密码'; +COMMENT ON COLUMN system_mail_account.host IS 'SMTP 服务器域名'; +COMMENT ON COLUMN system_mail_account.port IS 'SMTP 服务器端口'; +COMMENT ON COLUMN system_mail_account.ssl_enable IS '是否开启 SSL'; +COMMENT ON COLUMN system_mail_account.starttls_enable IS '是否开启 STARTTLS'; +COMMENT ON COLUMN system_mail_account.creator IS '创建者'; +COMMENT ON COLUMN system_mail_account.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_account.updater IS '更新者'; +COMMENT ON COLUMN system_mail_account.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_account.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_account IS '邮箱账号表'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', '1'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', '1'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_account_seq; +CREATE SEQUENCE system_mail_account_seq + START 5; + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_log; +CREATE TABLE system_mail_log +( + id int8 NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + to_mail varchar(255) NOT NULL, + account_id int8 NOT NULL, + from_mail varchar(255) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_nickname varchar(255) NULL DEFAULT NULL, + template_title varchar(255) NOT NULL, + template_content varchar(10240) NOT NULL, + template_params varchar(255) NOT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + send_message_id varchar(255) NULL DEFAULT NULL, + send_exception varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_log + ADD CONSTRAINT pk_system_mail_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_log.id IS '编号'; +COMMENT ON COLUMN system_mail_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_mail_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_mail_log.to_mail IS '接收邮箱地址'; +COMMENT ON COLUMN system_mail_log.account_id IS '邮箱账号编号'; +COMMENT ON COLUMN system_mail_log.from_mail IS '发送邮箱地址'; +COMMENT ON COLUMN system_mail_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_mail_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_mail_log.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_mail_log.template_title IS '邮件标题'; +COMMENT ON COLUMN system_mail_log.template_content IS '邮件内容'; +COMMENT ON COLUMN system_mail_log.template_params IS '邮件参数'; +COMMENT ON COLUMN system_mail_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_mail_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_mail_log.send_message_id IS '发送返回的消息 ID'; +COMMENT ON COLUMN system_mail_log.send_exception IS '发送异常'; +COMMENT ON COLUMN system_mail_log.creator IS '创建者'; +COMMENT ON COLUMN system_mail_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_log.updater IS '更新者'; +COMMENT ON COLUMN system_mail_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_log.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_log IS '邮件日志表'; + +DROP SEQUENCE IF EXISTS system_mail_log_seq; +CREATE SEQUENCE system_mail_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_template; +CREATE TABLE system_mail_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(63) NOT NULL, + account_id int8 NOT NULL, + nickname varchar(255) NULL DEFAULT NULL, + title varchar(255) NOT NULL, + content varchar(10240) NOT NULL, + params varchar(255) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_template + ADD CONSTRAINT pk_system_mail_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_template.id IS '编号'; +COMMENT ON COLUMN system_mail_template.name IS '模板名称'; +COMMENT ON COLUMN system_mail_template.code IS '模板编码'; +COMMENT ON COLUMN system_mail_template.account_id IS '发送的邮箱账号编号'; +COMMENT ON COLUMN system_mail_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_mail_template.title IS '模板标题'; +COMMENT ON COLUMN system_mail_template.content IS '模板内容'; +COMMENT ON COLUMN system_mail_template.params IS '参数数组'; +COMMENT ON COLUMN system_mail_template.status IS '开启状态'; +COMMENT ON COLUMN system_mail_template.remark IS '备注'; +COMMENT ON COLUMN system_mail_template.creator IS '创建者'; +COMMENT ON COLUMN system_mail_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_template.updater IS '更新者'; +COMMENT ON COLUMN system_mail_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_template.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_template IS '邮件模版表'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '

您的验证码是{code},名字是{name}

', '["code","name"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', '["key01","key02"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_template_seq; +CREATE SEQUENCE system_mail_template_seq + START 16; + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_menu; +CREATE TABLE system_menu +( + id int8 NOT NULL, + name varchar(50) NOT NULL, + permission varchar(100) NULL DEFAULT '', + type int2 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + parent_id int8 NOT NULL DEFAULT 0, + path varchar(200) NULL DEFAULT '', + icon varchar(100) NULL DEFAULT '#', + component varchar(255) NULL DEFAULT NULL, + component_name varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + visible bool NOT NULL DEFAULT '1', + keep_alive bool NOT NULL DEFAULT '1', + always_show bool NOT NULL DEFAULT '1', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_menu + ADD CONSTRAINT pk_system_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_menu.id IS '菜单ID'; +COMMENT ON COLUMN system_menu.name IS '菜单名称'; +COMMENT ON COLUMN system_menu.permission IS '权限标识'; +COMMENT ON COLUMN system_menu.type IS '菜单类型'; +COMMENT ON COLUMN system_menu.sort IS '显示顺序'; +COMMENT ON COLUMN system_menu.parent_id IS '父菜单ID'; +COMMENT ON COLUMN system_menu.path IS '路由地址'; +COMMENT ON COLUMN system_menu.icon IS '菜单图标'; +COMMENT ON COLUMN system_menu.component IS '组件路径'; +COMMENT ON COLUMN system_menu.component_name IS '组件名'; +COMMENT ON COLUMN system_menu.status IS '菜单状态'; +COMMENT ON COLUMN system_menu.visible IS '是否可见'; +COMMENT ON COLUMN system_menu.keep_alive IS '是否缓存'; +COMMENT ON COLUMN system_menu.always_show IS '是否总是显示'; +COMMENT ON COLUMN system_menu.creator IS '创建者'; +COMMENT ON COLUMN system_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_menu.updater IS '更新者'; +COMMENT ON COLUMN system_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_menu.deleted IS '是否删除'; +COMMENT ON TABLE system_menu IS '菜单权限表'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '报表管理', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, '1', '1', '1', '1', '2022-07-10 20:26:36', '1', '2024-02-29 12:33:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, '商品中心', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, '优惠劵模板更新', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, '优惠劵模板删除', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, '限时折扣活动删除', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, '限时折扣活动关闭', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, '秒杀商品', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, '秒杀活动查询', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, '秒杀活动创建', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, '秒杀活动更新', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, '秒杀活动删除', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, '秒杀时段', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, '秒杀时段查询', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '订单中心', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, '售后退款', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, '秒杀活动关闭', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, '订单列表', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '新增账号', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '修改账号', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, '查询账号', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, '删除账号', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, '生成二维码', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, '清空 API 配额', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, '数据统计', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, '标签管理', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, '查询标签', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, '新增标签', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '修改标签', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, '删除标签', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, '同步标签', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '粉丝管理', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, '查询粉丝', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '修改粉丝', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, '同步粉丝', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, '消息管理', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, '图文发表记录', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, '查询发布列表', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, '发布草稿', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, '删除发布记录', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, '图文草稿箱', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '新建草稿', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '修改草稿', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, '查询草稿', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, '删除草稿', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, '素材管理', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, '上传临时素材', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, '上传永久素材', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, '删除素材', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, '上传图文图片', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, '查询素材', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '菜单管理', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', '2023-01-14 17:43:54', '1', '2024-02-29 12:42:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, '自动回复', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, '查询回复', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, '新增回复', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '修改回复', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, '删除回复', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, '查询菜单', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '保存菜单', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, '1', '1', '1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot 开发文档', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:46:28', '1', '2023-12-02 21:32:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, '接入示例', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '配送管理', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, '自提门店删除', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, '会员积分', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, '回调通知', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, '拼团活动', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, '拼团商品', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, '拼团活动查询', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, '拼团活动创建', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, '拼团活动更新', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, '拼团活动删除', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, '拼团活动关闭', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, '砍价活动', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, '砍价商品', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, '砍价活动查询', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, '砍价活动创建', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, '会员标签查询', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, '会员分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '交易配置', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, '交易中心配置查询', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, '交易中心配置保存', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '分销管理', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, '分销用户', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, '分销用户查询', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, '分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, '分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, '分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, '分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, '分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, '佣金记录', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, '佣金记录查询', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, '佣金提现', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, '佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, '佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, '统计中心', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, '交易统计', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, '交易统计查询', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '助力记录查询', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, '分类创建', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '分类更新', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, '分类删除', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, '文章列表', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '文章管理查询', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '文章管理创建', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '文章管理更新', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, '客户管理', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM 系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, '1', '1', '1', '1', '2023-10-29 17:08:30', '1', '2024-02-04 15:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, '合同管理', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '线索管理', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '商机管理', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, '联系人管理', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, '回款管理', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, '回款计划', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, '客户公海配置', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, '客户公海配置保存', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, '客户限制配置', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, '客户限制配置查询', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, '客户限制配置创建', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, '客户限制配置更新', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, '产品更新', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, '产品删除', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, '产品导出', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, '产品分类配置', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, '产品分类查询', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, '产品分类创建', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, '产品分类更新', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, '产品分类删除', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '关联商机', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, '取关商机', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, '商品统计', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, '客户公海', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, '订单查询', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '订单更新', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '支付&退款案例', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, '转账案例', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:51:16', '1', '2024-01-18 23:51:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, '钱包管理', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, '充值套餐', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, '钱包余额', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, '产品信息', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, '产品查询', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, '产品创建', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, '产品更新', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, '产品删除', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, '产品导出', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, '产品分类', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, '分类查询', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, '分类创建', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '分类更新', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, '分类删除', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, '分类导出', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, '产品单位', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, '单位查询', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, '单位创建', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, '单位更新', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, '单位删除', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, '单位导出', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '库存管理', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, '仓库信息', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, '仓库查询', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, '仓库创建', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, '仓库更新', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, '仓库删除', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, '仓库导出', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, '产品库存', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, '库存查询', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '库存导出', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, '出入库明细', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, '库存明细查询', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, '库存明细导出', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '其它入库', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, '其它入库单查询', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, '其它入库单创建', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, '其它入库单更新', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, '其它入库单删除', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, '其它入库单导出', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, '采购管理', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, '供应商信息', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, '供应商查询', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, '供应商创建', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, '供应商更新', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, '供应商删除', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, '供应商导出', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, '其它入库单审批', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '其它出库', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, '其它出库单查询', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, '其它出库单创建', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, '其它出库单更新', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, '其它出库单删除', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, '其它出库单导出', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, '其它出库单审批', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '销售管理', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, '客户信息', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, '客户查询', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, '客户创建', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, '客户更新', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, '客户删除', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, '客户导出', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '库存调拨', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, '库存调度单查询', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, '库存调度单创建', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, '库存调度单更新', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, '库存调度单删除', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, '库存调度单导出', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, '库存调度单审批', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '库存盘点', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '库存盘点单查询', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '库存盘点单创建', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '库存盘点单更新', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '库存盘点单删除', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '库存盘点单导出', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '库存盘点单审批', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '销售订单', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '销售订单查询', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '销售订单创建', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '销售订单更新', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '销售订单删除', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '销售订单导出', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '销售订单审批', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '财务管理', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '结算账户', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '结算账户查询', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '结算账户创建', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '结算账户更新', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '结算账户删除', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '结算账户导出', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '销售出库', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '销售出库查询', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '销售出库创建', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '销售出库更新', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '销售出库删除', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '销售出库导出', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '销售出库审批', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '销售退货', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '销售退货查询', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '销售退货创建', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '销售退货更新', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '销售退货删除', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '销售退货导出', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '销售退货审批', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, '采购订单', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, '采购订单查询', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, '采购订单创建', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, '采购订单更新', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, '采购订单删除', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, '采购订单导出', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, '采购订单审批', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, '采购入库', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, '采购入库查询', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, '采购入库创建', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, '采购入库更新', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, '采购入库删除', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, '采购入库导出', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, '采购入库审批', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, '采购退货', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, '采购退货查询', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, '采购退货创建', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, '采购退货更新', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, '采购退货删除', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, '采购退货导出', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, '采购退货审批', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '付款单', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, '付款单查询', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '付款单创建', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '付款单更新', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, '付款单删除', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '付款单导出', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '付款单审批', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, '收款单', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, '收款单查询', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, '收款单创建', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, '收款单更新', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, '收款单删除', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, '收款单导出', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, '收款单审批', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '待办事项', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP 首页', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '商机状态配置', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '商机状态查询', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '商机状态创建', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '商机状态更新', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '商机状态删除', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, '合同配置', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_menu_seq; +CREATE SEQUENCE system_menu_seq + START 2758; + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +DROP TABLE IF EXISTS system_notice; +CREATE TABLE system_notice +( + id int8 NOT NULL, + title varchar(50) NOT NULL, + content text NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notice + ADD CONSTRAINT pk_system_notice PRIMARY KEY (id); + +COMMENT ON COLUMN system_notice.id IS '公告ID'; +COMMENT ON COLUMN system_notice.title IS '公告标题'; +COMMENT ON COLUMN system_notice.content IS '公告内容'; +COMMENT ON COLUMN system_notice.type IS '公告类型(1通知 2公告)'; +COMMENT ON COLUMN system_notice.status IS '公告状态(0正常 1关闭)'; +COMMENT ON COLUMN system_notice.creator IS '创建者'; +COMMENT ON COLUMN system_notice.create_time IS '创建时间'; +COMMENT ON COLUMN system_notice.updater IS '更新者'; +COMMENT ON COLUMN system_notice.update_time IS '更新时间'; +COMMENT ON COLUMN system_notice.deleted IS '是否删除'; +COMMENT ON COLUMN system_notice.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notice IS '通知公告表'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', '0', 121); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notice_seq; +CREATE SEQUENCE system_notice_seq + START 5; + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_message; +CREATE TABLE system_notify_message +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + template_id int8 NOT NULL, + template_code varchar(64) NOT NULL, + template_nickname varchar(63) NOT NULL, + template_content varchar(1024) NOT NULL, + template_type int4 NOT NULL, + template_params varchar(255) NOT NULL, + read_status bool NOT NULL, + read_time timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_message + ADD CONSTRAINT pk_system_notify_message PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_message.id IS '用户ID'; +COMMENT ON COLUMN system_notify_message.user_id IS '用户id'; +COMMENT ON COLUMN system_notify_message.user_type IS '用户类型'; +COMMENT ON COLUMN system_notify_message.template_id IS '模版编号'; +COMMENT ON COLUMN system_notify_message.template_code IS '模板编码'; +COMMENT ON COLUMN system_notify_message.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_notify_message.template_content IS '模版内容'; +COMMENT ON COLUMN system_notify_message.template_type IS '模版类型'; +COMMENT ON COLUMN system_notify_message.template_params IS '模版参数'; +COMMENT ON COLUMN system_notify_message.read_status IS '是否已读'; +COMMENT ON COLUMN system_notify_message.read_time IS '阅读时间'; +COMMENT ON COLUMN system_notify_message.creator IS '创建者'; +COMMENT ON COLUMN system_notify_message.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_message.updater IS '更新者'; +COMMENT ON COLUMN system_notify_message.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_message.deleted IS '是否删除'; +COMMENT ON COLUMN system_notify_message.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notify_message IS '站内信消息表'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:44:08', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:45:04', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{"name":"哈哈"}', '0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 22:21:42', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', '我是 2,我开始 3 了', 1, '{"name":"2","what":"3"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{"name":"123"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notify_message_seq; +CREATE SEQUENCE system_notify_message_seq + START 11; + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_template; +CREATE TABLE system_notify_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(64) NOT NULL, + nickname varchar(255) NOT NULL, + content varchar(1024) NOT NULL, + type int2 NOT NULL, + params varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_template + ADD CONSTRAINT pk_system_notify_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_template.id IS '主键'; +COMMENT ON COLUMN system_notify_template.name IS '模板名称'; +COMMENT ON COLUMN system_notify_template.code IS '模版编码'; +COMMENT ON COLUMN system_notify_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_notify_template.content IS '模版内容'; +COMMENT ON COLUMN system_notify_template.type IS '类型'; +COMMENT ON COLUMN system_notify_template.params IS '参数数组'; +COMMENT ON COLUMN system_notify_template.status IS '状态'; +COMMENT ON COLUMN system_notify_template.remark IS '备注'; +COMMENT ON COLUMN system_notify_template.creator IS '创建者'; +COMMENT ON COLUMN system_notify_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_template.updater IS '更新者'; +COMMENT ON COLUMN system_notify_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_template.deleted IS '是否删除'; +COMMENT ON TABLE system_notify_template IS '站内信模板表'; + +DROP SEQUENCE IF EXISTS system_notify_template_seq; +CREATE SEQUENCE system_notify_template_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_access_token; +CREATE TABLE system_oauth2_access_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + user_info varchar(512) NOT NULL, + access_token varchar(255) NOT NULL, + refresh_token varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_access_token + ADD CONSTRAINT pk_system_oauth2_access_token PRIMARY KEY (id); + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token); +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token); + +COMMENT ON COLUMN system_oauth2_access_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_access_token.user_info IS '用户信息'; +COMMENT ON COLUMN system_oauth2_access_token.access_token IS '访问令牌'; +COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_access_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_access_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_access_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_access_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_access_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_access_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_access_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_access_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 访问令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq; +CREATE SEQUENCE system_oauth2_access_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_approve; +CREATE TABLE system_oauth2_approve +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scope varchar(255) NULL DEFAULT '', + approved bool NOT NULL DEFAULT '0', + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_approve + ADD CONSTRAINT pk_system_oauth2_approve PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_approve.id IS '编号'; +COMMENT ON COLUMN system_oauth2_approve.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_approve.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_approve.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_approve.scope IS '授权范围'; +COMMENT ON COLUMN system_oauth2_approve.approved IS '是否接受'; +COMMENT ON COLUMN system_oauth2_approve.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_approve.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_approve.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_approve.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_approve.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_approve.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 批准表'; + +DROP SEQUENCE IF EXISTS system_oauth2_approve_seq; +CREATE SEQUENCE system_oauth2_approve_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_client; +CREATE TABLE system_oauth2_client +( + id int8 NOT NULL, + client_id varchar(255) NOT NULL, + secret varchar(255) NOT NULL, + name varchar(255) NOT NULL, + logo varchar(255) NOT NULL, + description varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + access_token_validity_seconds int4 NOT NULL, + refresh_token_validity_seconds int4 NOT NULL, + redirect_uris varchar(255) NOT NULL, + authorized_grant_types varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + auto_approve_scopes varchar(255) NULL DEFAULT NULL, + authorities varchar(255) NULL DEFAULT NULL, + resource_ids varchar(255) NULL DEFAULT NULL, + additional_information varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_client + ADD CONSTRAINT pk_system_oauth2_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_client.id IS '编号'; +COMMENT ON COLUMN system_oauth2_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_client.secret IS '客户端密钥'; +COMMENT ON COLUMN system_oauth2_client.name IS '应用名'; +COMMENT ON COLUMN system_oauth2_client.logo IS '应用图标'; +COMMENT ON COLUMN system_oauth2_client.description IS '应用描述'; +COMMENT ON COLUMN system_oauth2_client.status IS '状态'; +COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS '访问令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS '刷新令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.redirect_uris IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS '授权类型'; +COMMENT ON COLUMN system_oauth2_client.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS '自动通过的授权范围'; +COMMENT ON COLUMN system_oauth2_client.authorities IS '权限'; +COMMENT ON COLUMN system_oauth2_client.resource_ids IS '资源'; +COMMENT ON COLUMN system_oauth2_client.additional_information IS '附加信息'; +COMMENT ON COLUMN system_oauth2_client.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_client.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_client.deleted IS '是否删除'; +COMMENT ON TABLE system_oauth2_client IS 'OAuth2 客户端表'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '我是描述', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2024-02-22 16:31:52', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '啦啦啦啦', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2023-12-02 21:01:01', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2022-09-29 13:28:31', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2022-10-04 20:31:21', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_oauth2_client_seq; +CREATE SEQUENCE system_oauth2_client_seq + START 43; + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_code; +CREATE TABLE system_oauth2_code +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + code varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT '', + expires_time timestamp NOT NULL, + redirect_uri varchar(255) NULL DEFAULT NULL, + state varchar(255) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_code + ADD CONSTRAINT pk_system_oauth2_code PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_code.id IS '编号'; +COMMENT ON COLUMN system_oauth2_code.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_code.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_code.code IS '授权码'; +COMMENT ON COLUMN system_oauth2_code.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_code.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_code.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_code.redirect_uri IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_code.state IS '状态'; +COMMENT ON COLUMN system_oauth2_code.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_code.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_code IS 'OAuth2 授权码表'; + +DROP SEQUENCE IF EXISTS system_oauth2_code_seq; +CREATE SEQUENCE system_oauth2_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_refresh_token; +CREATE TABLE system_oauth2_refresh_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + refresh_token varchar(32) NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_refresh_token + ADD CONSTRAINT pk_system_oauth2_refresh_token PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_refresh_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq; +CREATE SEQUENCE system_oauth2_refresh_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +DROP TABLE IF EXISTS system_operate_log; +CREATE TABLE system_operate_log +( + id int8 NOT NULL, + trace_id varchar(64) NULL DEFAULT '', + user_id int8 NOT NULL, + user_type int2 NOT NULL DEFAULT 0, + type varchar(50) NOT NULL, + sub_type varchar(50) NOT NULL, + biz_id int8 NOT NULL, + action varchar(2000) NULL DEFAULT '', + extra varchar(2000) NULL DEFAULT '', + request_method varchar(16) NULL DEFAULT '', + request_url varchar(255) NULL DEFAULT '', + user_ip varchar(50) NULL DEFAULT NULL, + user_agent varchar(200) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_operate_log + ADD CONSTRAINT pk_system_operate_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_operate_log.id IS '日志主键'; +COMMENT ON COLUMN system_operate_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_operate_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_operate_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_operate_log.type IS '操作模块类型'; +COMMENT ON COLUMN system_operate_log.sub_type IS '操作名'; +COMMENT ON COLUMN system_operate_log.biz_id IS '操作数据模块编号'; +COMMENT ON COLUMN system_operate_log.action IS '操作内容'; +COMMENT ON COLUMN system_operate_log.extra IS '拓展字段'; +COMMENT ON COLUMN system_operate_log.request_method IS '请求方法名'; +COMMENT ON COLUMN system_operate_log.request_url IS '请求地址'; +COMMENT ON COLUMN system_operate_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_operate_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_operate_log.creator IS '创建者'; +COMMENT ON COLUMN system_operate_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_operate_log.updater IS '更新者'; +COMMENT ON COLUMN system_operate_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_operate_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_operate_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_operate_log IS '操作日志记录 V2 版本'; + +DROP SEQUENCE IF EXISTS system_operate_log_seq; +CREATE SEQUENCE system_operate_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +DROP TABLE IF EXISTS system_post; +CREATE TABLE system_post +( + id int8 NOT NULL, + code varchar(64) NOT NULL, + name varchar(50) NOT NULL, + sort int4 NOT NULL, + status int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_post + ADD CONSTRAINT pk_system_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_post.id IS '岗位ID'; +COMMENT ON COLUMN system_post.code IS '岗位编码'; +COMMENT ON COLUMN system_post.name IS '岗位名称'; +COMMENT ON COLUMN system_post.sort IS '显示顺序'; +COMMENT ON COLUMN system_post.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_post.remark IS '备注'; +COMMENT ON COLUMN system_post.creator IS '创建者'; +COMMENT ON COLUMN system_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_post.updater IS '更新者'; +COMMENT ON COLUMN system_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_post IS '岗位信息表'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 10:04:37', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', '人力资源', 5, 0, '', '1', '2024-03-24 20:45:40', '1', '2024-03-24 20:45:40', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_post_seq; +CREATE SEQUENCE system_post_seq + START 6; + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +DROP TABLE IF EXISTS system_role; +CREATE TABLE system_role +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + code varchar(100) NOT NULL, + sort int4 NOT NULL, + data_scope int2 NOT NULL DEFAULT 1, + data_scope_dept_ids varchar(500) NULL DEFAULT '', + status int2 NOT NULL, + type int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role + ADD CONSTRAINT pk_system_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_role.id IS '角色ID'; +COMMENT ON COLUMN system_role.name IS '角色名称'; +COMMENT ON COLUMN system_role.code IS '角色权限字符串'; +COMMENT ON COLUMN system_role.sort IS '显示顺序'; +COMMENT ON COLUMN system_role.data_scope IS '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +COMMENT ON COLUMN system_role.data_scope_dept_ids IS '数据范围(指定部门数组)'; +COMMENT ON COLUMN system_role.status IS '角色状态(0正常 1停用)'; +COMMENT ON COLUMN system_role.type IS '角色类型'; +COMMENT ON COLUMN system_role.remark IS '备注'; +COMMENT ON COLUMN system_role.creator IS '创建者'; +COMMENT ON COLUMN system_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_role.updater IS '更新者'; +COMMENT ON COLUMN system_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role IS '角色信息表'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '我想测试', '', '2021-01-06 13:49:35', '1', '2024-03-24 22:22:45', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_seq; +CREATE SEQUENCE system_role_seq + START 112; + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_role_menu; +CREATE TABLE system_role_menu +( + id int8 NOT NULL, + role_id int8 NOT NULL, + menu_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role_menu + ADD CONSTRAINT pk_system_role_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_role_menu.id IS '自增编号'; +COMMENT ON COLUMN system_role_menu.role_id IS '角色ID'; +COMMENT ON COLUMN system_role_menu.menu_id IS '菜单ID'; +COMMENT ON COLUMN system_role_menu.creator IS '创建者'; +COMMENT ON COLUMN system_role_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_role_menu.updater IS '更新者'; +COMMENT ON COLUMN system_role_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_role_menu.deleted IS '是否删除'; +COMMENT ON COLUMN system_role_menu.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role_menu IS '角色和菜单关联表'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_menu_seq; +CREATE SEQUENCE system_role_menu_seq + START 5779; + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_channel; +CREATE TABLE system_sms_channel +( + id int8 NOT NULL, + signature varchar(12) NOT NULL, + code varchar(63) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_key varchar(128) NOT NULL, + api_secret varchar(128) NULL DEFAULT NULL, + callback_url varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_channel + ADD CONSTRAINT pk_system_sms_channel PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_channel.id IS '编号'; +COMMENT ON COLUMN system_sms_channel.signature IS '短信签名'; +COMMENT ON COLUMN system_sms_channel.code IS '渠道编码'; +COMMENT ON COLUMN system_sms_channel.status IS '开启状态'; +COMMENT ON COLUMN system_sms_channel.remark IS '备注'; +COMMENT ON COLUMN system_sms_channel.api_key IS '短信 API 的账号'; +COMMENT ON COLUMN system_sms_channel.api_secret IS '短信 API 的秘钥'; +COMMENT ON COLUMN system_sms_channel.callback_url IS '短信发送回调 URL'; +COMMENT ON COLUMN system_sms_channel.creator IS '创建者'; +COMMENT ON COLUMN system_sms_channel.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_channel.updater IS '更新者'; +COMMENT ON COLUMN system_sms_channel.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_channel.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_channel IS '短信渠道'; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2023-12-02 22:10:17', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, '仅测试', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2023-12-02 22:10:08', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_channel_seq; +CREATE SEQUENCE system_sms_channel_seq + START 7; + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_code; +CREATE TABLE system_sms_code +( + id int8 NOT NULL, + mobile varchar(11) NOT NULL, + code varchar(6) NOT NULL, + create_ip varchar(15) NOT NULL, + scene int2 NOT NULL, + today_index int2 NOT NULL, + used int2 NOT NULL, + used_time timestamp NULL DEFAULT NULL, + used_ip varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_code + ADD CONSTRAINT pk_system_sms_code PRIMARY KEY (id); + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile); + +COMMENT ON COLUMN system_sms_code.id IS '编号'; +COMMENT ON COLUMN system_sms_code.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_code.code IS '验证码'; +COMMENT ON COLUMN system_sms_code.create_ip IS '创建 IP'; +COMMENT ON COLUMN system_sms_code.scene IS '发送场景'; +COMMENT ON COLUMN system_sms_code.today_index IS '今日发送的第几条'; +COMMENT ON COLUMN system_sms_code.used IS '是否使用'; +COMMENT ON COLUMN system_sms_code.used_time IS '使用时间'; +COMMENT ON COLUMN system_sms_code.used_ip IS '使用 IP'; +COMMENT ON COLUMN system_sms_code.creator IS '创建者'; +COMMENT ON COLUMN system_sms_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_code.updater IS '更新者'; +COMMENT ON COLUMN system_sms_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_sms_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_sms_code IS '手机验证码'; + +DROP SEQUENCE IF EXISTS system_sms_code_seq; +CREATE SEQUENCE system_sms_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_log; +CREATE TABLE system_sms_log +( + id int8 NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_type int2 NOT NULL, + template_content varchar(255) NOT NULL, + template_params varchar(255) NOT NULL, + api_template_id varchar(63) NOT NULL, + mobile varchar(11) NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + api_send_code varchar(63) NULL DEFAULT NULL, + api_send_msg varchar(255) NULL DEFAULT NULL, + api_request_id varchar(255) NULL DEFAULT NULL, + api_serial_no varchar(255) NULL DEFAULT NULL, + receive_status int2 NOT NULL DEFAULT 0, + receive_time timestamp NULL DEFAULT NULL, + api_receive_code varchar(63) NULL DEFAULT NULL, + api_receive_msg varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_log + ADD CONSTRAINT pk_system_sms_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_log.id IS '编号'; +COMMENT ON COLUMN system_sms_log.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_log.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_sms_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_sms_log.template_type IS '短信类型'; +COMMENT ON COLUMN system_sms_log.template_content IS '短信内容'; +COMMENT ON COLUMN system_sms_log.template_params IS '短信参数'; +COMMENT ON COLUMN system_sms_log.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_log.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_sms_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_sms_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_sms_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_sms_log.api_send_code IS '短信 API 发送结果的编码'; +COMMENT ON COLUMN system_sms_log.api_send_msg IS '短信 API 发送失败的提示'; +COMMENT ON COLUMN system_sms_log.api_request_id IS '短信 API 发送返回的唯一请求 ID'; +COMMENT ON COLUMN system_sms_log.api_serial_no IS '短信 API 发送返回的序号'; +COMMENT ON COLUMN system_sms_log.receive_status IS '接收状态'; +COMMENT ON COLUMN system_sms_log.receive_time IS '接收时间'; +COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API 接收结果的编码'; +COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API 接收结果的说明'; +COMMENT ON COLUMN system_sms_log.creator IS '创建者'; +COMMENT ON COLUMN system_sms_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_log.updater IS '更新者'; +COMMENT ON COLUMN system_sms_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_log.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_log IS '短信日志'; + +DROP SEQUENCE IF EXISTS system_sms_log_seq; +CREATE SEQUENCE system_sms_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_template; +CREATE TABLE system_sms_template +( + id int8 NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL, + code varchar(63) NOT NULL, + name varchar(63) NOT NULL, + content varchar(255) NOT NULL, + params varchar(255) NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_template_id varchar(63) NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_template + ADD CONSTRAINT pk_system_sms_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_template.id IS '编号'; +COMMENT ON COLUMN system_sms_template.type IS '模板类型'; +COMMENT ON COLUMN system_sms_template.status IS '开启状态'; +COMMENT ON COLUMN system_sms_template.code IS '模板编码'; +COMMENT ON COLUMN system_sms_template.name IS '模板名称'; +COMMENT ON COLUMN system_sms_template.content IS '模板内容'; +COMMENT ON COLUMN system_sms_template.params IS '参数数组'; +COMMENT ON COLUMN system_sms_template.remark IS '备注'; +COMMENT ON COLUMN system_sms_template.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_template.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_template.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_template.creator IS '创建者'; +COMMENT ON COLUMN system_sms_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_template.updater IS '更新者'; +COMMENT ON COLUMN system_sms_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_template.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_template IS '短信模板'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '["operation","code"]', '测试备注', '4383920', 6, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2023-12-02 22:32:47', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '["name"]', 'f哈哈哈', '4383920', 6, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2022-12-10 21:26:09', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '["name","code"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '["code"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2022-12-10 21:25:59', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '【工作流】流程被通过', '您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', '演示模板', '我就是测试一下下', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2023-03-24 23:45:07', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', '会员用户 - 修改手机', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', '会员用户 - 修改密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', '会员用户 - 重置密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_template_seq; +CREATE SEQUENCE system_sms_template_seq + START 17; + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +DROP TABLE IF EXISTS system_social_client; +CREATE TABLE system_social_client +( + id int8 NOT NULL, + name varchar(255) NOT NULL, + social_type int2 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + client_secret varchar(255) NOT NULL, + agent_id varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_client + ADD CONSTRAINT pk_system_social_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_client.id IS '编号'; +COMMENT ON COLUMN system_social_client.name IS '应用名'; +COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; +COMMENT ON COLUMN system_social_client.status IS '状态'; +COMMENT ON COLUMN system_social_client.creator IS '创建者'; +COMMENT ON COLUMN system_social_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_client.updater IS '更新者'; +COMMENT ON COLUMN system_social_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_client.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_client.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_client IS '社交客户端表'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '钉钉', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '钉钉(王土豆)', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', '1', 121); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '微信公众号', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '微信小程序', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', '1', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_social_client_seq; +CREATE SEQUENCE system_social_client_seq + START 44; + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user; +CREATE TABLE system_social_user +( + id int8 NOT NULL, + type int2 NOT NULL, + openid varchar(32) NOT NULL, + token varchar(256) NULL DEFAULT NULL, + raw_token_info varchar(1024) NOT NULL, + nickname varchar(32) NOT NULL, + avatar varchar(255) NULL DEFAULT NULL, + raw_user_info varchar(1024) NOT NULL, + code varchar(256) NOT NULL, + state varchar(256) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user + ADD CONSTRAINT pk_system_social_user PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user.type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user.openid IS '社交 openid'; +COMMENT ON COLUMN system_social_user.token IS '社交 token'; +COMMENT ON COLUMN system_social_user.raw_token_info IS '原始 Token 数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.nickname IS '用户昵称'; +COMMENT ON COLUMN system_social_user.avatar IS '用户头像'; +COMMENT ON COLUMN system_social_user.raw_user_info IS '原始用户数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.code IS '最后一次的认证 code'; +COMMENT ON COLUMN system_social_user.state IS '最后一次的认证 state'; +COMMENT ON COLUMN system_social_user.creator IS '创建者'; +COMMENT ON COLUMN system_social_user.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user.updater IS '更新者'; +COMMENT ON COLUMN system_social_user.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user IS '社交用户表'; + +DROP SEQUENCE IF EXISTS system_social_user_seq; +CREATE SEQUENCE system_social_user_seq + START 1; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user_bind; +CREATE TABLE system_social_user_bind +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + social_type int2 NOT NULL, + social_user_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user_bind + ADD CONSTRAINT pk_system_social_user_bind PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user_bind.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user_bind.user_id IS '用户编号'; +COMMENT ON COLUMN system_social_user_bind.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_user_bind.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user_bind.social_user_id IS '社交用户的编号'; +COMMENT ON COLUMN system_social_user_bind.creator IS '创建者'; +COMMENT ON COLUMN system_social_user_bind.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user_bind.updater IS '更新者'; +COMMENT ON COLUMN system_social_user_bind.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user_bind.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user_bind.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user_bind IS '社交绑定表'; + +DROP SEQUENCE IF EXISTS system_social_user_bind_seq; +CREATE SEQUENCE system_social_user_bind_seq + START 1; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant; +CREATE TABLE system_tenant +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + contact_user_id int8 NULL DEFAULT NULL, + contact_name varchar(30) NOT NULL, + contact_mobile varchar(500) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + website varchar(256) NULL DEFAULT '', + package_id int8 NOT NULL, + expire_time timestamp NOT NULL, + account_count int4 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant + ADD CONSTRAINT pk_system_tenant PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant.id IS '租户编号'; +COMMENT ON COLUMN system_tenant.name IS '租户名'; +COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号'; +COMMENT ON COLUMN system_tenant.contact_name IS '联系人'; +COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机'; +COMMENT ON COLUMN system_tenant.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant.website IS '绑定域名'; +COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号'; +COMMENT ON COLUMN system_tenant.expire_time IS '过期时间'; +COMMENT ON COLUMN system_tenant.account_count IS '账号数量'; +COMMENT ON COLUMN system_tenant.creator IS '创建者'; +COMMENT ON COLUMN system_tenant.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant.updater IS '更新者'; +COMMENT ON COLUMN system_tenant.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant IS '租户表'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_seq; +CREATE SEQUENCE system_tenant_seq + START 123; + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant_package; +CREATE TABLE system_tenant_package +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + status int2 NOT NULL DEFAULT 0, + remark varchar(256) NULL DEFAULT '', + menu_ids varchar(4096) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant_package + ADD CONSTRAINT pk_system_tenant_package PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant_package.id IS '套餐编号'; +COMMENT ON COLUMN system_tenant_package.name IS '套餐名'; +COMMENT ON COLUMN system_tenant_package.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant_package.remark IS '备注'; +COMMENT ON COLUMN system_tenant_package.menu_ids IS '关联的菜单编号'; +COMMENT ON COLUMN system_tenant_package.creator IS '创建者'; +COMMENT ON COLUMN system_tenant_package.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant_package.updater IS '更新者'; +COMMENT ON COLUMN system_tenant_package.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant_package.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant_package IS '租户套餐表'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-03-30 17:53:17', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_package_seq; +CREATE SEQUENCE system_tenant_package_seq + START 112; + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +DROP TABLE IF EXISTS system_user_post; +CREATE TABLE system_user_post +( + id int8 NOT NULL, + user_id int8 NOT NULL DEFAULT 0, + post_id int8 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_post + ADD CONSTRAINT pk_system_user_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_post.id IS 'id'; +COMMENT ON COLUMN system_user_post.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_post.post_id IS '岗位ID'; +COMMENT ON COLUMN system_user_post.creator IS '创建者'; +COMMENT ON COLUMN system_user_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_post.updater IS '更新者'; +COMMENT ON COLUMN system_user_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_post IS '用户岗位表'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_post_seq; +CREATE SEQUENCE system_user_post_seq + START 125; + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +DROP TABLE IF EXISTS system_user_role; +CREATE TABLE system_user_role +( + id int8 NOT NULL, + user_id int8 NOT NULL, + role_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_role + ADD CONSTRAINT pk_system_user_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_role.id IS '自增编号'; +COMMENT ON COLUMN system_user_role.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_role.role_id IS '角色ID'; +COMMENT ON COLUMN system_user_role.creator IS '创建者'; +COMMENT ON COLUMN system_user_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_role.updater IS '更新者'; +COMMENT ON COLUMN system_user_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_role IS '用户和角色关联表'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_role_seq; +CREATE SEQUENCE system_user_role_seq + START 39; + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +DROP TABLE IF EXISTS system_users; +CREATE TABLE system_users +( + id int8 NOT NULL, + username varchar(30) NOT NULL, + password varchar(100) NULL DEFAULT '', + nickname varchar(30) NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + dept_id int8 NULL DEFAULT NULL, + post_ids varchar(255) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT '', + mobile varchar(11) NULL DEFAULT '', + sex int2 NULL DEFAULT 0, + avatar varchar(512) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + login_ip varchar(50) NULL DEFAULT '', + login_date timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_users + ADD CONSTRAINT pk_system_users PRIMARY KEY (id); + +COMMENT ON COLUMN system_users.id IS '用户ID'; +COMMENT ON COLUMN system_users.username IS '用户账号'; +COMMENT ON COLUMN system_users.password IS '密码'; +COMMENT ON COLUMN system_users.nickname IS '用户昵称'; +COMMENT ON COLUMN system_users.remark IS '备注'; +COMMENT ON COLUMN system_users.dept_id IS '部门ID'; +COMMENT ON COLUMN system_users.post_ids IS '岗位编号数组'; +COMMENT ON COLUMN system_users.email IS '用户邮箱'; +COMMENT ON COLUMN system_users.mobile IS '手机号码'; +COMMENT ON COLUMN system_users.sex IS '用户性别'; +COMMENT ON COLUMN system_users.avatar IS '头像地址'; +COMMENT ON COLUMN system_users.status IS '帐号状态(0正常 1停用)'; +COMMENT ON COLUMN system_users.login_ip IS '最后登录IP'; +COMMENT ON COLUMN system_users.login_date IS '最后登录时间'; +COMMENT ON COLUMN system_users.creator IS '创建者'; +COMMENT ON COLUMN system_users.create_time IS '创建时间'; +COMMENT ON COLUMN system_users.updater IS '更新者'; +COMMENT ON COLUMN system_users.update_time IS '更新时间'; +COMMENT ON COLUMN system_users.deleted IS '是否删除'; +COMMENT ON COLUMN system_users.tenant_id IS '租户编号'; +COMMENT ON TABLE system_users IS '用户信息表'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', '0', 118); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', '0', 119); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', '0', 120); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', '0', 122); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_users_seq; +CREATE SEQUENCE system_users_seq + START 132; + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo01_contact; +CREATE TABLE yudao_demo01_contact +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + avatar varchar(512) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo01_contact + ADD CONSTRAINT pk_yudao_demo01_contact PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo01_contact.id IS '编号'; +COMMENT ON COLUMN yudao_demo01_contact.name IS '名字'; +COMMENT ON COLUMN yudao_demo01_contact.sex IS '性别'; +COMMENT ON COLUMN yudao_demo01_contact.birthday IS '出生年'; +COMMENT ON COLUMN yudao_demo01_contact.description IS '简介'; +COMMENT ON COLUMN yudao_demo01_contact.avatar IS '头像'; +COMMENT ON COLUMN yudao_demo01_contact.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo01_contact.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo01_contact.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo01_contact.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo01_contact.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo01_contact IS '示例联系人表'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 2, '2023-11-07 00:00:00', '

天蚕土豆!呀

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq; +CREATE SEQUENCE yudao_demo01_contact_seq + START 2; + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo02_category; +CREATE TABLE yudao_demo02_category +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + parent_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo02_category + ADD CONSTRAINT pk_yudao_demo02_category PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo02_category.id IS '编号'; +COMMENT ON COLUMN yudao_demo02_category.name IS '名字'; +COMMENT ON COLUMN yudao_demo02_category.parent_id IS '父级编号'; +COMMENT ON COLUMN yudao_demo02_category.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo02_category.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo02_category.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo02_category.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo02_category.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo02_category IS '示例分类表'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '番茄', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '怪怪', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '小番茄', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大番茄', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo02_category_seq; +CREATE SEQUENCE yudao_demo02_category_seq + START 7; + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_course; +CREATE TABLE yudao_demo03_course +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + score int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_course + ADD CONSTRAINT pk_yudao_demo03_course PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_course.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_course.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_course.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_course.score IS '分数'; +COMMENT ON COLUMN yudao_demo03_course.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_course.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_course.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_course.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_course.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_course IS '学生课程表'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_course_seq; +CREATE SEQUENCE yudao_demo03_course_seq + START 14; + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_grade; +CREATE TABLE yudao_demo03_grade +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + teacher varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_grade + ADD CONSTRAINT pk_yudao_demo03_grade PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_grade.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_grade.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_grade.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_grade.teacher IS '班主任'; +COMMENT ON COLUMN yudao_demo03_grade.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_grade.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_grade.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_grade.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_grade.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_grade IS '学生班级表'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq; +CREATE SEQUENCE yudao_demo03_grade_seq + START 10; + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_student; +CREATE TABLE yudao_demo03_student +( + id int8 NOT NULL, + name varchar(100) NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_student + ADD CONSTRAINT pk_yudao_demo03_student PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_student.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_student.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_student.sex IS '性别'; +COMMENT ON COLUMN yudao_demo03_student.birthday IS '出生日期'; +COMMENT ON COLUMN yudao_demo03_student.description IS '简介'; +COMMENT ON COLUMN yudao_demo03_student.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_student.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_student.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_student.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_student.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_student IS '学生表'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_student_seq; +CREATE SEQUENCE yudao_demo03_student_seq + START 10; + diff --git a/ruoyi-vue-pro-master/sql/oracle/quartz.sql b/ruoyi-vue-pro-master/sql/oracle/quartz.sql new file mode 100644 index 0000000..c3ed175 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/oracle/quartz.sql @@ -0,0 +1,845 @@ +/* + 注意:仅仅需要 Quartz 定时任务的场景,可选!!! + + Date: 15/06/2022 08:20:08 +*/ + +-- ---------------------------- +-- Table structure for QRTZ_BLOB_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_BLOB_TRIGGERS"; +CREATE TABLE "QRTZ_BLOB_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "BLOB_DATA" BLOB +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_BLOB_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_CALENDARS +-- ---------------------------- +DROP TABLE "QRTZ_CALENDARS"; +CREATE TABLE "QRTZ_CALENDARS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "CALENDAR_NAME" VARCHAR2(200 BYTE) NOT NULL, + "CALENDAR" BLOB NOT NULL +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_CALENDARS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_CRON_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_CRON_TRIGGERS"; +CREATE TABLE "QRTZ_CRON_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "CRON_EXPRESSION" VARCHAR2(120 BYTE) NOT NULL, + "TIME_ZONE_ID" VARCHAR2(80 BYTE) +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_CRON_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_FIRED_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_FIRED_TRIGGERS"; +CREATE TABLE "QRTZ_FIRED_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "ENTRY_ID" VARCHAR2(95 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "INSTANCE_NAME" VARCHAR2(200 BYTE) NOT NULL, + "FIRED_TIME" NUMBER(13,0) NOT NULL, + "SCHED_TIME" NUMBER(13,0) NOT NULL, + "PRIORITY" NUMBER(13,0) NOT NULL, + "STATE" VARCHAR2(16 BYTE) NOT NULL, + "JOB_NAME" VARCHAR2(200 BYTE), + "JOB_GROUP" VARCHAR2(200 BYTE), + "IS_NONCONCURRENT" VARCHAR2(1 BYTE), + "REQUESTS_RECOVERY" VARCHAR2(1 BYTE) +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_FIRED_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_JOB_DETAILS +-- ---------------------------- +DROP TABLE "QRTZ_JOB_DETAILS"; +CREATE TABLE "QRTZ_JOB_DETAILS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "JOB_NAME" VARCHAR2(200 BYTE) NOT NULL, + "JOB_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "DESCRIPTION" VARCHAR2(250 BYTE), + "JOB_CLASS_NAME" VARCHAR2(250 BYTE) NOT NULL, + "IS_DURABLE" VARCHAR2(1 BYTE) NOT NULL, + "IS_NONCONCURRENT" VARCHAR2(1 BYTE) NOT NULL, + "IS_UPDATE_DATA" VARCHAR2(1 BYTE) NOT NULL, + "REQUESTS_RECOVERY" VARCHAR2(1 BYTE) NOT NULL, + "JOB_DATA" BLOB +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_JOB_DETAILS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_LOCKS +-- ---------------------------- +DROP TABLE "QRTZ_LOCKS"; +CREATE TABLE "QRTZ_LOCKS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "LOCK_NAME" VARCHAR2(40 BYTE) NOT NULL +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_LOCKS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +DROP TABLE "QRTZ_PAUSED_TRIGGER_GRPS"; +CREATE TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SCHEDULER_STATE +-- ---------------------------- +DROP TABLE "QRTZ_SCHEDULER_STATE"; +CREATE TABLE "QRTZ_SCHEDULER_STATE" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "INSTANCE_NAME" VARCHAR2(200 BYTE) NOT NULL, + "LAST_CHECKIN_TIME" NUMBER(13,0) NOT NULL, + "CHECKIN_INTERVAL" NUMBER(13,0) NOT NULL +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_SCHEDULER_STATE +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_SIMPLE_TRIGGERS"; +CREATE TABLE "QRTZ_SIMPLE_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "REPEAT_COUNT" NUMBER(7,0) NOT NULL, + "REPEAT_INTERVAL" NUMBER(12,0) NOT NULL, + "TIMES_TRIGGERED" NUMBER(10,0) NOT NULL +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_SIMPROP_TRIGGERS"; +CREATE TABLE "QRTZ_SIMPROP_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "STR_PROP_1" VARCHAR2(512 BYTE), + "STR_PROP_2" VARCHAR2(512 BYTE), + "STR_PROP_3" VARCHAR2(512 BYTE), + "INT_PROP_1" NUMBER(10,0), + "INT_PROP_2" NUMBER(10,0), + "LONG_PROP_1" NUMBER(13,0), + "LONG_PROP_2" NUMBER(13,0), + "DEC_PROP_1" NUMBER(13,4), + "DEC_PROP_2" NUMBER(13,4), + "BOOL_PROP_1" VARCHAR2(1 BYTE), + "BOOL_PROP_2" VARCHAR2(1 BYTE) +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Table structure for QRTZ_TRIGGERS +-- ---------------------------- +DROP TABLE "QRTZ_TRIGGERS"; +CREATE TABLE "QRTZ_TRIGGERS" ( + "SCHED_NAME" VARCHAR2(120 BYTE) NOT NULL, + "TRIGGER_NAME" VARCHAR2(200 BYTE) NOT NULL, + "TRIGGER_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "JOB_NAME" VARCHAR2(200 BYTE) NOT NULL, + "JOB_GROUP" VARCHAR2(200 BYTE) NOT NULL, + "DESCRIPTION" VARCHAR2(250 BYTE), + "NEXT_FIRE_TIME" NUMBER(13,0), + "PREV_FIRE_TIME" NUMBER(13,0), + "PRIORITY" NUMBER(13,0), + "TRIGGER_STATE" VARCHAR2(16 BYTE) NOT NULL, + "TRIGGER_TYPE" VARCHAR2(8 BYTE) NOT NULL, + "START_TIME" NUMBER(13,0) NOT NULL, + "END_TIME" NUMBER(13,0), + "CALENDAR_NAME" VARCHAR2(200 BYTE), + "MISFIRE_INSTR" NUMBER(2,0), + "JOB_DATA" BLOB +) + LOGGING +NOCOMPRESS +PCTFREE 10 +INITRANS 1 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +) +PARALLEL 1 +NOCACHE +DISABLE ROW MOVEMENT +; + +-- ---------------------------- +-- Records of QRTZ_TRIGGERS +-- ---------------------------- +COMMIT; +COMMIT; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_BLOB_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "QRTZ_BLOB_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_BLOB_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008266" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008267" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008268" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008653" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008654" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "SYS_C008655" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_CALENDARS +-- ---------------------------- +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "QRTZ_CALENDARS_PK" PRIMARY KEY ("SCHED_NAME", "CALENDAR_NAME"); + +-- ---------------------------- +-- Checks structure for table QRTZ_CALENDARS +-- ---------------------------- +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008271" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008272" CHECK ("CALENDAR_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008273" CHECK ("CALENDAR" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008656" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008657" CHECK ("CALENDAR_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT "SYS_C008658" CHECK ("CALENDAR" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "QRTZ_CRON_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008255" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008256" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008257" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008258" CHECK ("CRON_EXPRESSION" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008659" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008660" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008661" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "SYS_C008662" CHECK ("CRON_EXPRESSION" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_FIRED_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "QRTZ_FIRED_TRIGGER_PK" PRIMARY KEY ("SCHED_NAME", "ENTRY_ID"); + +-- ---------------------------- +-- Checks structure for table QRTZ_FIRED_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008278" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008279" CHECK ("ENTRY_ID" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008280" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008281" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008282" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008283" CHECK ("FIRED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008284" CHECK ("SCHED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008285" CHECK ("PRIORITY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008286" CHECK ("STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008663" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008664" CHECK ("ENTRY_ID" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008665" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008666" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008667" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008668" CHECK ("FIRED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008669" CHECK ("SCHED_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008670" CHECK ("PRIORITY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008671" CHECK ("STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Indexes structure for table QRTZ_FIRED_TRIGGERS +-- ---------------------------- +CREATE INDEX "IDX_QRTZ_FT_INST_JOB_REQ_RCVRY" + ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "INSTANCE_NAME" ASC, "REQUESTS_RECOVERY" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_FT_JG" + ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) + LOGGING + ONLINE + NOSORT + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_FT_J_G" + ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_FT_TG" + ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_GROUP" ASC) LOCAL + LOGGING + NOSORT + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); + +-- ---------------------------- +-- Primary Key structure for table QRTZ_JOB_DETAILS +-- ---------------------------- +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "QRTZ_JOB_DETAILS_PK" PRIMARY KEY ("SCHED_NAME", "JOB_NAME", "JOB_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_JOB_DETAILS +-- ---------------------------- +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008228" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008229" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008230" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008231" CHECK ("JOB_CLASS_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008232" CHECK ("IS_DURABLE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008233" CHECK ("IS_NONCONCURRENT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008234" CHECK ("IS_UPDATE_DATA" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT "SYS_C008235" CHECK ("REQUESTS_RECOVERY" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Indexes structure for table QRTZ_JOB_DETAILS +-- ---------------------------- +CREATE INDEX "IDX_QRTZ_J_GRP" + ON "QRTZ_JOB_DETAILS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_J_REQ_RECOVERY" + ON "QRTZ_JOB_DETAILS" ("SCHED_NAME" ASC, "REQUESTS_RECOVERY" ASC) LOCAL + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); + +-- ---------------------------- +-- Primary Key structure for table QRTZ_LOCKS +-- ---------------------------- +ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "QRTZ_LOCKS_PK" PRIMARY KEY ("SCHED_NAME", "LOCK_NAME"); + +-- ---------------------------- +-- Checks structure for table QRTZ_LOCKS +-- ---------------------------- +ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008293" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008294" CHECK ("LOCK_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008672" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT "SYS_C008673" CHECK ("LOCK_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "QRTZ_PAUSED_TRIG_GRPS_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008275" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008276" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008674" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT "SYS_C008675" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SCHEDULER_STATE +-- ---------------------------- +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "QRTZ_SCHEDULER_STATE_PK" PRIMARY KEY ("SCHED_NAME", "INSTANCE_NAME"); + +-- ---------------------------- +-- Checks structure for table QRTZ_SCHEDULER_STATE +-- ---------------------------- +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008288" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008289" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008290" CHECK ("LAST_CHECKIN_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008291" CHECK ("CHECKIN_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008676" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008677" CHECK ("INSTANCE_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008678" CHECK ("LAST_CHECKIN_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT "SYS_C008679" CHECK ("CHECKIN_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPLE_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008247" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008248" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008249" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008250" CHECK ("REPEAT_COUNT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008251" CHECK ("REPEAT_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008252" CHECK ("TIMES_TRIGGERED" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008680" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008681" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008682" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008683" CHECK ("REPEAT_COUNT" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008684" CHECK ("REPEAT_INTERVAL" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "SYS_C008685" CHECK ("TIMES_TRIGGERED" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPROP_TRIG_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008261" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008262" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008263" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008686" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008687" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "SYS_C008688" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Primary Key structure for table QRTZ_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "QRTZ_TRIGGERS_PK" PRIMARY KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP"); + +-- ---------------------------- +-- Checks structure for table QRTZ_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008237" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008238" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008239" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008240" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008241" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008242" CHECK ("TRIGGER_STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008243" CHECK ("TRIGGER_TYPE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008244" CHECK ("START_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008689" CHECK ("SCHED_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008690" CHECK ("TRIGGER_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008691" CHECK ("TRIGGER_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008692" CHECK ("JOB_NAME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008693" CHECK ("JOB_GROUP" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008694" CHECK ("TRIGGER_STATE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008695" CHECK ("TRIGGER_TYPE" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; +ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008696" CHECK ("START_TIME" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Indexes structure for table QRTZ_TRIGGERS +-- ---------------------------- +CREATE INDEX "IDX_QRTZ_T_C" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "CALENDAR_NAME" ASC) LOCAL + LOGGING + ONLINE + NOSORT + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_J" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_JG" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) LOCAL + LOGGING + ONLINE + NOSORT + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_NEXT_FIRE_TIME" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "NEXT_FIRE_TIME" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_NFT_ST" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_STATE" ASC, "NEXT_FIRE_TIME" ASC) LOCAL + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_NFT_ST_MISFIRE" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "MISFIRE_INSTR" ASC, "NEXT_FIRE_TIME" ASC, "TRIGGER_STATE" ASC) LOCAL + LOGGING + ONLINE + NOSORT + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); +CREATE INDEX "IDX_QRTZ_T_STATE" + ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_STATE" ASC) + LOGGING + VISIBLE +PCTFREE 10 +INITRANS 2 +STORAGE ( + INITIAL 65536 + NEXT 1048576 + MINEXTENTS 1 + MAXEXTENTS 2147483645 + FREELISTS 1 + FREELIST GROUPS 1 + BUFFER_POOL DEFAULT +); + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_BLOB_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "QRTZ_BLOB_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "QRTZ_CRON_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPLE_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPROP_TRIG_TO_TRIG_FK" FOREIGN KEY ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS" ("SCHED_NAME", "TRIGGER_NAME", "TRIGGER_GROUP") NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/sql/oracle/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/oracle/ruoyi-vue-pro.sql new file mode 100644 index 0000000..9fbf8d5 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/oracle/ruoyi-vue-pro.sql @@ -0,0 +1,4582 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : Oracle + + Date: 2024-05-02 00:10:33 +*/ + + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +CREATE TABLE infra_api_access_log +( + id number NOT NULL, + trace_id varchar2(64) DEFAULT '' NULL, + user_id number DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + application_name varchar2(50) NOT NULL, + request_method varchar2(16) DEFAULT '' NULL, + request_url varchar2(255) DEFAULT '' NULL, + request_params clob NULL, + response_body clob NULL, + user_ip varchar2(50) NOT NULL, + user_agent varchar2(512) NOT NULL, + operate_module varchar2(50) DEFAULT NULL NULL, + operate_name varchar2(50) DEFAULT NULL NULL, + operate_type smallint DEFAULT 0 NULL, + begin_time date NOT NULL, + end_time date NOT NULL, + duration number NOT NULL, + result_code number DEFAULT 0 NOT NULL, + result_msg varchar2(512) DEFAULT '' NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_api_access_log + ADD CONSTRAINT pk_infra_api_access_log PRIMARY KEY (id); + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time); + +COMMENT ON COLUMN infra_api_access_log.id IS '日志主键'; +COMMENT ON COLUMN infra_api_access_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN infra_api_access_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_access_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_access_log.application_name IS '应用名'; +COMMENT ON COLUMN infra_api_access_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_access_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_access_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_access_log.response_body IS '响应结果'; +COMMENT ON COLUMN infra_api_access_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_access_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_access_log.operate_module IS '操作模块'; +COMMENT ON COLUMN infra_api_access_log.operate_name IS '操作名'; +COMMENT ON COLUMN infra_api_access_log.operate_type IS '操作分类'; +COMMENT ON COLUMN infra_api_access_log.begin_time IS '开始请求时间'; +COMMENT ON COLUMN infra_api_access_log.end_time IS '结束请求时间'; +COMMENT ON COLUMN infra_api_access_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_api_access_log.result_code IS '结果码'; +COMMENT ON COLUMN infra_api_access_log.result_msg IS '结果提示'; +COMMENT ON COLUMN infra_api_access_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_access_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_access_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_access_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_access_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_access_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_access_log IS 'API 访问日志表'; + +CREATE SEQUENCE infra_api_access_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +CREATE TABLE infra_api_error_log +( + id number NOT NULL, + trace_id varchar2(64) NOT NULL, + user_id number DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + application_name varchar2(50) NOT NULL, + request_method varchar2(16) NOT NULL, + request_url varchar2(255) NOT NULL, + request_params varchar2(4000) NOT NULL, + user_ip varchar2(50) NOT NULL, + user_agent varchar2(512) NOT NULL, + exception_time date NOT NULL, + exception_name varchar2(128) DEFAULT '' NULL, + exception_message clob NOT NULL, + exception_root_cause_message clob NOT NULL, + exception_stack_trace clob NOT NULL, + exception_class_name varchar2(512) NOT NULL, + exception_file_name varchar2(512) NOT NULL, + exception_method_name varchar2(512) NOT NULL, + exception_line_number number NOT NULL, + process_status smallint NOT NULL, + process_time date DEFAULT NULL NULL, + process_user_id number DEFAULT 0 NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_api_error_log + ADD CONSTRAINT pk_infra_api_error_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_api_error_log.id IS '编号'; +COMMENT ON COLUMN infra_api_error_log.trace_id IS '链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。'; +COMMENT ON COLUMN infra_api_error_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_error_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_error_log.application_name IS '应用名 + * + * 目前读取 spring.application.name'; +COMMENT ON COLUMN infra_api_error_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_error_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_error_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_error_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_error_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_error_log.exception_time IS '异常发生时间'; +COMMENT ON COLUMN infra_api_error_log.exception_name IS '异常名 + * + * {@link Throwable#getClass()} 的类全名'; +COMMENT ON COLUMN infra_api_error_log.exception_message IS '异常导致的消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '异常导致的根消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '异常的栈轨迹 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}'; +COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '异常发生的类全名 + * + * {@link StackTraceElement#getClassName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '异常发生的类文件 + * + * {@link StackTraceElement#getFileName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()}'; +COMMENT ON COLUMN infra_api_error_log.process_status IS '处理状态'; +COMMENT ON COLUMN infra_api_error_log.process_time IS '处理时间'; +COMMENT ON COLUMN infra_api_error_log.process_user_id IS '处理用户编号'; +COMMENT ON COLUMN infra_api_error_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_error_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_error_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_error_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_error_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_error_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_error_log IS '系统异常日志'; + +CREATE SEQUENCE infra_api_error_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +CREATE TABLE infra_codegen_column +( + id number NOT NULL, + table_id number NOT NULL, + column_name varchar2(200) NOT NULL, + data_type varchar2(100) NOT NULL, + column_comment varchar2(500) NOT NULL, + nullable number(1, 0) NOT NULL, + primary_key number(1, 0) NOT NULL, + ordinal_position number NOT NULL, + java_type varchar2(32) NOT NULL, + java_field varchar2(64) NOT NULL, + dict_type varchar2(200) DEFAULT '' NULL, + example varchar2(64) DEFAULT NULL NULL, + create_operation number(1, 0) NOT NULL, + update_operation number(1, 0) NOT NULL, + list_operation number(1, 0) NOT NULL, + list_operation_condition varchar2(32) DEFAULT '=' NOT NULL, + list_operation_result number(1, 0) NOT NULL, + html_type varchar2(32) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_codegen_column + ADD CONSTRAINT pk_infra_codegen_column PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_column.id IS '编号'; +COMMENT ON COLUMN infra_codegen_column.table_id IS '表编号'; +COMMENT ON COLUMN infra_codegen_column.column_name IS '字段名'; +COMMENT ON COLUMN infra_codegen_column.data_type IS '字段类型'; +COMMENT ON COLUMN infra_codegen_column.column_comment IS '字段描述'; +COMMENT ON COLUMN infra_codegen_column.nullable IS '是否允许为空'; +COMMENT ON COLUMN infra_codegen_column.primary_key IS '是否主键'; +COMMENT ON COLUMN infra_codegen_column.ordinal_position IS '排序'; +COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java 属性类型'; +COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java 属性名'; +COMMENT ON COLUMN infra_codegen_column.dict_type IS '字典类型'; +COMMENT ON COLUMN infra_codegen_column.example IS '数据示例'; +COMMENT ON COLUMN infra_codegen_column.create_operation IS '是否为 Create 创建操作的字段'; +COMMENT ON COLUMN infra_codegen_column.update_operation IS '是否为 Update 更新操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation IS '是否为 List 查询操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List 查询操作的条件类型'; +COMMENT ON COLUMN infra_codegen_column.list_operation_result IS '是否为 List 查询操作的返回字段'; +COMMENT ON COLUMN infra_codegen_column.html_type IS '显示类型'; +COMMENT ON COLUMN infra_codegen_column.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_column.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_column.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_column.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_column.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_column IS '代码生成表字段定义'; + +CREATE SEQUENCE infra_codegen_column_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +CREATE TABLE infra_codegen_table +( + id number NOT NULL, + data_source_config_id number NOT NULL, + scene smallint DEFAULT 1 NOT NULL, + table_name varchar2(200) DEFAULT '' NULL, + table_comment varchar2(500) DEFAULT '' NULL, + remark varchar2(500) DEFAULT NULL NULL, + module_name varchar2(30) NOT NULL, + business_name varchar2(30) NOT NULL, + class_name varchar2(100) DEFAULT '' NULL, + class_comment varchar2(50) NOT NULL, + author varchar2(50) NOT NULL, + template_type smallint DEFAULT 1 NOT NULL, + front_type smallint NOT NULL, + parent_menu_id number DEFAULT NULL NULL, + master_table_id number DEFAULT NULL NULL, + sub_join_column_id number DEFAULT NULL NULL, + sub_join_many number(1, 0) DEFAULT NULL NULL, + tree_parent_column_id number DEFAULT NULL NULL, + tree_name_column_id number DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_codegen_table + ADD CONSTRAINT pk_infra_codegen_table PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_table.id IS '编号'; +COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS '数据源配置的编号'; +COMMENT ON COLUMN infra_codegen_table.scene IS '生成场景'; +COMMENT ON COLUMN infra_codegen_table.table_name IS '表名称'; +COMMENT ON COLUMN infra_codegen_table.table_comment IS '表描述'; +COMMENT ON COLUMN infra_codegen_table.remark IS '备注'; +COMMENT ON COLUMN infra_codegen_table.module_name IS '模块名'; +COMMENT ON COLUMN infra_codegen_table.business_name IS '业务名'; +COMMENT ON COLUMN infra_codegen_table.class_name IS '类名称'; +COMMENT ON COLUMN infra_codegen_table.class_comment IS '类描述'; +COMMENT ON COLUMN infra_codegen_table.author IS '作者'; +COMMENT ON COLUMN infra_codegen_table.template_type IS '模板类型'; +COMMENT ON COLUMN infra_codegen_table.front_type IS '前端类型'; +COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '父菜单编号'; +COMMENT ON COLUMN infra_codegen_table.master_table_id IS '主表的编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS '子表关联主表的字段编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_many IS '主表与子表是否一对多'; +COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS '树表的父字段编号'; +COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS '树表的名字字段编号'; +COMMENT ON COLUMN infra_codegen_table.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_table.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_table.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_table.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_table.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_table IS '代码生成表定义'; + +CREATE SEQUENCE infra_codegen_table_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +CREATE TABLE infra_config +( + id number NOT NULL, + category varchar2(50) NOT NULL, + type smallint NOT NULL, + name varchar2(100) DEFAULT '' NULL, + config_key varchar2(100) DEFAULT '' NULL, + value varchar2(500) DEFAULT '' NULL, + visible number(1, 0) NOT NULL, + remark varchar2(500) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_config + ADD CONSTRAINT pk_infra_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_config.id IS '参数主键'; +COMMENT ON COLUMN infra_config.category IS '参数分组'; +COMMENT ON COLUMN infra_config.type IS '参数类型'; +COMMENT ON COLUMN infra_config.name IS '参数名称'; +COMMENT ON COLUMN infra_config.config_key IS '参数键名'; +COMMENT ON COLUMN infra_config.value IS '参数键值'; +COMMENT ON COLUMN infra_config.visible IS '是否可见'; +COMMENT ON COLUMN infra_config.remark IS '备注'; +COMMENT ON COLUMN infra_config.creator IS '创建者'; +COMMENT ON COLUMN infra_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_config.updater IS '更新者'; +COMMENT ON COLUMN infra_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_config IS '参数配置表'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, '用户管理-账号初始密码', 'sys.user.init-password', '123456', '0', '初始化密码 123456', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-03 17:22:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL 监控的地址', 'url.druid', '', '1', '', '1', to_date('2023-04-07 13:41:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-07 14:33:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking 监控的地址', 'url.skywalking', '', '1', '', '1', to_date('2023-04-07 13:41:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-07 14:57:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin 监控的地址', 'url.spring-boot-admin', '', '1', '', '1', to_date('2023-04-07 13:41:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-07 14:52:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger 接口文档的地址', 'url.swagger', '', '1', '', '1', to_date('2023-04-07 13:41:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-07 14:59:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, 'ui', 2, '腾讯地图 key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', '1', '腾讯地图 key', '1', to_date('2023-06-03 19:16:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-03 19:16:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', to_date('2023-12-03 09:55:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-03 09:55:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE infra_config_seq + START WITH 13; + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +CREATE TABLE infra_data_source_config +( + id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + url varchar2(1024) NOT NULL, + username varchar2(255) NOT NULL, + password varchar2(255) DEFAULT '' NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_data_source_config + ADD CONSTRAINT pk_infra_data_source_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_data_source_config.id IS '主键编号'; +COMMENT ON COLUMN infra_data_source_config.name IS '参数名称'; +COMMENT ON COLUMN infra_data_source_config.url IS '数据源连接'; +COMMENT ON COLUMN infra_data_source_config.username IS '用户名'; +COMMENT ON COLUMN infra_data_source_config.password IS '密码'; +COMMENT ON COLUMN infra_data_source_config.creator IS '创建者'; +COMMENT ON COLUMN infra_data_source_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_data_source_config.updater IS '更新者'; +COMMENT ON COLUMN infra_data_source_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_data_source_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_data_source_config IS '数据源配置表'; + +CREATE SEQUENCE infra_data_source_config_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +CREATE TABLE infra_file +( + id number NOT NULL, + config_id number DEFAULT NULL NULL, + name varchar2(256) DEFAULT NULL NULL, + path varchar2(512) NOT NULL, + url varchar2(1024) NOT NULL, + type varchar2(128) DEFAULT NULL NULL, + "size" number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_file + ADD CONSTRAINT pk_infra_file PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file.id IS '文件编号'; +COMMENT ON COLUMN infra_file.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file.name IS '文件名'; +COMMENT ON COLUMN infra_file.path IS '文件路径'; +COMMENT ON COLUMN infra_file.url IS '文件 URL'; +COMMENT ON COLUMN infra_file.type IS '文件类型'; +COMMENT ON COLUMN infra_file.size IS '文件大小'; +COMMENT ON COLUMN infra_file.creator IS '创建者'; +COMMENT ON COLUMN infra_file.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file.updater IS '更新者'; +COMMENT ON COLUMN infra_file.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file.deleted IS '是否删除'; +COMMENT ON TABLE infra_file IS '文件表'; + +CREATE SEQUENCE infra_file_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +CREATE TABLE infra_file_config +( + id number NOT NULL, + name varchar2(63) NOT NULL, + storage smallint NOT NULL, + remark varchar2(255) DEFAULT NULL NULL, + master number(1, 0) NOT NULL, + config varchar2(4000) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_file_config + ADD CONSTRAINT pk_infra_file_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_config.id IS '编号'; +COMMENT ON COLUMN infra_file_config.name IS '配置名'; +COMMENT ON COLUMN infra_file_config.storage IS '存储器'; +COMMENT ON COLUMN infra_file_config.remark IS '备注'; +COMMENT ON COLUMN infra_file_config.master IS '是否为主配置'; +COMMENT ON COLUMN infra_file_config.config IS '存储配置'; +COMMENT ON COLUMN infra_file_config.creator IS '创建者'; +COMMENT ON COLUMN infra_file_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_config.updater IS '更新者'; +COMMENT ON COLUMN infra_file_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_config IS '文件配置表'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', to_date('2022-03-15 23:56:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-28 22:54:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', to_date('2024-01-13 22:11:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-03 19:38:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE infra_file_config_seq + START WITH 23; + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +CREATE TABLE infra_file_content +( + id number NOT NULL, + config_id number NOT NULL, + path varchar2(512) NOT NULL, + content blob NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_file_content + ADD CONSTRAINT pk_infra_file_content PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_content.id IS '编号'; +COMMENT ON COLUMN infra_file_content.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file_content.path IS '文件路径'; +COMMENT ON COLUMN infra_file_content.content IS '文件内容'; +COMMENT ON COLUMN infra_file_content.creator IS '创建者'; +COMMENT ON COLUMN infra_file_content.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_content.updater IS '更新者'; +COMMENT ON COLUMN infra_file_content.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_content.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_content IS '文件表'; + +CREATE SEQUENCE infra_file_content_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +CREATE TABLE infra_job +( + id number NOT NULL, + name varchar2(32) NOT NULL, + status smallint NOT NULL, + handler_name varchar2(64) NOT NULL, + handler_param varchar2(255) DEFAULT NULL NULL, + cron_expression varchar2(32) NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + retry_interval number DEFAULT 0 NOT NULL, + monitor_timeout number DEFAULT 0 NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_job + ADD CONSTRAINT pk_infra_job PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job.id IS '任务编号'; +COMMENT ON COLUMN infra_job.name IS '任务名称'; +COMMENT ON COLUMN infra_job.status IS '任务状态'; +COMMENT ON COLUMN infra_job.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job.cron_expression IS 'CRON 表达式'; +COMMENT ON COLUMN infra_job.retry_count IS '重试次数'; +COMMENT ON COLUMN infra_job.retry_interval IS '重试间隔'; +COMMENT ON COLUMN infra_job.monitor_timeout IS '监控超时时间'; +COMMENT ON COLUMN infra_job.creator IS '创建者'; +COMMENT ON COLUMN infra_job.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job.updater IS '更新者'; +COMMENT ON COLUMN infra_job.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job.deleted IS '是否删除'; +COMMENT ON TABLE infra_job IS '定时任务表'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', to_date('2021-10-27 08:34:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-09 20:51:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', to_date('2023-07-22 14:36:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-22 15:39:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', to_date('2023-07-22 15:36:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-22 15:39:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', to_date('2023-07-23 21:03:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-23 21:09:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', to_date('2023-09-25 23:43:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-26 19:23:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', to_date('2023-09-26 19:23:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-26 23:38:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', to_date('2023-09-26 23:38:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-27 11:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', to_date('2023-09-28 22:01:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 22:01:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', to_date('2023-10-03 10:59:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 11:01:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', to_date('2023-10-03 11:00:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 11:01:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', to_date('2023-10-03 11:01:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 11:01:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE infra_job_seq + START WITH 28; + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +CREATE TABLE infra_job_log +( + id number NOT NULL, + job_id number NOT NULL, + handler_name varchar2(64) NOT NULL, + handler_param varchar2(255) DEFAULT NULL NULL, + execute_index smallint DEFAULT 1 NOT NULL, + begin_time date NOT NULL, + end_time date DEFAULT NULL NULL, + duration number DEFAULT NULL NULL, + status smallint NOT NULL, + result varchar2(4000) DEFAULT '' NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE infra_job_log + ADD CONSTRAINT pk_infra_job_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job_log.id IS '日志编号'; +COMMENT ON COLUMN infra_job_log.job_id IS '任务编号'; +COMMENT ON COLUMN infra_job_log.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job_log.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job_log.execute_index IS '第几次执行'; +COMMENT ON COLUMN infra_job_log.begin_time IS '开始执行时间'; +COMMENT ON COLUMN infra_job_log.end_time IS '结束执行时间'; +COMMENT ON COLUMN infra_job_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_job_log.status IS '任务状态'; +COMMENT ON COLUMN infra_job_log.result IS '结果数据'; +COMMENT ON COLUMN infra_job_log.creator IS '创建者'; +COMMENT ON COLUMN infra_job_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job_log.updater IS '更新者'; +COMMENT ON COLUMN infra_job_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job_log.deleted IS '是否删除'; +COMMENT ON TABLE infra_job_log IS '定时任务日志表'; + +CREATE SEQUENCE infra_job_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +CREATE TABLE system_dept +( + id number NOT NULL, + name varchar2(30) DEFAULT '' NULL, + parent_id number DEFAULT 0 NOT NULL, + sort number DEFAULT 0 NOT NULL, + leader_user_id number DEFAULT NULL NULL, + phone varchar2(11) DEFAULT NULL NULL, + email varchar2(50) DEFAULT NULL NULL, + status smallint NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_dept + ADD CONSTRAINT pk_system_dept PRIMARY KEY (id); + +COMMENT ON COLUMN system_dept.id IS '部门id'; +COMMENT ON COLUMN system_dept.name IS '部门名称'; +COMMENT ON COLUMN system_dept.parent_id IS '父部门id'; +COMMENT ON COLUMN system_dept.sort IS '显示顺序'; +COMMENT ON COLUMN system_dept.leader_user_id IS '负责人'; +COMMENT ON COLUMN system_dept.phone IS '联系电话'; +COMMENT ON COLUMN system_dept.email IS '邮箱'; +COMMENT ON COLUMN system_dept.status IS '部门状态(0正常 1停用)'; +COMMENT ON COLUMN system_dept.creator IS '创建者'; +COMMENT ON COLUMN system_dept.create_time IS '创建时间'; +COMMENT ON COLUMN system_dept.updater IS '更新者'; +COMMENT ON COLUMN system_dept.update_time IS '更新时间'; +COMMENT ON COLUMN system_dept.deleted IS '是否删除'; +COMMENT ON COLUMN system_dept.tenant_id IS '租户编号'; +COMMENT ON TABLE system_dept IS '部门表'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-14 23:30:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 09:53:35', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-12-15 05:01:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-24 20:56:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-12-15 05:01:38', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-16 20:25:15', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '103', to_date('2022-01-15 21:32:22', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, '运维部门', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 09:28:22', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 08:35:45', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-12-15 05:01:29', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', to_date('2022-02-23 20:46:30', 'SYYYY-MM-DD HH24:MI:SS'), '110', to_date('2022-02-23 20:46:30', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', to_date('2022-03-07 21:44:50', 'SYYYY-MM-DD HH24:MI:SS'), '113', to_date('2022-03-07 21:44:50', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, '产品部门', 101, 100, 1, NULL, NULL, 1, '1', to_date('2023-12-02 09:45:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 09:45:31', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, '支持部门', 102, 3, 104, NULL, NULL, 1, '1', to_date('2023-12-02 09:47:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 09:47:38', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_dept_seq + START WITH 114; + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +CREATE TABLE system_dict_data +( + id number NOT NULL, + sort number DEFAULT 0 NOT NULL, + label varchar2(100) DEFAULT '' NULL, + value varchar2(100) DEFAULT '' NULL, + dict_type varchar2(100) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + color_type varchar2(100) DEFAULT '' NULL, + css_class varchar2(100) DEFAULT '' NULL, + remark varchar2(500) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_dict_data + ADD CONSTRAINT pk_system_dict_data PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_data.id IS '字典编码'; +COMMENT ON COLUMN system_dict_data.sort IS '字典排序'; +COMMENT ON COLUMN system_dict_data.label IS '字典标签'; +COMMENT ON COLUMN system_dict_data.value IS '字典键值'; +COMMENT ON COLUMN system_dict_data.dict_type IS '字典类型'; +COMMENT ON COLUMN system_dict_data.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_data.color_type IS '颜色类型'; +COMMENT ON COLUMN system_dict_data.css_class IS 'css 样式'; +COMMENT ON COLUMN system_dict_data.remark IS '备注'; +COMMENT ON COLUMN system_dict_data.creator IS '创建者'; +COMMENT ON COLUMN system_dict_data.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_data.updater IS '更新者'; +COMMENT ON COLUMN system_dict_data.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_data.deleted IS '是否删除'; +COMMENT ON TABLE system_dict_data IS '字典数据表'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-29 00:14:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-15 23:30:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:33:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:33:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:06:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, '自定义', '2', 'infra_config_type', 0, 'primary', '', '参数类型 - 自定义', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:06:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '通知', '1', 'system_notice_type', 0, 'success', '', '通知', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:05:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '公告', '2', 'system_notice_type', 0, 'info', '', '公告', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:06:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '其它', '0', 'infra_operate_type', 0, 'default', '', '其它操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, '查询', '1', 'infra_operate_type', 0, 'info', '', '查询操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '新增', '2', 'infra_operate_type', 0, 'primary', '', '新增操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '修改', '3', 'infra_operate_type', 0, 'warning', '', '修改操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, '删除', '4', 'infra_operate_type', 0, 'danger', '', '删除操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '导出', '5', 'infra_operate_type', 0, 'default', '', '导出操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '导入', '6', 'infra_operate_type', 0, 'default', '', '导入操作', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '开启', '0', 'common_status', 0, 'primary', '', '开启状态', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 08:00:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, '关闭', '1', 'common_status', 0, 'info', '', '关闭状态', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 08:00:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, '目录', '1', 'system_menu_type', 0, '', '', '目录', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:43:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '菜单', '2', 'system_menu_type', 0, '', '', '菜单', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:43:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, '按钮', '3', 'system_menu_type', 0, '', '', '按钮', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:43:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '内置', '1', 'system_role_type', 0, 'danger', '', '内置角色', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:02:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, '自定义', '2', 'system_role_type', 0, 'primary', '', '自定义角色', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:02:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, '全部数据权限', '1', 'system_data_scope', 0, '', '', '全部数据权限', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:47:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, '指定部门数据权限', '2', 'system_data_scope', 0, '', '', '指定部门数据权限', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:47:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:47:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:47:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:47:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', to_date('2021-01-18 06:17:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:23:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', to_date('2021-01-18 06:17:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:24:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', to_date('2021-01-18 06:17:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:23:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '验证码不存在', '30', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不存在', '', to_date('2021-01-18 06:17:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:24:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '验证码不正确', '31', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不正确', '', to_date('2021-01-18 06:17:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:24:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, '未知异常', '100', 'system_login_result', 0, 'danger', '', '登陆结果 - 未知异常', '', to_date('2021-01-18 06:17:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:24:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '是', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 是否类型 - 是', '', to_date('2021-01-19 03:20:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 23:01:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '否', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 是否类型 - 否', '', to_date('2021-01-19 03:20:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 23:09:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, '单表(增删改查)', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', to_date('2021-02-05 07:09:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-03-10 16:33:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, '树表(增删改查)', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', to_date('2021-02-05 07:14:46', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-03-10 16:33:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, '初始化中', '0', 'infra_job_status', 0, 'primary', '', NULL, '', to_date('2021-02-07 07:46:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:33:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '运行中', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', to_date('2021-02-08 10:04:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:07:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, '成功', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', to_date('2021-02-08 10:06:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:07:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, '失败', '2', 'infra_job_log_status', 0, 'warning', '', '失败', '', to_date('2021-02-08 10:07:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 19:07:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, '会员', '1', 'user_type', 0, 'primary', '', NULL, '', to_date('2021-02-26 00:16:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:22:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, '管理员', '2', 'user_type', 0, 'success', '', NULL, '', to_date('2021-02-26 00:16:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:22:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', to_date('2021-02-26 07:07:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 20:14:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', to_date('2021-02-26 07:07:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 20:14:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', to_date('2021-02-26 07:07:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 20:14:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', to_date('2021-04-05 01:05:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:09:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', to_date('2021-04-05 21:50:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 12:48:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', to_date('2021-04-05 21:51:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 12:48:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, '营销', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', to_date('2021-04-05 21:51:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 12:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, '初始化', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', to_date('2021-04-11 20:18:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:26:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, '发送成功', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', to_date('2021-04-11 20:18:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:25:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, '发送失败', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', to_date('2021-04-11 20:18:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:26:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '不发送', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', to_date('2021-04-11 20:19:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:26:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, '等待结果', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', to_date('2021-04-11 20:27:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:28:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', to_date('2021-04-11 20:29:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:28:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', to_date('2021-04-11 20:29:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:28:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', to_date('2021-04-13 00:20:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:10:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', to_date('2021-10-06 00:52:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:11:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', to_date('2021-10-06 00:52:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:11:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', to_date('2021-10-06 00:52:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:11:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', to_date('2021-10-06 00:53:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:11:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', to_date('2021-09-21 22:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:00:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', to_date('2021-09-21 22:36:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:00:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', to_date('2021-09-21 22:36:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 10:00:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', to_date('2021-12-03 10:40:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:08:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', to_date('2021-12-03 10:41:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:08:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', to_date('2021-12-03 10:41:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '支付宝 PC 网站支付', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '支付宝 PC 网站支付', '1', to_date('2021-12-03 10:42:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', to_date('2021-12-03 10:42:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', to_date('2021-12-03 10:42:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', to_date('2021-12-03 10:43:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', to_date('2021-12-03 11:02:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', to_date('2021-12-03 11:02:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', to_date('2021-12-03 11:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:08:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', to_date('2021-12-03 11:18:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:04:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', to_date('2021-12-03 11:18:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:05:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', to_date('2021-12-03 11:18:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:04:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', to_date('2021-12-10 16:44:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:14:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', to_date('2021-12-10 16:45:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:15:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', to_date('2021-12-10 16:46:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:15:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', to_date('2022-01-07 23:47:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-16 16:11:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', to_date('2022-01-07 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-16 16:11:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', to_date('2022-01-07 23:48:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', to_date('2022-01-07 23:48:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', to_date('2022-01-07 23:48:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', to_date('2022-01-07 23:49:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', to_date('2022-01-11 23:51:30', 'SYYYY-MM-DD HH24:MI:SS'), '103', to_date('2022-01-11 23:51:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', to_date('2022-01-11 23:51:47', 'SYYYY-MM-DD HH24:MI:SS'), '103', to_date('2022-01-11 23:51:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', to_date('2022-01-12 23:21:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', to_date('2022-01-12 23:21:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', to_date('2022-01-12 23:33:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', to_date('2022-01-12 23:34:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', to_date('2022-01-12 23:34:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', to_date('2022-01-12 23:34:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', to_date('2022-01-14 18:41:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-06 02:53:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', to_date('2022-02-02 13:15:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-10 16:32:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', to_date('2022-02-02 13:15:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-10 16:33:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', to_date('2022-03-15 00:25:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:25:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, '本地磁盘', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', to_date('2022-03-15 00:25:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:25:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP 服务器', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', to_date('2022-03-15 00:26:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:26:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP 服务器', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', to_date('2022-03-15 00:26:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:26:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 对象存储', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', to_date('2022-03-15 00:26:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:26:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, '短信登录', '103', 'system_login_type', 0, 'default', '', NULL, '1', to_date('2022-05-09 23:57:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-09 23:58:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '密码模式', '1', to_date('2022-05-12 00:22:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:26:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '授权码模式', '1', to_date('2022-05-12 00:22:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:26:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '简化模式', '1', to_date('2022-05-12 00:23:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:26:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '客户端模式', '1', to_date('2022-05-12 00:23:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:26:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '刷新模式', '1', to_date('2022-05-12 00:24:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:26:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '销售中', '1', 'product_spu_status', 0, 'success', '', '商品 SPU 状态 - 销售中', '1', to_date('2022-10-24 21:19:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-10-24 21:20:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, '仓库中', '0', 'product_spu_status', 0, 'info', '', '商品 SPU 状态 - 仓库中', '1', to_date('2022-10-24 21:20:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-10-24 21:21:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, '回收站', '-1', 'product_spu_status', 0, 'default', '', '商品 SPU 状态 - 回收站', '1', to_date('2022-10-24 21:21:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-10-24 21:21:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '满减', '1', 'promotion_discount_type', 0, 'success', '', '优惠类型 - 满减', '1', to_date('2022-11-01 12:46:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-01 12:50:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', to_date('2022-11-01 12:46:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-01 12:50:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', to_date('2022-11-02 00:07:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 00:07:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', to_date('2022-11-02 00:07:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 00:07:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, '通用劵', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', to_date('2022-11-02 00:28:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 00:27:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, '商品劵', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', to_date('2022-11-02 00:28:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 00:27:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, '未使用', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', to_date('2022-11-04 00:15:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 12:54:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', to_date('2022-11-04 00:15:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 19:16:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', to_date('2022-11-04 00:15:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 19:16:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, '直接领取', '1', 'promotion_coupon_take_type', 0, 'primary', '', '优惠劵的领取方式 - 直接领取', '1', to_date('2022-11-04 19:13:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 19:13:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, '指定发放', '2', 'promotion_coupon_take_type', 0, 'success', '', '优惠劵的领取方式 - 指定发放', '1', to_date('2022-11-04 19:13:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 19:14:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, '未开始', '10', 'promotion_activity_status', 0, 'primary', '', '促销活动的状态枚举 - 未开始', '1', to_date('2022-11-04 22:54:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:55:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '进行中', '20', 'promotion_activity_status', 0, 'success', '', '促销活动的状态枚举 - 进行中', '1', to_date('2022-11-04 22:55:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:55:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, '已结束', '30', 'promotion_activity_status', 0, 'info', '', '促销活动的状态枚举 - 已结束', '1', to_date('2022-11-04 22:55:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:55:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, '已关闭', '40', 'promotion_activity_status', 0, 'warning', '', '促销活动的状态枚举 - 已关闭', '1', to_date('2022-11-04 22:56:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:56:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, '满 N 元', '10', 'promotion_condition_type', 0, 'primary', '', '营销的条件类型 - 满 N 元', '1', to_date('2022-11-04 22:59:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:59:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, '满 N 件', '20', 'promotion_condition_type', 0, 'success', '', '营销的条件类型 - 满 N 件', '1', to_date('2022-11-04 23:00:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 23:00:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, '申请售后', '10', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 申请售后', '1', to_date('2022-11-19 20:53:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 20:54:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, '商品待退货', '20', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商品待退货', '1', to_date('2022-11-19 20:54:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 20:58:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '商家待收货', '30', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商家待收货', '1', to_date('2022-11-19 20:56:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 20:59:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, '等待退款', '40', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 等待退款', '1', to_date('2022-11-19 20:59:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:00:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '退款成功', '50', 'trade_after_sale_status', 0, 'default', '', '交易售后状态 - 退款成功', '1', to_date('2022-11-19 21:00:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:00:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, '买家取消', '61', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 买家取消', '1', to_date('2022-11-19 21:01:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:01:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '商家拒绝', '62', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒绝', '1', to_date('2022-11-19 21:02:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:02:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '商家拒收货', '63', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒收货', '1', to_date('2022-11-19 21:02:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:03:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '售中退款', '10', 'trade_after_sale_type', 0, 'success', '', '交易售后的类型 - 售中退款', '1', to_date('2022-11-19 21:05:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:38:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, '售后退款', '20', 'trade_after_sale_type', 0, 'primary', '', '交易售后的类型 - 售后退款', '1', to_date('2022-11-19 21:05:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:38:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '仅退款', '10', 'trade_after_sale_way', 0, 'primary', '', '交易售后的方式 - 仅退款', '1', to_date('2022-11-19 21:39:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:39:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '退货退款', '20', 'trade_after_sale_way', 0, 'success', '', '交易售后的方式 - 退货退款', '1', to_date('2022-11-19 21:39:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:39:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '微信小程序', '10', 'terminal', 0, 'default', '', '终端 - 微信小程序', '1', to_date('2022-12-10 10:51:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:51:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 网页', '20', 'terminal', 0, 'default', '', '终端 - H5 网页', '1', to_date('2022-12-10 10:51:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:51:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '微信公众号', '11', 'terminal', 0, 'default', '', '终端 - 微信公众号', '1', to_date('2022-12-10 10:54:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:52:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, '苹果 App', '31', 'terminal', 0, 'default', '', '终端 - 苹果 App', '1', to_date('2022-12-10 10:54:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:52:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', to_date('2022-12-10 10:55:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:59:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', to_date('2022-12-10 16:34:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:34:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', to_date('2022-12-10 16:34:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:34:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', to_date('2022-12-10 16:34:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:34:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', to_date('2022-12-10 16:34:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:34:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', to_date('2022-12-10 16:49:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:49:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', to_date('2022-12-10 16:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:51:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', to_date('2022-12-10 16:50:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:51:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '已完成', '30', 'trade_order_status', 0, 'success', '', '交易订单状态 - 已完成', '1', to_date('2022-12-10 16:50:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:51:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, '已取消', '40', 'trade_order_status', 0, 'danger', '', '交易订单状态 - 已取消', '1', to_date('2022-12-10 16:50:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:51:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, '未售后', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '交易订单项的售后状态 - 未售后', '1', to_date('2022-12-10 20:58:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 20:59:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, '售后中', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '交易订单项的售后状态 - 售后中', '1', to_date('2022-12-10 20:59:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 20:59:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, '已退款', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '交易订单项的售后状态 - 已退款', '1', to_date('2022-12-10 20:59:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 20:59:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, '完全匹配', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '公众号自动回复的请求关键字匹配模式 - 完全匹配', '1', to_date('2023-01-16 23:30:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 23:31:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, '半匹配', '2', 'mp_auto_reply_request_match', 0, 'success', '', '公众号自动回复的请求关键字匹配模式 - 半匹配', '1', to_date('2023-01-16 23:30:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 23:31:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, '文本', 'text', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 文本', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 22:17:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, '图片', 'image', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图片', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:19:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '语音', 'voice', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 语音', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:20:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, '视频', 'video', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 视频', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:21:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, '小视频', 'shortvideo', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 小视频', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:19:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, '图文', 'news', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图文', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:22:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '音乐', 'music', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 音乐', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:22:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, '地理位置', 'location', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 地理位置', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:23:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '链接', 'link', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 链接', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '事件', 'event', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 事件', '1', to_date('2023-01-17 22:17:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 14:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, '初始化', '0', 'system_mail_send_status', 0, 'primary', '', '邮件发送状态 - 初始化\n', '1', to_date('2023-01-26 09:53:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 16:36:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', to_date('2023-01-26 09:54:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 16:36:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', to_date('2023-01-26 09:54:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 16:36:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', to_date('2023-01-26 09:55:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 16:36:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', to_date('2023-01-28 10:35:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 10:35:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', to_date('2023-01-28 10:36:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 10:36:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', to_date('2023-02-18 23:32:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', to_date('2023-04-13 00:03:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-13 00:03:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', to_date('2023-04-13 00:04:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-13 00:04:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', to_date('2023-04-13 00:04:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-13 00:04:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', to_date('2023-04-13 00:04:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-13 00:04:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', to_date('2023-05-21 22:46:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-05-21 22:46:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', to_date('2023-05-21 22:46:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-05-21 22:46:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', to_date('2023-05-21 22:47:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-05-21 22:47:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, '订单积分抵扣', '11', 'member_point_biz_type', 0, '', '', '', '1', to_date('2023-06-10 12:15:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:41:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, '签到', '1', 'member_point_biz_type', 0, '', '', '', '1', to_date('2023-06-10 12:15:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 11:59:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '已退款', '20', 'pay_order_status', 0, 'danger', '', '已退款', '1', to_date('2023-07-19 18:05:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:05:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, '请求成功,但是结果失败', '21', 'pay_notify_status', 0, 'warning', '', '请求成功,但是结果失败', '1', to_date('2023-07-19 18:10:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:11:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, '请求失败', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', to_date('2023-07-19 18:11:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:11:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '微信扫码支付', 'wx_native', 'pay_channel_code', 0, 'success', '', '微信扫码支付', '1', to_date('2023-07-19 20:07:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '微信条码支付', 'wx_bar', 'pay_channel_code', 0, 'success', '', '微信条码支付\n', '1', to_date('2023-07-19 20:08:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 20:09:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '支付单', '1', 'pay_notify_type', 0, 'primary', '', '支付单', '1', to_date('2023-07-20 12:23:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-20 12:23:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', to_date('2023-07-20 12:23:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-20 12:23:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', to_date('2023-07-29 11:10:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-29 03:14:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, '订单积分抵扣(整单取消)', '12', 'member_point_biz_type', 0, '', '', '', '1', to_date('2023-08-20 12:00:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:42:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, '下单奖励', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, '下单奖励(整单取消)', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', to_date('2023-08-23 00:04:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-23 00:04:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', to_date('2023-08-23 00:05:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-23 00:05:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, '品类劵', '3', 'promotion_product_scope', 0, 'default', '', '', '1', to_date('2023-09-01 23:43:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 00:27:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '人人分销', '1', 'brokerage_enabled_condition', 0, '', '', '所有用户都可以分销', '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, '指定分销', '2', 'brokerage_enabled_condition', 0, '', '', '仅可后台手动设置推广员', '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '首次绑定', '1', 'brokerage_bind_mode', 0, '', '', '只要用户没有推广人,随时都可以绑定推广关系', '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, '注册绑定', '2', 'brokerage_bind_mode', 0, '', '', '仅新用户注册时才能绑定推广关系', '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, '申请提现驳回', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '待结算', '0', 'brokerage_record_status', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, '已结算', '1', 'brokerage_record_status', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, '已取消', '2', 'brokerage_record_status', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '审核中', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, '审核通过', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, '提现成功', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '审核不通过', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, '提现失败', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '工商银行', '0', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '建设银行', '1', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, '农业银行', '2', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, '中国银行', '3', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, '交通银行', '4', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '招商银行', '5', 'brokerage_bank_name', 0, '', '', NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, '钱包', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', to_date('2023-10-01 21:46:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 21:48:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', to_date('2023-10-05 10:41:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 10:41:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', to_date('2023-10-05 10:41:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 10:41:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', to_date('2023-10-05 10:41:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 10:41:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', to_date('2023-10-08 07:24:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-08 07:24:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', to_date('2023-10-08 07:24:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-08 07:24:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', to_date('2023-10-08 07:25:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-08 07:25:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', to_date('2023-10-11 07:41:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:41:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', to_date('2023-10-11 07:42:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:42:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', to_date('2023-10-11 07:42:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:42:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', to_date('2023-10-11 07:42:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:43:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', to_date('2023-10-11 07:43:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:43:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', to_date('2023-10-11 07:45:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-11 07:45:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:55:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:55:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '支付宝', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:55:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:55:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '微信支付', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:55:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:55:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '其他', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:56:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:56:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:02:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:30:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, '金融业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:02:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:30:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, '房地产', '3', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:02:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:30:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, '商业服务', '4', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:02:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:30:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '运输/物流', '5', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:03:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:31:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '生产', '6', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:03:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:31:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '政府', '7', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:03:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:31:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, '文化传媒', '8', 'crm_customer_industry', 0, 'default', '', '', '1', to_date('2023-10-28 23:03:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:31:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', to_date('2023-10-28 23:07:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:07:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', to_date('2023-10-28 23:07:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:07:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', to_date('2023-10-28 23:07:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:07:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:08:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:08:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:08:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:08:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:08:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:08:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:08:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:08:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:09:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:09:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:09:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:09:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:10:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:10:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:10:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:10:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', to_date('2023-10-28 23:10:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 23:10:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:04:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:04:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:04:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:04:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:05:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:05:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:05:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', to_date('2023-10-30 21:49:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-30 21:49:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', to_date('2023-10-30 21:49:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-30 21:49:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', to_date('2023-11-13 23:06:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-13 23:06:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', to_date('2023-11-14 12:32:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-14 12:32:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', to_date('2023-11-14 12:33:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-14 12:33:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', to_date('2023-11-14 12:33:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-14 12:33:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '负责人', '1', 'crm_permission_level', 0, 'default', '', '', '1', to_date('2023-11-30 09:53:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 09:53:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, '只读', '2', 'crm_permission_level', 0, '', '', '', '1', to_date('2023-11-30 09:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 09:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, '读写', '3', 'crm_permission_level', 0, '', '', '', '1', to_date('2023-11-30 09:53:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 09:53:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, '未提交', '0', 'crm_audit_status', 0, '', '', '', '1', to_date('2023-11-30 18:56:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:56:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '审批中', '10', 'crm_audit_status', 0, '', '', '', '1', to_date('2023-11-30 18:57:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:57:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, '审核通过', '20', 'crm_audit_status', 0, '', '', '', '1', to_date('2023-11-30 18:57:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:57:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '审核不通过', '30', 'crm_audit_status', 0, '', '', '', '1', to_date('2023-11-30 18:57:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:57:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, '已取消', '40', 'crm_audit_status', 0, '', '', '', '1', to_date('2023-11-30 18:57:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:57:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '支票', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:54:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:54:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, '现金', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:54:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:54:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '邮政汇款', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:54:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:54:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '电汇', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:55:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:55:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', to_date('2023-10-18 21:55:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:55:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '个', '1', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:02:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:02:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '块', '2', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:02:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:02:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, '只', '3', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:02:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:02:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '把', '4', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, '枚', '5', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, '瓶', '6', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '盒', '7', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '台', '8', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '吨', '9', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, '千克', '10', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:04:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:04:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '米', '11', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:04:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:04:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '箱', '12', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:04:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:04:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '套', '13', 'crm_product_unit', 0, '', '', '', '1', to_date('2023-12-05 23:04:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:04:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '打电话', '1', 'crm_follow_up_type', 0, '', '', '', '1', to_date('2024-01-15 20:48:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-15 20:48:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '发短信', '2', 'crm_follow_up_type', 0, '', '', '', '1', to_date('2024-01-15 20:48:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-15 20:48:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, '上门拜访', '3', 'crm_follow_up_type', 0, '', '', '', '1', to_date('2024-01-15 20:49:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-15 20:49:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '微信沟通', '4', 'crm_follow_up_type', 0, '', '', '', '1', to_date('2024-01-15 20:49:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-15 20:49:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', to_date('2023-10-28 16:28:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:28:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', to_date('2023-10-28 16:28:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:28:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', to_date('2023-10-28 16:28:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:28:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', to_date('2023-10-28 16:27:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:27:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', to_date('2023-10-28 16:24:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:24:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', to_date('2023-10-28 16:23:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:23:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', to_date('2023-10-28 16:23:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:23:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', to_date('2023-10-28 16:21:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:23:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '其它入库', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-05 18:07:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 18:07:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '其它入库(作废)', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-05 18:08:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 19:20:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '其它出库', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-05 18:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 18:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '其它出库(作废)', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-05 18:09:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 19:20:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, '未审核', '10', 'erp_audit_status', 0, 'default', '', '', '1', to_date('2024-02-06 00:00:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 00:00:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '已审核', '20', 'erp_audit_status', 0, 'success', '', '', '1', to_date('2024-02-06 00:00:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 00:00:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '调拨入库', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-07 20:34:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 12:36:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '调拨入库(作废)', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-07 20:34:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 20:37:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '调拨出库', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-07 20:34:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 12:36:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '调拨出库(作废)', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-07 20:34:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 20:37:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, '盘盈入库', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-08 08:53:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-08 08:53:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, '盘盈入库(作废)', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-08 08:53:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 19:40:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '盘亏出库', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-08 08:54:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-08 08:54:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '盘亏出库(作废)', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-08 08:54:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 19:40:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '销售出库', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-11 21:47:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-11 21:50:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '销售出库(作废)', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-11 21:47:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-11 21:51:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '销售退货入库', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-12 06:51:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 06:51:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '销售退货入库(作废)', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-12 06:51:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 06:51:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, '采购入库', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-16 13:10:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 13:10:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-16 13:10:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 19:40:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', to_date('2024-02-16 13:10:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 13:10:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', to_date('2024-02-16 13:10:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 19:40:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', to_date('2024-03-16 16:12:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-16 16:12:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', to_date('2024-03-16 16:12:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-16 16:12:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', to_date('2024-03-16 19:10:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', to_date('2024-03-17 10:06:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', to_date('2024-03-17 10:06:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', to_date('2024-03-17 10:07:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:41:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', to_date('2024-03-22 19:45:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-22 19:45:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', to_date('2024-03-23 12:54:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:14:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', to_date('2024-03-23 12:54:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:14:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', to_date('2024-03-23 15:08:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:14:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', to_date('2024-03-23 15:09:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:14:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', to_date('2024-03-23 15:11:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:14:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '天', '1', 'date_interval', 0, '', '', '', '1', to_date('2024-03-29 22:50:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:50:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '周', '2', 'date_interval', 0, '', '', '', '1', to_date('2024-03-29 22:50:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:50:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', to_date('2024-03-29 22:50:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:50:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', to_date('2024-03-29 22:51:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:51:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', to_date('2024-03-29 22:51:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:51:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', to_date('2024-04-13 23:26:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-13 23:26:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', to_date('2024-04-13 23:27:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-13 23:27:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', to_date('2024-04-13 23:27:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-13 23:27:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_dict_data_seq + START WITH 1537; + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +CREATE TABLE system_dict_type +( + id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + type varchar2(100) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + remark varchar2(500) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + deleted_time date DEFAULT NULL NULL +); + +ALTER TABLE system_dict_type + ADD CONSTRAINT pk_system_dict_type PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_type.id IS '字典主键'; +COMMENT ON COLUMN system_dict_type.name IS '字典名称'; +COMMENT ON COLUMN system_dict_type.type IS '字典类型'; +COMMENT ON COLUMN system_dict_type.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_type.remark IS '备注'; +COMMENT ON COLUMN system_dict_type.creator IS '创建者'; +COMMENT ON COLUMN system_dict_type.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_type.updater IS '更新者'; +COMMENT ON COLUMN system_dict_type.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_type.deleted IS '是否删除'; +COMMENT ON COLUMN system_dict_type.deleted_time IS '删除时间'; +COMMENT ON TABLE system_dict_type IS '字典类型表'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-16 20:29:32', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:36:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:35:26', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '操作类型', 'infra_operate_type', 0, NULL, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-14 12:44:01', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:21:28', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', to_date('2021-01-19 03:20:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:37:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '登陆结果', 'system_login_result', 0, '登陆结果', '', to_date('2021-01-18 06:17:11', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:36:00', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, '代码生成模板类型', 'infra_codegen_template_type', 0, NULL, '', to_date('2021-02-05 07:08:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-16 20:26:50', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, '定时任务状态', 'infra_job_status', 0, NULL, '', to_date('2021-02-07 07:44:16', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:51:11', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, '定时任务日志状态', 'infra_job_log_status', 0, NULL, '', to_date('2021-02-08 10:03:51', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:50:43', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, '用户类型', 'user_type', 0, NULL, '', to_date('2021-02-26 00:15:51', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-02-26 00:15:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 异常数据的处理状态', 'infra_api_error_log_process_status', 0, NULL, '', to_date('2021-02-26 07:07:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-01 16:50:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '短信渠道编码', 'system_sms_channel_code', 0, NULL, '1', to_date('2021-04-05 01:04:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 02:09:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', to_date('2021-04-05 21:50:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-01 16:35:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', to_date('2021-04-11 20:18:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-01 16:35:09', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', to_date('2021-04-11 20:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-01 16:35:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', to_date('2021-10-06 00:50:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-01 16:35:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', to_date('2021-09-21 22:34:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-01-22 10:41:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', to_date('2021-12-03 10:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-10 10:11:39', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', to_date('2021-12-03 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 18:09:43', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', to_date('2021-12-03 11:17:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2021-12-03 11:17:50', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', to_date('2021-12-10 16:42:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-19 10:13:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', to_date('2022-01-07 23:46:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-01-07 23:46:42', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', to_date('2022-01-07 23:48:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-08 22:42:03', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', to_date('2022-01-11 23:50:45', 'SYYYY-MM-DD HH24:MI:SS'), '103', to_date('2022-01-11 23:50:45', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', to_date('2022-01-12 23:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '103', to_date('2024-03-06 02:53:59', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', to_date('2022-02-02 13:14:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-10 16:33:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', to_date('2022-02-16 13:01:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-16 13:01:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', to_date('2022-03-15 00:24:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-15 00:24:38', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 授权类型', 'system_oauth2_grant_type', 0, 'OAuth 2.0 授权类型(模式)', '1', to_date('2022-05-12 00:20:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 16:25:49', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, '商品 SPU 状态', 'product_spu_status', 0, '商品 SPU 状态', '1', to_date('2022-10-24 21:19:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-10-24 21:19:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, '优惠类型', 'promotion_discount_type', 0, '优惠类型', '1', to_date('2022-11-01 12:46:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-01 12:46:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, '优惠劵模板的有限期类型', 'promotion_coupon_template_validity_type', 0, '优惠劵模板的有限期类型', '1', to_date('2022-11-02 00:06:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 00:08:26', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, '营销的商品范围', 'promotion_product_scope', 0, '营销的商品范围', '1', to_date('2022-11-02 00:28:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-02 00:28:01', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, '优惠劵的状态', 'promotion_coupon_status', 0, '优惠劵的状态', '1', to_date('2022-11-04 00:14:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 00:14:49', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, '优惠劵的领取方式', 'promotion_coupon_take_type', 0, '优惠劵的领取方式', '1', to_date('2022-11-04 19:12:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 19:12:27', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '促销活动的状态', 'promotion_activity_status', 0, '促销活动的状态', '1', to_date('2022-11-04 22:54:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:54:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, '营销的条件类型', 'promotion_condition_type', 0, '营销的条件类型', '1', to_date('2022-11-04 22:59:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-04 22:59:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, '交易售后状态', 'trade_after_sale_status', 0, '交易售后状态', '1', to_date('2022-11-19 20:52:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 20:52:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, '交易售后的类型', 'trade_after_sale_type', 0, '交易售后的类型', '1', to_date('2022-11-19 21:04:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:04:09', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, '交易售后的方式', 'trade_after_sale_way', 0, '交易售后的方式', '1', to_date('2022-11-19 21:39:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-19 21:39:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, '终端', 'terminal', 0, '终端', '1', to_date('2022-12-10 10:50:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 10:53:11', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '交易订单的类型', 'trade_order_type', 0, '交易订单的类型', '1', to_date('2022-12-10 16:33:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:33:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '交易订单的状态', 'trade_order_status', 0, '交易订单的状态', '1', to_date('2022-12-10 16:48:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 16:48:44', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '交易订单项的售后状态', 'trade_order_item_after_sale_status', 0, '交易订单项的售后状态', '1', to_date('2022-12-10 20:58:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 20:58:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', to_date('2023-01-16 23:29:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 23:29:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', to_date('2023-01-17 22:17:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 22:17:09', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', to_date('2023-01-26 09:53:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 09:53:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', to_date('2023-01-28 10:35:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 10:35:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, '代码生成的前端类型', 'infra_codegen_front_type', 0, '', '1', to_date('2023-04-12 23:57:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-12 23:57:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', to_date('2023-05-21 22:45:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-05-21 22:45:03', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', to_date('2023-06-10 12:15:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-28 13:48:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', to_date('2023-07-20 12:23:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-07-20 12:23:03', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', to_date('2023-08-23 00:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-23 00:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, '分佣模式', 'brokerage_enabled_condition', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, '分销关系绑定模式', 'brokerage_bind_mode', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, '佣金提现类型', 'brokerage_withdraw_type', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, '佣金记录业务类型', 'brokerage_record_biz_type', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, '佣金记录状态', 'brokerage_record_status', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, '佣金提现状态', 'brokerage_withdraw_status', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', to_date('2023-10-05 10:41:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 10:41:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', to_date('2023-10-08 07:24:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-08 07:24:25', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, '回款-回款方式', 'crm_receivable_return_type', 0, '回款-回款方式', '1', to_date('2023-10-18 21:54:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-18 21:54:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM 客户行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', to_date('2023-10-28 22:57:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-18 23:30:22', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', to_date('2023-10-28 22:59:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 15:11:16', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', to_date('2023-10-28 23:00:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 15:11:16', 'SYYYY-MM-DD HH24:MI:SS'), '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', to_date('2023-10-08 07:24:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:04:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', to_date('2023-11-04 13:03:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:03:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', to_date('2023-10-30 21:47:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-30 21:48:45', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM 数据权限的级别', 'crm_permission_level', 0, '', '1', to_date('2023-11-30 09:51:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 09:51:59', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM 审批状态', 'crm_audit_status', 0, '', '1', to_date('2023-11-30 18:56:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-30 18:56:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM 产品单位', 'crm_product_unit', 0, '', '1', to_date('2023-12-05 23:01:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 23:01:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM 跟进方式', 'crm_follow_up_type', 0, '', '1', to_date('2024-01-15 20:48:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-15 20:48:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, '支付转账类型', 'pay_transfer_type', 0, '', '1', to_date('2023-10-28 16:27:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:27:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', to_date('2023-10-28 16:18:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-28 16:18:32', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', to_date('2024-02-05 18:07:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 18:07:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', to_date('2024-02-06 00:00:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 00:00:07', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', to_date('2024-03-23 12:52:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-09 15:54:28', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', to_date('2024-03-23 13:00:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 13:00:31', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', to_date('2024-03-29 22:50:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-29 22:50:09', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', to_date('2024-04-13 23:23:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-13 23:23:00', 'SYYYY-MM-DD HH24:MI:SS'), '0', to_date('1970-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_dict_type_seq + START WITH 620; + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +CREATE TABLE system_login_log +( + id number NOT NULL, + log_type number NOT NULL, + trace_id varchar2(64) DEFAULT '' NULL, + user_id number DEFAULT 0 NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + username varchar2(50) DEFAULT '' NULL, + result smallint NOT NULL, + user_ip varchar2(50) NOT NULL, + user_agent varchar2(512) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_login_log + ADD CONSTRAINT pk_system_login_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_login_log.id IS '访问ID'; +COMMENT ON COLUMN system_login_log.log_type IS '日志类型'; +COMMENT ON COLUMN system_login_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_login_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_login_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_login_log.username IS '用户账号'; +COMMENT ON COLUMN system_login_log.result IS '登陆结果'; +COMMENT ON COLUMN system_login_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_login_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_login_log.creator IS '创建者'; +COMMENT ON COLUMN system_login_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_login_log.updater IS '更新者'; +COMMENT ON COLUMN system_login_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_login_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_login_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_login_log IS '系统访问记录'; + +CREATE SEQUENCE system_login_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +CREATE TABLE system_mail_account +( + id number NOT NULL, + mail varchar2(255) NOT NULL, + username varchar2(255) NOT NULL, + password varchar2(255) NOT NULL, + host varchar2(255) NOT NULL, + port number NOT NULL, + ssl_enable number(1, 0) DEFAULT '0' NOT NULL, + starttls_enable number(1, 0) DEFAULT '0' NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_mail_account + ADD CONSTRAINT pk_system_mail_account PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_account.id IS '主键'; +COMMENT ON COLUMN system_mail_account.mail IS '邮箱'; +COMMENT ON COLUMN system_mail_account.username IS '用户名'; +COMMENT ON COLUMN system_mail_account.password IS '密码'; +COMMENT ON COLUMN system_mail_account.host IS 'SMTP 服务器域名'; +COMMENT ON COLUMN system_mail_account.port IS 'SMTP 服务器端口'; +COMMENT ON COLUMN system_mail_account.ssl_enable IS '是否开启 SSL'; +COMMENT ON COLUMN system_mail_account.starttls_enable IS '是否开启 STARTTLS'; +COMMENT ON COLUMN system_mail_account.creator IS '创建者'; +COMMENT ON COLUMN system_mail_account.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_account.updater IS '更新者'; +COMMENT ON COLUMN system_mail_account.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_account.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_account IS '邮箱账号表'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', to_date('2023-01-25 17:39:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 09:13:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', to_date('2023-01-26 01:26:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-12 22:39:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', to_date('2023-01-27 15:06:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-27 07:08:36', 'SYYYY-MM-DD HH24:MI:SS'), '1'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', to_date('2023-04-12 23:05:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-04-12 15:05:11', 'SYYYY-MM-DD HH24:MI:SS'), '1'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_mail_account_seq + START WITH 5; + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +CREATE TABLE system_mail_log +( + id number NOT NULL, + user_id number DEFAULT NULL NULL, + user_type smallint DEFAULT NULL NULL, + to_mail varchar2(255) NOT NULL, + account_id number NOT NULL, + from_mail varchar2(255) NOT NULL, + template_id number NOT NULL, + template_code varchar2(63) NOT NULL, + template_nickname varchar2(255) DEFAULT NULL NULL, + template_title varchar2(255) NOT NULL, + template_content varchar2(4000) NOT NULL, + template_params varchar2(255) NOT NULL, + send_status smallint DEFAULT 0 NOT NULL, + send_time date DEFAULT NULL NULL, + send_message_id varchar2(255) DEFAULT NULL NULL, + send_exception varchar2(4000) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_mail_log + ADD CONSTRAINT pk_system_mail_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_log.id IS '编号'; +COMMENT ON COLUMN system_mail_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_mail_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_mail_log.to_mail IS '接收邮箱地址'; +COMMENT ON COLUMN system_mail_log.account_id IS '邮箱账号编号'; +COMMENT ON COLUMN system_mail_log.from_mail IS '发送邮箱地址'; +COMMENT ON COLUMN system_mail_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_mail_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_mail_log.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_mail_log.template_title IS '邮件标题'; +COMMENT ON COLUMN system_mail_log.template_content IS '邮件内容'; +COMMENT ON COLUMN system_mail_log.template_params IS '邮件参数'; +COMMENT ON COLUMN system_mail_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_mail_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_mail_log.send_message_id IS '发送返回的消息 ID'; +COMMENT ON COLUMN system_mail_log.send_exception IS '发送异常'; +COMMENT ON COLUMN system_mail_log.creator IS '创建者'; +COMMENT ON COLUMN system_mail_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_log.updater IS '更新者'; +COMMENT ON COLUMN system_mail_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_log.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_log IS '邮件日志表'; + +CREATE SEQUENCE system_mail_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +CREATE TABLE system_mail_template +( + id number NOT NULL, + name varchar2(63) NOT NULL, + code varchar2(63) NOT NULL, + account_id number NOT NULL, + nickname varchar2(255) DEFAULT NULL NULL, + title varchar2(255) NOT NULL, + content varchar2(4000) NOT NULL, + params varchar2(255) NOT NULL, + status smallint NOT NULL, + remark varchar2(255) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_mail_template + ADD CONSTRAINT pk_system_mail_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_template.id IS '编号'; +COMMENT ON COLUMN system_mail_template.name IS '模板名称'; +COMMENT ON COLUMN system_mail_template.code IS '模板编码'; +COMMENT ON COLUMN system_mail_template.account_id IS '发送的邮箱账号编号'; +COMMENT ON COLUMN system_mail_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_mail_template.title IS '模板标题'; +COMMENT ON COLUMN system_mail_template.content IS '模板内容'; +COMMENT ON COLUMN system_mail_template.params IS '参数数组'; +COMMENT ON COLUMN system_mail_template.status IS '开启状态'; +COMMENT ON COLUMN system_mail_template.remark IS '备注'; +COMMENT ON COLUMN system_mail_template.creator IS '创建者'; +COMMENT ON COLUMN system_mail_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_template.updater IS '更新者'; +COMMENT ON COLUMN system_mail_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_template.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_template IS '邮件模版表'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '

您的验证码是{code},名字是{name}

', '["code","name"]', 0, '3', '1', to_date('2021-10-11 08:10:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 19:51:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', '["key01","key02"]', 0, NULL, '1', to_date('2023-01-26 01:27:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-27 10:32:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', to_date('2023-01-27 15:50:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-27 16:34:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_mail_template_seq + START WITH 16; + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +CREATE TABLE system_menu +( + id number NOT NULL, + name varchar2(50) NOT NULL, + permission varchar2(100) DEFAULT '' NULL, + type smallint NOT NULL, + sort number DEFAULT 0 NOT NULL, + parent_id number DEFAULT 0 NOT NULL, + path varchar2(200) DEFAULT '' NULL, + icon varchar2(100) DEFAULT '#' NULL, + component varchar2(255) DEFAULT NULL NULL, + component_name varchar2(255) DEFAULT NULL NULL, + status smallint DEFAULT 0 NOT NULL, + visible number(1, 0) DEFAULT '1' NOT NULL, + keep_alive number(1, 0) DEFAULT '1' NOT NULL, + always_show number(1, 0) DEFAULT '1' NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_menu + ADD CONSTRAINT pk_system_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_menu.id IS '菜单ID'; +COMMENT ON COLUMN system_menu.name IS '菜单名称'; +COMMENT ON COLUMN system_menu.permission IS '权限标识'; +COMMENT ON COLUMN system_menu.type IS '菜单类型'; +COMMENT ON COLUMN system_menu.sort IS '显示顺序'; +COMMENT ON COLUMN system_menu.parent_id IS '父菜单ID'; +COMMENT ON COLUMN system_menu.path IS '路由地址'; +COMMENT ON COLUMN system_menu.icon IS '菜单图标'; +COMMENT ON COLUMN system_menu.component IS '组件路径'; +COMMENT ON COLUMN system_menu.component_name IS '组件名'; +COMMENT ON COLUMN system_menu.status IS '菜单状态'; +COMMENT ON COLUMN system_menu.visible IS '是否可见'; +COMMENT ON COLUMN system_menu.keep_alive IS '是否缓存'; +COMMENT ON COLUMN system_menu.always_show IS '是否总是显示'; +COMMENT ON COLUMN system_menu.creator IS '创建者'; +COMMENT ON COLUMN system_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_menu.updater IS '更新者'; +COMMENT ON COLUMN system_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_menu.deleted IS '是否删除'; +COMMENT ON TABLE system_menu IS '菜单权限表'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:04:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-01 08:28:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', to_date('2021-09-20 16:26:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:38:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:02:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:03:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:03:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:06:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:06:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:07:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:02:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-22 23:56:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:08:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:13:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:57:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:05:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:06:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:06:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:51:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:51:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:01:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:09:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:10:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-09 23:54:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-09 23:54:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-01-06 17:53:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-01-06 17:56:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-01-07 10:23:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-01-26 01:02:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-01-26 01:02:52', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', to_date('2021-02-06 12:42:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-15 23:45:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-02-07 13:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', to_date('2021-02-08 20:41:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', to_date('2021-02-26 01:32:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:54:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-02-26 01:32:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', to_date('2021-02-26 02:18:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-22 23:58:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', to_date('2021-02-26 07:53:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:55:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-02-26 07:53:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-02-26 07:53:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-03-10 01:26:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-03-10 01:28:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-03-10 01:29:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', to_date('2021-03-12 20:16:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:53:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-03-12 20:16:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-03-12 20:16:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', to_date('2021-04-05 01:10:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-22 23:56:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', to_date('2021-04-01 11:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:15:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 11:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 11:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 11:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 11:07:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:16:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-01 17:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-04-11 00:26:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', to_date('2021-04-11 08:37:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:49:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-11 08:37:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-04-11 08:37:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', to_date('2021-12-25 16:43:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:58:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', to_date('2021-09-20 08:51:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:38:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-09-20 08:51:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-09-20 08:51:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', to_date('2021-11-10 01:13:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:59:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-11-08 15:15:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-11-10 01:13:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', to_date('2021-12-14 12:31:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:01:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-14 12:31:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-14 12:31:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-14 12:31:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-14 12:31:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-14 12:31:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2021-11-08 15:15:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:59:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:29:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:59:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-25 08:49:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', to_date('2021-12-30 20:26:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:43:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', to_date('2021-12-30 20:28:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:36:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 12:25:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2021-12-30 12:38:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', to_date('2021-12-31 23:24:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 12:25:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:01:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:01:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:01:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:02:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:02:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-03 19:03:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-01-07 23:51:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-21 00:33:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', to_date('2022-01-07 15:53:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-21 23:52:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-01-07 15:53:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', to_date('2022-01-08 10:33:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:37:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', to_date('2022-01-08 10:34:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:37:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', to_date('2022-01-14 02:14:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-21 23:55:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-01-14 02:14:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-01-14 02:14:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-01-14 02:14:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-01-14 02:14:20', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:21:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:26:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:28:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:28:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:36:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:36:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:38:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-01-23 00:39:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-02-20 01:41:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 00:59:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', to_date('2022-02-19 17:44:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:01:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-02-19 17:44:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-02-19 17:44:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-02-19 17:44:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-02-19 17:44:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:52:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-03-15 14:35:28', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-20 17:03:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', to_date('2022-03-16 23:47:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:02:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-04-23 01:03:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-08 23:40:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:51:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-04-27 14:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-05-09 23:38:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:12:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', to_date('2022-05-10 16:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:13:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-05-10 16:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 00:31:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-05-10 16:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 00:31:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-05-10 16:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 00:31:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-05-10 16:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-11 00:31:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '报表管理', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-07-10 20:22:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:33:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, '1', '1', '1', '1', to_date('2022-07-10 20:26:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:33:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, '商品中心', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-30 11:52:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-21 10:27:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-29 15:53:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-21 10:27:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 13:52:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-21 10:27:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', to_date('2022-08-01 14:55:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:01:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-08-01 14:55:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-12-12 20:26:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-08-01 14:55:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-12-12 20:26:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-08-01 14:55:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-12-12 20:26:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-08-01 14:55:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-12-12 20:26:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', to_date('2022-08-01 14:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-24 20:20:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-08-01 14:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-24 20:20:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-08-01 14:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-24 20:20:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-08-01 14:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-24 20:20:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-08-01 14:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-24 20:20:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-10-31 21:25:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-30 11:54:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 12:40:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, '优惠劵模板更新', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, '优惠劵模板删除', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-10-31 22:27:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', to_date('2022-11-03 23:21:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 12:55:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-03 23:21:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-03 23:21:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-03 23:21:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-03 23:21:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', to_date('2022-11-04 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-21 19:24:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-04 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-04 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-04 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-04 23:47:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-04 23:47:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-04 23:47:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-04 23:47:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-04 23:47:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2022-11-05 10:42:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-11-05 10:42:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', to_date('2022-11-05 17:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-21 19:24:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-05 17:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-05 17:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-05 17:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-05 17:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, '限时折扣活动删除', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, '限时折扣活动关闭', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-05 17:12:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, '秒杀商品', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 18:57:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, '秒杀活动查询', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, '秒杀活动创建', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, '秒杀活动更新', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, '秒杀活动删除', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-11-06 22:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, '秒杀时段', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', to_date('2022-11-15 19:46:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 18:57:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, '秒杀时段查询', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-11-15 19:46:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 17:50:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-11-15 19:46:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 17:48:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-11-15 19:46:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 17:50:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', to_date('2022-11-15 19:46:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 17:50:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '订单中心', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', to_date('2022-11-19 18:57:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-30 11:54:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, '售后退款', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', to_date('2022-11-19 20:15:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 21:42:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-11-19 20:15:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 21:04:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, '秒杀活动关闭', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', to_date('2022-11-28 20:20:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 18:34:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, '订单列表', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', to_date('2022-12-10 21:05:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 21:42:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', to_date('2022-12-23 17:35:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:50:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-01-01 20:11:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:39:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', to_date('2023-01-01 20:13:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '新增账号', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-01 20:21:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 17:32:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '修改账号', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-07 17:32:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 17:32:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, '查询账号', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-07 17:33:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 17:33:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, '删除账号', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-07 17:33:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 17:33:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, '生成二维码', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-07 17:33:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 17:33:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, '清空 API 配额', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-07 18:20:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-07 18:20:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, '数据统计', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', to_date('2023-01-07 20:17:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, '标签管理', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', to_date('2023-01-08 11:37:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, '查询标签', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 11:59:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 11:59:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, '新增标签', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 11:59:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 11:59:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '修改标签', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 11:59:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 11:59:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, '删除标签', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 12:00:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 12:00:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, '同步标签', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 12:00:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 12:00:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '粉丝管理', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', to_date('2023-01-08 16:51:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, '查询粉丝', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 17:16:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 17:17:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '修改粉丝', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 17:17:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 17:17:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, '同步粉丝', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-08 17:17:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-08 17:17:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, '消息管理', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', to_date('2023-01-08 18:44:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, '图文发表记录', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', to_date('2023-01-13 00:30:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:43:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, '查询发布列表', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-13 07:19:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-13 07:19:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, '发布草稿', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-13 07:19:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-13 07:19:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, '删除发布记录', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-13 07:20:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-13 07:20:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, '图文草稿箱', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', to_date('2023-01-13 07:40:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:43:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '新建草稿', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-13 23:15:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-13 23:15:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '修改草稿', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 10:08:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 10:08:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, '查询草稿', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 10:09:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 10:09:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, '删除草稿', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 10:09:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 10:09:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, '素材管理', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', to_date('2023-01-14 14:12:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:43:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, '上传临时素材', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 15:33:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 15:33:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, '上传永久素材', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 15:34:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 15:34:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, '删除素材', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 15:35:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 15:35:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, '上传图文图片', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 15:36:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 15:36:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, '查询素材', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-14 15:39:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-14 15:39:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '菜单管理', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', to_date('2023-01-14 17:43:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:42:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, '自动回复', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', to_date('2023-01-15 22:13:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:43:10', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, '查询回复', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-16 22:28:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 22:28:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, '新增回复', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-16 22:28:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 22:28:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '修改回复', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-16 22:29:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 22:29:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, '删除回复', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-16 22:29:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-16 22:29:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, '查询菜单', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-17 23:05:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 23:05:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '保存菜单', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-17 23:06:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 23:06:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-17 23:06:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 23:06:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-17 23:07:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 23:07:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-17 23:07:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-17 23:07:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-01-25 17:27:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-22 23:56:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:48:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 09:33:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:48:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-25 12:05:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', to_date('2023-01-26 02:16:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:48:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-26 02:16:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-26 02:16:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-26 23:29:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-26 23:29:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-01-28 10:25:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-22 23:56:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:49:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-28 02:26:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-01-28 10:54:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 10:54:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', to_date('2023-01-28 04:28:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:49:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-01-28 04:28:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-01-28 04:28:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, '1', '1', '1', '1', to_date('2023-02-07 00:03:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 12:34:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-02-07 19:25:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-07 19:25:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-02-07 19:25:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:01:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-02-07 19:25:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-07 19:25:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-02-07 19:26:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-07 19:26:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', to_date('2023-02-07 19:26:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-07 19:26:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot 开发文档', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-02-10 22:46:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 21:32:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-02-10 22:47:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 21:32:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, '接入示例', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', to_date('2023-02-11 14:21:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-18 23:50:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-07-30 14:22:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '配送管理', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', to_date('2023-05-18 09:18:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 10:58:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', to_date('2023-05-18 09:22:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-30 21:02:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', to_date('2023-05-18 09:23:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-30 21:03:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', to_date('2023-05-18 09:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-30 21:02:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-18 09:37:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', to_date('2023-05-20 06:48:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-30 21:03:13', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-20 06:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', to_date('2023-05-25 10:50:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-30 21:03:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, '自提门店删除', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-05-25 10:53:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', to_date('2023-06-24 17:39:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-06-24 18:55:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', to_date('2023-06-10 00:42:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 09:23:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', to_date('2023-06-10 02:07:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 23:41:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', to_date('2023-06-10 02:07:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:48:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', to_date('2023-06-10 02:07:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:49:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 19:25:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 03:26:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, '会员积分', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', to_date('2023-06-10 04:18:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 23:42:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 04:18:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 04:18:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', to_date('2023-06-10 04:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 19:26:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 04:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 04:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-06-10 04:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-06-10 04:48:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', to_date('2023-06-27 22:49:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 09:23:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, '回调通知', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', to_date('2023-07-20 04:41:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-18 23:56:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-07-20 04:41:32', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-07-20 04:41:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, '拼团活动', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:19:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-12 17:20:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, '拼团商品', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', to_date('2023-08-12 17:22:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-12 17:22:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, '拼团活动查询', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:54:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-24 11:57:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, '拼团活动创建', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:54:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-12 17:54:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, '拼团活动更新', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:55:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-12 17:55:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, '拼团活动删除', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:55:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-12 17:55:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, '拼团活动关闭', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-12 17:55:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-06 10:51:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, '砍价活动', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:27:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:27:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, '砍价商品', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', to_date('2023-08-13 00:28:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 01:16:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, '砍价活动查询', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:32:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:32:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, '砍价活动创建', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:32:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:32:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:34:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:34:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-13 00:35:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-13 00:35:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', to_date('2023-08-19 04:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-24 00:50:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-19 04:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-19 04:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-19 04:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-19 04:12:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-20 09:23:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, '会员标签查询', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-20 01:03:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', to_date('2023-08-22 12:41:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-22 21:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 12:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, '会员分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 23:42:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-22 13:50:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-08-23 16:49:05', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-08-23 16:50:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', to_date('2023-08-26 11:03:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:03:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-26 11:04:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:04:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-26 11:04:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:08:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-26 11:04:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:04:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-08-26 11:04:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-26 11:04:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-09-02 00:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-02 00:03:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '交易配置', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:30:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, '交易中心配置查询', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, '交易中心配置保存', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '分销管理', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 10:58:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, '分销用户', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:33:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, '分销用户查询', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, '分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, '分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, '分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, '分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, '分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, '佣金记录', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:33:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, '佣金记录查询', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, '佣金提现', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:33:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, '佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, '佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-28 02:46:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, '统计中心', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-30 11:54:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, '交易统计', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:42:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, '交易统计查询', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-09-30 03:22:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', to_date('2023-09-30 11:52:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-30 11:52:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-01 14:39:43', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-01 14:39:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', to_date('2023-10-01 14:39:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-01 22:42:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', to_date('2023-10-03 12:39:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 00:16:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', to_date('2023-10-05 02:49:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 10:50:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-05 02:49:06', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-05 02:49:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '助力记录查询', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-10-05 12:27:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-05 12:27:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', to_date('2023-10-08 07:10:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-08 07:34:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', to_date('2023-10-11 04:39:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:41:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-11 04:39:24', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-11 04:39:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-10-14 17:11:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-14 17:11:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-16 09:38:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, '分类创建', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '分类更新', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, '分类删除', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, '文章列表', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-16 09:41:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '文章管理查询', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '文章管理创建', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '文章管理更新', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 01:26:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', to_date('2023-10-16 09:37:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-16 09:37:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', to_date('2023-10-16 12:10:33', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-16 12:10:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', to_date('2023-10-19 16:09:51', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-19 16:09:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', to_date('2023-10-21 19:23:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-21 19:23:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, '客户管理', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:13:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 09:04:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM 系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, '1', '1', '1', '1', to_date('2023-10-29 17:08:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 15:37:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, '合同管理', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:15:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 10:50:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '线索管理', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:15:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:06:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '商机管理', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:14:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:12:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, '联系人管理', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:13:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:14:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, '回款管理', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:16:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, '回款计划', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:16:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 11:18:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-10-29 14:19:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', to_date('2023-11-04 12:12:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 01:14:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', to_date('2023-11-04 12:17:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 12:17:19', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-11-04 12:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 12:43:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-11-04 12:43:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 12:43:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-11-04 12:44:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 12:44:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-11-04 12:44:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 12:44:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', to_date('2023-11-04 14:01:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 14:01:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', to_date('2023-11-13 04:39:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:34:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-15 14:42:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:35:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:10:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-16 12:53:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', to_date('2023-11-16 15:50:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 13:19:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, '客户公海配置', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', to_date('2023-11-18 13:33:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-03 19:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, '客户公海配置保存', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:31', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, '客户限制配置', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 16:43:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, '客户限制配置查询', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, '客户限制配置创建', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, '客户限制配置更新', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-11-18 13:33:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', to_date('2023-11-18 21:58:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:14:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', to_date('2023-11-23 19:41:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:02:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', to_date('2023-12-05 22:45:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-20 20:36:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-05 22:47:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 22:47:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-05 22:47:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 22:47:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, '产品更新', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-05 22:48:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 22:48:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, '产品删除', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-05 22:48:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 22:48:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, '产品导出', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-05 22:48:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-05 22:48:29', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, '产品分类配置', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', to_date('2023-12-06 12:52:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-06 12:52:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, '产品分类查询', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-06 12:53:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-06 12:53:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, '产品分类创建', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-06 12:53:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-06 12:53:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, '产品分类更新', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-06 12:53:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-06 12:53:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, '产品分类删除', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', to_date('2023-12-06 12:54:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-06 12:54:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '关联商机', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-01-02 17:28:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-02 17:28:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, '取关商机', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-01-02 17:28:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-02 17:28:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, '商品统计', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', to_date('2023-12-15 18:54:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 20:41:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, '客户公海', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', to_date('2024-01-15 21:29:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:14:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, '订单查询', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-01-16 08:52:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-16 08:52:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '订单更新', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-01-16 08:52:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-16 08:52:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '支付&退款案例', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', to_date('2024-01-18 23:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-18 23:47:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, '转账案例', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, '1', '1', '1', '1', to_date('2024-01-18 23:51:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-01-18 23:51:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, '钱包管理', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-29 08:58:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, '充值套餐', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, '钱包余额', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-29 02:32:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', to_date('2024-01-26 22:50:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 20:10:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', to_date('2024-01-26 22:52:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:39:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-01 13:09:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-01 13:09:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, '1', '1', '1', '1', to_date('2024-02-04 15:37:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 15:37:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', to_date('2024-02-04 15:38:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 15:38:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, '产品信息', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 14:42:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, '产品查询', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:21:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, '产品创建', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:22:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, '产品更新', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:22:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, '产品删除', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:22:22', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, '产品导出', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-02-04 07:52:15', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:22:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, '产品分类', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 17:24:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, '分类查询', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, '分类创建', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '分类更新', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, '分类删除', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, '分类导出', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 09:21:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, '产品单位', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-04 19:54:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, '单位查询', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, '单位创建', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, '单位更新', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, '单位删除', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, '单位导出', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 11:54:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '库存管理', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', to_date('2024-02-05 00:29:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 00:29:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, '仓库信息', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 01:12:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, '仓库查询', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, '仓库创建', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, '仓库更新', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, '仓库删除', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, '仓库导出', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-04 17:12:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, '产品库存', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', to_date('2024-02-05 06:40:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-05 14:42:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, '库存查询', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 06:40:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 06:40:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '库存导出', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 06:40:50', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 06:40:50', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, '出入库明细', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', to_date('2024-02-05 10:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 17:26:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, '库存明细查询', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 10:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 10:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, '库存明细导出', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 10:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 10:27:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '其它入库', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 19:06:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, '其它入库单查询', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, '其它入库单创建', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, '其它入库单更新', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, '其它入库单删除', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, '其它入库单导出', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, '采购管理', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', to_date('2024-02-06 16:01:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 16:01:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, '供应商信息', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-06 16:22:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, '供应商查询', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, '供应商创建', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, '供应商更新', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, '供应商删除', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, '供应商导出', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-06 08:21:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, '其它入库单审批', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '其它出库', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 19:06:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, '其它出库单查询', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:39', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, '其它出库单创建', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, '其它出库单更新', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, '其它出库单删除', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, '其它出库单导出', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, '其它出库单审批', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 06:43:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '销售管理', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', to_date('2024-02-07 15:12:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 15:12:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, '客户信息', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-07 15:22:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, '客户查询', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, '客户创建', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, '客户更新', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, '客户删除', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, '客户导出', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 07:21:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '库存调拨', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-16 18:53:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, '库存调度单查询', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, '库存调度单创建', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, '库存调度单更新', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, '库存调度单删除', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, '库存调度单导出', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, '库存调度单审批', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:13:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '库存盘点', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-08 08:31:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '库存盘点单查询', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '库存盘点单创建', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '库存盘点单更新', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '库存盘点单删除', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '库存盘点单导出', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '库存盘点单审批', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:13:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '销售订单', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-10 21:59:20', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '销售订单查询', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '销售订单创建', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '销售订单更新', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '销售订单删除', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '销售订单导出', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '销售订单审批', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:13:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '财务管理', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', to_date('2024-02-10 08:05:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-10 08:06:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '结算账户', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-14 08:24:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '结算账户查询', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '结算账户创建', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '结算账户更新', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '结算账户删除', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '结算账户导出', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-10 00:15:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '销售出库', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-10 22:02:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '销售出库查询', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '销售出库创建', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '销售出库更新', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '销售出库删除', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '销售出库导出', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '销售出库审批', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:13:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '销售退货', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 06:12:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '销售退货查询', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '销售退货创建', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '销售退货更新', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:55', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '销售退货删除', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '销售退货导出', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:12:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '销售退货审批', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-07 11:13:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, '采购订单', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 08:51:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, '采购订单查询', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, '采购订单创建', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, '采购订单更新', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, '采购订单删除', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, '采购订单导出', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, '采购订单审批', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, '采购入库', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 11:19:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, '采购入库查询', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, '采购入库创建', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, '采购入库更新', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, '采购入库删除', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, '采购入库导出', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, '采购入库审批', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, '采购退货', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-12 20:51:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, '采购退货查询', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, '采购退货创建', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, '采购退货更新', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, '采购退货删除', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, '采购退货导出', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, '采购退货审批', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '付款单', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-14 08:24:23', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, '付款单查询', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '付款单创建', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '付款单更新', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, '付款单删除', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '付款单导出', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '付款单审批', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, '收款单', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-15 19:35:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, '收款单查询', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, '收款单创建', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:54', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, '收款单更新', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:44:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, '收款单删除', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:00', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, '收款单导出', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, '收款单审批', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-02-05 16:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-02-12 00:45:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '待办事项', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', to_date('2024-02-17 17:17:11', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-17 17:17:11', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP 首页', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', to_date('2024-02-18 16:49:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-26 21:12:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '商机状态配置', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', to_date('2024-02-21 20:15:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-21 20:15:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '商机状态查询', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-21 20:35:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-21 20:36:06', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '商机状态创建', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-21 20:35:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-21 20:35:57', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '商机状态更新', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-21 20:36:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-21 20:36:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '商机状态删除', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-21 20:36:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-21 20:36:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, '合同配置', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', to_date('2024-02-24 16:44:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 16:44:48', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-24 16:45:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 16:45:28', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-24 16:45:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 16:45:56', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-02-24 16:46:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 16:46:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', to_date('2024-03-09 16:43:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', to_date('2024-03-17 21:50:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:55:12', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', to_date('2024-03-08 02:00:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-21 23:51:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-03-08 02:00:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 14:36:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-03-08 02:00:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 14:36:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-03-08 02:00:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 14:36:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', to_date('2024-03-08 02:00:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-19 14:36:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', to_date('2024-03-19 19:46:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:03:42', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', to_date('2024-03-21 23:57:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-21 23:57:30', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-03-22 08:18:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-22 08:19:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-03-22 08:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-22 08:19:25', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', to_date('2024-03-22 08:43:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-22 08:43:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-03-22 08:43:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-22 08:43:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 13:13:38', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 16:05:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-23 19:43:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2024-03-09 22:35:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', to_date('2024-04-05 13:49:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:42:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', to_date('2024-04-05 13:57:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:42:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', to_date('2024-04-13 10:53:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:39:33', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', to_date('2024-04-22 23:54:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 09:36:35', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', to_date('2024-04-23 00:04:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-23 00:04:44', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:47:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:47:45', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:48:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:48:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:50:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:50:05', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:50:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:50:26', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:53:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:53:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:53:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:53:58', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:54:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:54:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:55:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:55:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:57:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:57:43', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:58:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:58:40', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 19:59:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 19:59:03', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 20:00:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:00:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 20:00:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:00:24', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 20:01:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:01:37', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 20:02:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:02:32', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', to_date('2024-04-24 20:02:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-24 20:02:51', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_menu_seq + START WITH 2758; + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +CREATE TABLE system_notice +( + id number NOT NULL, + title varchar2(50) NOT NULL, + content clob NOT NULL, + type smallint NOT NULL, + status smallint DEFAULT 0 NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_notice + ADD CONSTRAINT pk_system_notice PRIMARY KEY (id); + +COMMENT ON COLUMN system_notice.id IS '公告ID'; +COMMENT ON COLUMN system_notice.title IS '公告标题'; +COMMENT ON COLUMN system_notice.content IS '公告内容'; +COMMENT ON COLUMN system_notice.type IS '公告类型(1通知 2公告)'; +COMMENT ON COLUMN system_notice.status IS '公告状态(0正常 1关闭)'; +COMMENT ON COLUMN system_notice.creator IS '创建者'; +COMMENT ON COLUMN system_notice.create_time IS '创建时间'; +COMMENT ON COLUMN system_notice.updater IS '更新者'; +COMMENT ON COLUMN system_notice.update_time IS '更新时间'; +COMMENT ON COLUMN system_notice.deleted IS '是否删除'; +COMMENT ON COLUMN system_notice.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notice IS '通知公告表'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-04 21:00:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

11112222

', 2, 1, 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 20:07:26', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', to_date('2022-02-22 01:01:25', 'SYYYY-MM-DD HH24:MI:SS'), '110', to_date('2022-02-22 01:01:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_notice_seq + START WITH 5; + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +CREATE TABLE system_notify_message +( + id number NOT NULL, + user_id number NOT NULL, + user_type smallint NOT NULL, + template_id number NOT NULL, + template_code varchar2(64) NOT NULL, + template_nickname varchar2(63) NOT NULL, + template_content varchar2(1024) NOT NULL, + template_type number NOT NULL, + template_params varchar2(255) NOT NULL, + read_status number(1, 0) NOT NULL, + read_time date DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_notify_message + ADD CONSTRAINT pk_system_notify_message PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_message.id IS '用户ID'; +COMMENT ON COLUMN system_notify_message.user_id IS '用户id'; +COMMENT ON COLUMN system_notify_message.user_type IS '用户类型'; +COMMENT ON COLUMN system_notify_message.template_id IS '模版编号'; +COMMENT ON COLUMN system_notify_message.template_code IS '模板编码'; +COMMENT ON COLUMN system_notify_message.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_notify_message.template_content IS '模版内容'; +COMMENT ON COLUMN system_notify_message.template_type IS '模版类型'; +COMMENT ON COLUMN system_notify_message.template_params IS '模版参数'; +COMMENT ON COLUMN system_notify_message.read_status IS '是否已读'; +COMMENT ON COLUMN system_notify_message.read_time IS '阅读时间'; +COMMENT ON COLUMN system_notify_message.creator IS '创建者'; +COMMENT ON COLUMN system_notify_message.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_message.updater IS '更新者'; +COMMENT ON COLUMN system_notify_message.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_message.deleted IS '是否删除'; +COMMENT ON COLUMN system_notify_message.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notify_message IS '站内信消息表'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 11:44:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 11:45:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{"name":"哈哈"}', '0', NULL, '1', to_date('2023-01-28 21:02:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 21:02:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 22:21:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-10 00:47:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 22:22:07', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', '我是 2,我开始 3 了', 1, '{"name":"2","what":"3"}', '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 23:45:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{"name":"123"}', '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-28 23:50:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-29 10:52:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', to_date('2023-09-28 16:36:22', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-09-28 16:36:22', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', to_date('2023-10-03 12:11:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-10-03 12:11:34', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_notify_message_seq + START WITH 11; + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +CREATE TABLE system_notify_template +( + id number NOT NULL, + name varchar2(63) NOT NULL, + code varchar2(64) NOT NULL, + nickname varchar2(255) NOT NULL, + content varchar2(1024) NOT NULL, + type smallint NOT NULL, + params varchar2(255) DEFAULT NULL NULL, + status smallint NOT NULL, + remark varchar2(255) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_notify_template + ADD CONSTRAINT pk_system_notify_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_template.id IS '主键'; +COMMENT ON COLUMN system_notify_template.name IS '模板名称'; +COMMENT ON COLUMN system_notify_template.code IS '模版编码'; +COMMENT ON COLUMN system_notify_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_notify_template.content IS '模版内容'; +COMMENT ON COLUMN system_notify_template.type IS '类型'; +COMMENT ON COLUMN system_notify_template.params IS '参数数组'; +COMMENT ON COLUMN system_notify_template.status IS '状态'; +COMMENT ON COLUMN system_notify_template.remark IS '备注'; +COMMENT ON COLUMN system_notify_template.creator IS '创建者'; +COMMENT ON COLUMN system_notify_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_template.updater IS '更新者'; +COMMENT ON COLUMN system_notify_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_template.deleted IS '是否删除'; +COMMENT ON TABLE system_notify_template IS '站内信模板表'; + +CREATE SEQUENCE system_notify_template_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +CREATE TABLE system_oauth2_access_token +( + id number NOT NULL, + user_id number NOT NULL, + user_type smallint NOT NULL, + user_info varchar2(512) NOT NULL, + access_token varchar2(255) NOT NULL, + refresh_token varchar2(32) NOT NULL, + client_id varchar2(255) NOT NULL, + scopes varchar2(255) DEFAULT NULL NULL, + expires_time date NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_oauth2_access_token + ADD CONSTRAINT pk_system_oauth2_access_token PRIMARY KEY (id); + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token); +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token); + +COMMENT ON COLUMN system_oauth2_access_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_access_token.user_info IS '用户信息'; +COMMENT ON COLUMN system_oauth2_access_token.access_token IS '访问令牌'; +COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_access_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_access_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_access_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_access_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_access_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_access_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_access_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_access_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 访问令牌'; + +CREATE SEQUENCE system_oauth2_access_token_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +CREATE TABLE system_oauth2_approve +( + id number NOT NULL, + user_id number NOT NULL, + user_type smallint NOT NULL, + client_id varchar2(255) NOT NULL, + scope varchar2(255) DEFAULT '' NULL, + approved number(1, 0) DEFAULT '0' NOT NULL, + expires_time date NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_oauth2_approve + ADD CONSTRAINT pk_system_oauth2_approve PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_approve.id IS '编号'; +COMMENT ON COLUMN system_oauth2_approve.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_approve.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_approve.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_approve.scope IS '授权范围'; +COMMENT ON COLUMN system_oauth2_approve.approved IS '是否接受'; +COMMENT ON COLUMN system_oauth2_approve.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_approve.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_approve.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_approve.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_approve.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_approve.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 批准表'; + +CREATE SEQUENCE system_oauth2_approve_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +CREATE TABLE system_oauth2_client +( + id number NOT NULL, + client_id varchar2(255) NOT NULL, + secret varchar2(255) NOT NULL, + name varchar2(255) NOT NULL, + logo varchar2(255) NOT NULL, + description varchar2(255) DEFAULT NULL NULL, + status smallint NOT NULL, + access_token_validity_seconds number NOT NULL, + refresh_token_validity_seconds number NOT NULL, + redirect_uris varchar2(255) NOT NULL, + authorized_grant_types varchar2(255) NOT NULL, + scopes varchar2(255) DEFAULT NULL NULL, + auto_approve_scopes varchar2(255) DEFAULT NULL NULL, + authorities varchar2(255) DEFAULT NULL NULL, + resource_ids varchar2(255) DEFAULT NULL NULL, + additional_information varchar2(4000) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_oauth2_client + ADD CONSTRAINT pk_system_oauth2_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_client.id IS '编号'; +COMMENT ON COLUMN system_oauth2_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_client.secret IS '客户端密钥'; +COMMENT ON COLUMN system_oauth2_client.name IS '应用名'; +COMMENT ON COLUMN system_oauth2_client.logo IS '应用图标'; +COMMENT ON COLUMN system_oauth2_client.description IS '应用描述'; +COMMENT ON COLUMN system_oauth2_client.status IS '状态'; +COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS '访问令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS '刷新令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.redirect_uris IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS '授权类型'; +COMMENT ON COLUMN system_oauth2_client.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS '自动通过的授权范围'; +COMMENT ON COLUMN system_oauth2_client.authorities IS '权限'; +COMMENT ON COLUMN system_oauth2_client.resource_ids IS '资源'; +COMMENT ON COLUMN system_oauth2_client.additional_information IS '附加信息'; +COMMENT ON COLUMN system_oauth2_client.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_client.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_client.deleted IS '是否删除'; +COMMENT ON TABLE system_oauth2_client IS 'OAuth2 客户端表'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '我是描述', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', to_date('2022-05-11 21:47:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-22 16:31:52', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '啦啦啦啦', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', to_date('2022-05-12 00:28:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 21:01:01', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', to_date('2022-09-29 13:28:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-29 13:28:31', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', to_date('2022-10-04 17:40:16', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-10-04 20:31:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_oauth2_client_seq + START WITH 43; + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +CREATE TABLE system_oauth2_code +( + id number NOT NULL, + user_id number NOT NULL, + user_type smallint NOT NULL, + code varchar2(32) NOT NULL, + client_id varchar2(255) NOT NULL, + scopes varchar2(255) DEFAULT '' NULL, + expires_time date NOT NULL, + redirect_uri varchar2(255) DEFAULT NULL NULL, + state varchar2(255) DEFAULT '' NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_oauth2_code + ADD CONSTRAINT pk_system_oauth2_code PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_code.id IS '编号'; +COMMENT ON COLUMN system_oauth2_code.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_code.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_code.code IS '授权码'; +COMMENT ON COLUMN system_oauth2_code.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_code.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_code.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_code.redirect_uri IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_code.state IS '状态'; +COMMENT ON COLUMN system_oauth2_code.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_code.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_code IS 'OAuth2 授权码表'; + +CREATE SEQUENCE system_oauth2_code_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +CREATE TABLE system_oauth2_refresh_token +( + id number NOT NULL, + user_id number NOT NULL, + refresh_token varchar2(32) NOT NULL, + user_type smallint NOT NULL, + client_id varchar2(255) NOT NULL, + scopes varchar2(255) DEFAULT NULL NULL, + expires_time date NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_oauth2_refresh_token + ADD CONSTRAINT pk_system_oauth2_refresh_token PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_refresh_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; + +CREATE SEQUENCE system_oauth2_refresh_token_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +CREATE TABLE system_operate_log +( + id number NOT NULL, + trace_id varchar2(64) DEFAULT '' NULL, + user_id number NOT NULL, + user_type smallint DEFAULT 0 NOT NULL, + type varchar2(50) NOT NULL, + sub_type varchar2(50) NOT NULL, + biz_id number NOT NULL, + action varchar2(2000) DEFAULT '' NULL, + extra varchar2(2000) DEFAULT '' NULL, + request_method varchar2(16) DEFAULT '' NULL, + request_url varchar2(255) DEFAULT '' NULL, + user_ip varchar2(50) DEFAULT NULL NULL, + user_agent varchar2(200) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_operate_log + ADD CONSTRAINT pk_system_operate_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_operate_log.id IS '日志主键'; +COMMENT ON COLUMN system_operate_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_operate_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_operate_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_operate_log.type IS '操作模块类型'; +COMMENT ON COLUMN system_operate_log.sub_type IS '操作名'; +COMMENT ON COLUMN system_operate_log.biz_id IS '操作数据模块编号'; +COMMENT ON COLUMN system_operate_log.action IS '操作内容'; +COMMENT ON COLUMN system_operate_log.extra IS '拓展字段'; +COMMENT ON COLUMN system_operate_log.request_method IS '请求方法名'; +COMMENT ON COLUMN system_operate_log.request_url IS '请求地址'; +COMMENT ON COLUMN system_operate_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_operate_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_operate_log.creator IS '创建者'; +COMMENT ON COLUMN system_operate_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_operate_log.updater IS '更新者'; +COMMENT ON COLUMN system_operate_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_operate_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_operate_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_operate_log IS '操作日志记录 V2 版本'; + +CREATE SEQUENCE system_operate_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +CREATE TABLE system_post +( + id number NOT NULL, + code varchar2(64) NOT NULL, + name varchar2(50) NOT NULL, + sort number NOT NULL, + status smallint NOT NULL, + remark varchar2(500) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_post + ADD CONSTRAINT pk_system_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_post.id IS '岗位ID'; +COMMENT ON COLUMN system_post.code IS '岗位编码'; +COMMENT ON COLUMN system_post.name IS '岗位名称'; +COMMENT ON COLUMN system_post.sort IS '显示顺序'; +COMMENT ON COLUMN system_post.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_post.remark IS '备注'; +COMMENT ON COLUMN system_post.creator IS '创建者'; +COMMENT ON COLUMN system_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_post.updater IS '更新者'; +COMMENT ON COLUMN system_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_post IS '岗位信息表'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', to_date('2021-01-06 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-11 15:19:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-15 09:18:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 10:04:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', '人力资源', 5, 0, '', '1', to_date('2024-03-24 20:45:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-24 20:45:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_post_seq + START WITH 6; + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +CREATE TABLE system_role +( + id number NOT NULL, + name varchar2(30) NOT NULL, + code varchar2(100) NOT NULL, + sort number NOT NULL, + data_scope smallint DEFAULT 1 NOT NULL, + data_scope_dept_ids varchar2(500) DEFAULT '' NULL, + status smallint NOT NULL, + type smallint NOT NULL, + remark varchar2(500) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_role + ADD CONSTRAINT pk_system_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_role.id IS '角色ID'; +COMMENT ON COLUMN system_role.name IS '角色名称'; +COMMENT ON COLUMN system_role.code IS '角色权限字符串'; +COMMENT ON COLUMN system_role.sort IS '显示顺序'; +COMMENT ON COLUMN system_role.data_scope IS '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +COMMENT ON COLUMN system_role.data_scope_dept_ids IS '数据范围(指定部门数组)'; +COMMENT ON COLUMN system_role.status IS '角色状态(0正常 1停用)'; +COMMENT ON COLUMN system_role.type IS '角色类型'; +COMMENT ON COLUMN system_role.remark IS '备注'; +COMMENT ON COLUMN system_role.creator IS '创建者'; +COMMENT ON COLUMN system_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_role.updater IS '更新者'; +COMMENT ON COLUMN system_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role IS '角色信息表'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-22 05:08:21', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', to_date('2021-01-05 17:03:48', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-02-22 05:08:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', to_date('2024-02-24 10:51:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-02-24 02:51:32', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '我想测试', '', to_date('2021-01-06 13:49:35', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-24 22:22:45', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_role_seq + START WITH 112; + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +CREATE TABLE system_role_menu +( + id number NOT NULL, + role_id number NOT NULL, + menu_id number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_role_menu + ADD CONSTRAINT pk_system_role_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_role_menu.id IS '自增编号'; +COMMENT ON COLUMN system_role_menu.role_id IS '角色ID'; +COMMENT ON COLUMN system_role_menu.menu_id IS '菜单ID'; +COMMENT ON COLUMN system_role_menu.creator IS '创建者'; +COMMENT ON COLUMN system_role_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_role_menu.updater IS '更新者'; +COMMENT ON COLUMN system_role_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_role_menu.deleted IS '是否删除'; +COMMENT ON COLUMN system_role_menu.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role_menu IS '角色和菜单关联表'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:09:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 13:16:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', to_date('2022-02-23 00:23:55', 'SYYYY-MM-DD HH24:MI:SS'), '110', to_date('2022-02-23 00:23:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:45:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, '1', to_date('2022-04-01 22:21:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-04-01 22:21:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:54', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:55', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:08:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:43:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-09-21 22:48:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:52', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:42:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-01-25 08:43:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-02-09 23:49:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:19:40', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 23:41:02', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-30 11:42:36', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:18', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, '1', to_date('2024-04-30 09:38:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-30 09:38:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, '1', to_date('2024-04-30 09:38:37', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-30 09:38:37', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_role_menu_seq + START WITH 5779; + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +CREATE TABLE system_sms_channel +( + id number NOT NULL, + signature varchar2(12) NOT NULL, + code varchar2(63) NOT NULL, + status smallint NOT NULL, + remark varchar2(255) DEFAULT NULL NULL, + api_key varchar2(128) NOT NULL, + api_secret varchar2(128) DEFAULT NULL NULL, + callback_url varchar2(255) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_sms_channel + ADD CONSTRAINT pk_system_sms_channel PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_channel.id IS '编号'; +COMMENT ON COLUMN system_sms_channel.signature IS '短信签名'; +COMMENT ON COLUMN system_sms_channel.code IS '渠道编码'; +COMMENT ON COLUMN system_sms_channel.status IS '开启状态'; +COMMENT ON COLUMN system_sms_channel.remark IS '备注'; +COMMENT ON COLUMN system_sms_channel.api_key IS '短信 API 的账号'; +COMMENT ON COLUMN system_sms_channel.api_secret IS '短信 API 的秘钥'; +COMMENT ON COLUMN system_sms_channel.callback_url IS '短信发送回调 URL'; +COMMENT ON COLUMN system_sms_channel.creator IS '创建者'; +COMMENT ON COLUMN system_sms_channel.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_channel.updater IS '更新者'; +COMMENT ON COLUMN system_sms_channel.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_channel.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_channel IS '短信渠道'; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', to_date('2021-03-31 11:53:10', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 22:10:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', to_date('2021-04-13 00:23:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-27 20:29:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, '仅测试', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', to_date('2022-04-10 23:07:59', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 22:10:08', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_sms_channel_seq + START WITH 7; + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +CREATE TABLE system_sms_code +( + id number NOT NULL, + mobile varchar2(11) NOT NULL, + code varchar2(6) NOT NULL, + create_ip varchar2(15) NOT NULL, + scene smallint NOT NULL, + today_index smallint NOT NULL, + used smallint NOT NULL, + used_time date DEFAULT NULL NULL, + used_ip varchar2(255) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_sms_code + ADD CONSTRAINT pk_system_sms_code PRIMARY KEY (id); + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile); + +COMMENT ON COLUMN system_sms_code.id IS '编号'; +COMMENT ON COLUMN system_sms_code.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_code.code IS '验证码'; +COMMENT ON COLUMN system_sms_code.create_ip IS '创建 IP'; +COMMENT ON COLUMN system_sms_code.scene IS '发送场景'; +COMMENT ON COLUMN system_sms_code.today_index IS '今日发送的第几条'; +COMMENT ON COLUMN system_sms_code.used IS '是否使用'; +COMMENT ON COLUMN system_sms_code.used_time IS '使用时间'; +COMMENT ON COLUMN system_sms_code.used_ip IS '使用 IP'; +COMMENT ON COLUMN system_sms_code.creator IS '创建者'; +COMMENT ON COLUMN system_sms_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_code.updater IS '更新者'; +COMMENT ON COLUMN system_sms_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_sms_code.tenant_id IS '租户编号'; +COMMENT ON COLUMN system_sms_code.idx_mobile IS '手机号'; +COMMENT ON TABLE system_sms_code IS '手机验证码'; + +CREATE SEQUENCE system_sms_code_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +CREATE TABLE system_sms_log +( + id number NOT NULL, + channel_id number NOT NULL, + channel_code varchar2(63) NOT NULL, + template_id number NOT NULL, + template_code varchar2(63) NOT NULL, + template_type smallint NOT NULL, + template_content varchar2(255) NOT NULL, + template_params varchar2(255) NOT NULL, + api_template_id varchar2(63) NOT NULL, + mobile varchar2(11) NOT NULL, + user_id number DEFAULT NULL NULL, + user_type smallint DEFAULT NULL NULL, + send_status smallint DEFAULT 0 NOT NULL, + send_time date DEFAULT NULL NULL, + api_send_code varchar2(63) DEFAULT NULL NULL, + api_send_msg varchar2(255) DEFAULT NULL NULL, + api_request_id varchar2(255) DEFAULT NULL NULL, + api_serial_no varchar2(255) DEFAULT NULL NULL, + receive_status smallint DEFAULT 0 NOT NULL, + receive_time date DEFAULT NULL NULL, + api_receive_code varchar2(63) DEFAULT NULL NULL, + api_receive_msg varchar2(255) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_sms_log + ADD CONSTRAINT pk_system_sms_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_log.id IS '编号'; +COMMENT ON COLUMN system_sms_log.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_log.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_sms_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_sms_log.template_type IS '短信类型'; +COMMENT ON COLUMN system_sms_log.template_content IS '短信内容'; +COMMENT ON COLUMN system_sms_log.template_params IS '短信参数'; +COMMENT ON COLUMN system_sms_log.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_log.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_sms_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_sms_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_sms_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_sms_log.api_send_code IS '短信 API 发送结果的编码'; +COMMENT ON COLUMN system_sms_log.api_send_msg IS '短信 API 发送失败的提示'; +COMMENT ON COLUMN system_sms_log.api_request_id IS '短信 API 发送返回的唯一请求 ID'; +COMMENT ON COLUMN system_sms_log.api_serial_no IS '短信 API 发送返回的序号'; +COMMENT ON COLUMN system_sms_log.receive_status IS '接收状态'; +COMMENT ON COLUMN system_sms_log.receive_time IS '接收时间'; +COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API 接收结果的编码'; +COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API 接收结果的说明'; +COMMENT ON COLUMN system_sms_log.creator IS '创建者'; +COMMENT ON COLUMN system_sms_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_log.updater IS '更新者'; +COMMENT ON COLUMN system_sms_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_log.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_log IS '短信日志'; + +CREATE SEQUENCE system_sms_log_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +CREATE TABLE system_sms_template +( + id number NOT NULL, + type smallint NOT NULL, + status smallint NOT NULL, + code varchar2(63) NOT NULL, + name varchar2(63) NOT NULL, + content varchar2(255) NOT NULL, + params varchar2(255) NOT NULL, + remark varchar2(255) DEFAULT NULL NULL, + api_template_id varchar2(63) NOT NULL, + channel_id number NOT NULL, + channel_code varchar2(63) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_sms_template + ADD CONSTRAINT pk_system_sms_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_template.id IS '编号'; +COMMENT ON COLUMN system_sms_template.type IS '模板类型'; +COMMENT ON COLUMN system_sms_template.status IS '开启状态'; +COMMENT ON COLUMN system_sms_template.code IS '模板编码'; +COMMENT ON COLUMN system_sms_template.name IS '模板名称'; +COMMENT ON COLUMN system_sms_template.content IS '模板内容'; +COMMENT ON COLUMN system_sms_template.params IS '参数数组'; +COMMENT ON COLUMN system_sms_template.remark IS '备注'; +COMMENT ON COLUMN system_sms_template.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_template.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_template.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_template.creator IS '创建者'; +COMMENT ON COLUMN system_sms_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_template.updater IS '更新者'; +COMMENT ON COLUMN system_sms_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_template.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_template IS '短信模板'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '["operation","code"]', '测试备注', '4383920', 6, 'DEBUG_DING_TALK', '', to_date('2021-03-31 10:49:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 22:32:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', to_date('2021-03-31 11:56:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2021-04-10 01:22:02', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '["name"]', 'f哈哈哈', '4383920', 6, 'DEBUG_DING_TALK', '1', to_date('2021-04-10 01:07:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 21:26:09', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '["name","code"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', to_date('2021-04-13 00:29:53', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 22:35:34', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '["code"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', to_date('2021-10-11 08:10:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-12-10 21:25:59', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', to_date('2022-01-21 22:31:19', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-01-22 00:03:36', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', to_date('2022-01-22 00:03:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-01 12:33:14', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '【工作流】流程被通过', '您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', to_date('2022-01-22 00:04:31', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-27 20:32:21', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', '演示模板', '我就是测试一下下', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', to_date('2022-04-10 23:22:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-03-24 23:45:07', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', '会员用户 - 修改手机', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', to_date('2023-08-19 18:58:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-19 11:34:04', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', '会员用户 - 修改密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', to_date('2023-08-19 18:58:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-08-19 11:34:18', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', '会员用户 - 重置密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', to_date('2023-08-19 18:58:01', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-02 22:35:27', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_sms_template_seq + START WITH 17; + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +CREATE TABLE system_social_client +( + id number NOT NULL, + name varchar2(255) NOT NULL, + social_type smallint NOT NULL, + user_type smallint NOT NULL, + client_id varchar2(255) NOT NULL, + client_secret varchar2(255) NOT NULL, + agent_id varchar2(255) DEFAULT NULL NULL, + status smallint NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_social_client + ADD CONSTRAINT pk_system_social_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_client.id IS '编号'; +COMMENT ON COLUMN system_social_client.name IS '应用名'; +COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; +COMMENT ON COLUMN system_social_client.status IS '状态'; +COMMENT ON COLUMN system_social_client.creator IS '创建者'; +COMMENT ON COLUMN system_social_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_client.updater IS '更新者'; +COMMENT ON COLUMN system_social_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_client.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_client.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_client IS '社交客户端表'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '钉钉', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', to_date('2023-10-18 11:21:18', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-20 21:28:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '钉钉(王土豆)', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', to_date('2023-10-18 11:21:18', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2023-12-20 21:28:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', 121); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '微信公众号', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', to_date('2023-10-18 16:07:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-20 21:28:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '微信小程序', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', to_date('2023-10-19 13:37:41', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-12-20 21:28:25', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_social_client_seq + START WITH 44; + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +CREATE TABLE system_social_user +( + id number NOT NULL, + type smallint NOT NULL, + openid varchar2(32) NOT NULL, + token varchar2(256) DEFAULT NULL NULL, + raw_token_info varchar2(1024) NOT NULL, + nickname varchar2(32) NOT NULL, + avatar varchar2(255) DEFAULT NULL NULL, + raw_user_info varchar2(1024) NOT NULL, + code varchar2(256) NOT NULL, + state varchar2(256) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_social_user + ADD CONSTRAINT pk_system_social_user PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user.type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user.openid IS '社交 openid'; +COMMENT ON COLUMN system_social_user.token IS '社交 token'; +COMMENT ON COLUMN system_social_user.raw_token_info IS '原始 Token 数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.nickname IS '用户昵称'; +COMMENT ON COLUMN system_social_user.avatar IS '用户头像'; +COMMENT ON COLUMN system_social_user.raw_user_info IS '原始用户数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.code IS '最后一次的认证 code'; +COMMENT ON COLUMN system_social_user.state IS '最后一次的认证 state'; +COMMENT ON COLUMN system_social_user.creator IS '创建者'; +COMMENT ON COLUMN system_social_user.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user.updater IS '更新者'; +COMMENT ON COLUMN system_social_user.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user IS '社交用户表'; + +CREATE SEQUENCE system_social_user_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +CREATE TABLE system_social_user_bind +( + id number NOT NULL, + user_id number NOT NULL, + user_type smallint NOT NULL, + social_type smallint NOT NULL, + social_user_id number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_social_user_bind + ADD CONSTRAINT pk_system_social_user_bind PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user_bind.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user_bind.user_id IS '用户编号'; +COMMENT ON COLUMN system_social_user_bind.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_user_bind.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user_bind.social_user_id IS '社交用户的编号'; +COMMENT ON COLUMN system_social_user_bind.creator IS '创建者'; +COMMENT ON COLUMN system_social_user_bind.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user_bind.updater IS '更新者'; +COMMENT ON COLUMN system_social_user_bind.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user_bind.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user_bind.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user_bind IS '社交绑定表'; + +CREATE SEQUENCE system_social_user_bind_seq + START WITH 1; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +CREATE TABLE system_tenant +( + id number NOT NULL, + name varchar2(30) NOT NULL, + contact_user_id number DEFAULT NULL NULL, + contact_name varchar2(30) NOT NULL, + contact_mobile varchar2(500) DEFAULT NULL NULL, + status smallint DEFAULT 0 NOT NULL, + website varchar2(256) DEFAULT '' NULL, + package_id number NOT NULL, + expire_time date NOT NULL, + account_count number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_tenant + ADD CONSTRAINT pk_system_tenant PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant.id IS '租户编号'; +COMMENT ON COLUMN system_tenant.name IS '租户名'; +COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号'; +COMMENT ON COLUMN system_tenant.contact_name IS '联系人'; +COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机'; +COMMENT ON COLUMN system_tenant.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant.website IS '绑定域名'; +COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号'; +COMMENT ON COLUMN system_tenant.expire_time IS '过期时间'; +COMMENT ON COLUMN system_tenant.account_count IS '账号数量'; +COMMENT ON COLUMN system_tenant.creator IS '创建者'; +COMMENT ON COLUMN system_tenant.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant.updater IS '更新者'; +COMMENT ON COLUMN system_tenant.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant IS '租户表'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, to_date('2099-02-19 17:14:16', 'SYYYY-MM-DD HH24:MI:SS'), 9999, '1', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-06 11:41:41', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, to_date('2024-03-11 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 20, '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-06 11:41:47', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, to_date('2022-04-30 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 50, '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-06 11:41:53', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_tenant_seq + START WITH 123; + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +CREATE TABLE system_tenant_package +( + id number NOT NULL, + name varchar2(30) NOT NULL, + status smallint DEFAULT 0 NOT NULL, + remark varchar2(256) DEFAULT '' NULL, + menu_ids varchar2(4000) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL +); + +ALTER TABLE system_tenant_package + ADD CONSTRAINT pk_system_tenant_package PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant_package.id IS '套餐编号'; +COMMENT ON COLUMN system_tenant_package.name IS '套餐名'; +COMMENT ON COLUMN system_tenant_package.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant_package.remark IS '备注'; +COMMENT ON COLUMN system_tenant_package.menu_ids IS '关联的菜单编号'; +COMMENT ON COLUMN system_tenant_package.creator IS '创建者'; +COMMENT ON COLUMN system_tenant_package.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant_package.updater IS '更新者'; +COMMENT ON COLUMN system_tenant_package.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant_package.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant_package IS '租户套餐表'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', to_date('2022-02-22 00:54:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-30 17:53:17', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_tenant_package_seq + START WITH 112; + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +CREATE TABLE system_user_post +( + id number NOT NULL, + user_id number DEFAULT 0 NOT NULL, + post_id number DEFAULT 0 NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_user_post + ADD CONSTRAINT pk_system_user_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_post.id IS 'id'; +COMMENT ON COLUMN system_user_post.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_post.post_id IS '岗位ID'; +COMMENT ON COLUMN system_user_post.creator IS '创建者'; +COMMENT ON COLUMN system_user_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_post.updater IS '更新者'; +COMMENT ON COLUMN system_user_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_post IS '用户岗位表'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', to_date('2022-05-02 07:25:24', 'SYYYY-MM-DD HH24:MI:SS'), 'admin', to_date('2022-05-02 07:25:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', to_date('2022-05-02 07:25:24', 'SYYYY-MM-DD HH24:MI:SS'), 'admin', to_date('2022-05-02 07:25:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', to_date('2022-05-16 19:36:28', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-16 19:36:28', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', to_date('2022-07-09 17:40:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-07-09 17:40:26', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', to_date('2022-07-09 17:44:44', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-07-09 17:44:44', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', to_date('2024-03-24 20:45:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-24 20:45:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', to_date('2024-04-04 09:37:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-04 09:37:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', to_date('2024-04-04 09:37:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-04 09:37:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_user_post_seq + START WITH 125; + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +CREATE TABLE system_user_role +( + id number NOT NULL, + user_id number NOT NULL, + role_id number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_user_role + ADD CONSTRAINT pk_system_user_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_role.id IS '自增编号'; +COMMENT ON COLUMN system_user_role.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_role.role_id IS '角色ID'; +COMMENT ON COLUMN system_user_role.creator IS '创建者'; +COMMENT ON COLUMN system_user_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_role.updater IS '更新者'; +COMMENT ON COLUMN system_user_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_role IS '用户和角色关联表'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-05-12 12:35:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-05-12 12:35:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, '', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-05-12 12:35:13', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-05-12 12:35:12', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2022-05-12 12:35:11', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-01-11 13:19:45', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', to_date('2022-02-23 13:14:38', 'SYYYY-MM-DD HH24:MI:SS'), '110', to_date('2022-02-23 13:14:38', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', to_date('2022-05-12 20:39:29', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-12 20:39:29', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, '1', to_date('2022-05-28 15:43:57', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-05-28 15:43:57', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', to_date('2022-07-21 22:08:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-07-21 22:08:30', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', to_date('2024-03-15 20:00:24', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-15 20:00:24', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', to_date('2024-03-17 09:12:08', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-17 09:12:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, '1', to_date('2024-03-24 22:23:03', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-03-24 22:23:03', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_user_role_seq + START WITH 39; + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +CREATE TABLE system_users +( + id number NOT NULL, + username varchar2(30) NOT NULL, + password varchar2(100) DEFAULT '' NULL, + nickname varchar2(30) NOT NULL, + remark varchar2(500) DEFAULT NULL NULL, + dept_id number DEFAULT NULL NULL, + post_ids varchar2(255) DEFAULT NULL NULL, + email varchar2(50) DEFAULT '' NULL, + mobile varchar2(11) DEFAULT '' NULL, + sex smallint DEFAULT 0 NULL, + avatar varchar2(512) DEFAULT '' NULL, + status smallint DEFAULT 0 NOT NULL, + login_ip varchar2(50) DEFAULT '' NULL, + login_date date DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE system_users + ADD CONSTRAINT pk_system_users PRIMARY KEY (id); + +COMMENT ON COLUMN system_users.id IS '用户ID'; +COMMENT ON COLUMN system_users.username IS '用户账号'; +COMMENT ON COLUMN system_users.password IS '密码'; +COMMENT ON COLUMN system_users.nickname IS '用户昵称'; +COMMENT ON COLUMN system_users.remark IS '备注'; +COMMENT ON COLUMN system_users.dept_id IS '部门ID'; +COMMENT ON COLUMN system_users.post_ids IS '岗位编号数组'; +COMMENT ON COLUMN system_users.email IS '用户邮箱'; +COMMENT ON COLUMN system_users.mobile IS '手机号码'; +COMMENT ON COLUMN system_users.sex IS '用户性别'; +COMMENT ON COLUMN system_users.avatar IS '头像地址'; +COMMENT ON COLUMN system_users.status IS '帐号状态(0正常 1停用)'; +COMMENT ON COLUMN system_users.login_ip IS '最后登录IP'; +COMMENT ON COLUMN system_users.login_date IS '最后登录时间'; +COMMENT ON COLUMN system_users.creator IS '创建者'; +COMMENT ON COLUMN system_users.create_time IS '创建时间'; +COMMENT ON COLUMN system_users.updater IS '更新者'; +COMMENT ON COLUMN system_users.update_time IS '更新时间'; +COMMENT ON COLUMN system_users.deleted IS '是否删除'; +COMMENT ON COLUMN system_users.tenant_id IS '租户编号'; +COMMENT ON TABLE system_users IS '用户信息表'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', to_date('2024-04-29 21:50:32', 'SYYYY-MM-DD HH24:MI:SS'), 'admin', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2024-04-29 21:50:32', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', to_date('2022-07-09 23:03:33', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-01-07 09:07:17', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2022-07-09 23:03:33', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', to_date('2024-03-18 21:09:04', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-01-13 23:50:35', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2024-03-18 21:09:04', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', to_date('2024-03-26 07:11:35', 'SYYYY-MM-DD HH24:MI:SS'), '', to_date('2021-01-21 02:13:53', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2024-03-26 07:11:35', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', to_date('2022-02-20 22:59:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-27 08:26:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 118); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', to_date('2022-02-20 23:00:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-27 08:26:53', 'SYYYY-MM-DD HH24:MI:SS'), '0', 119); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', to_date('2022-02-20 23:11:50', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-27 08:26:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 120); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', to_date('2022-09-25 22:47:33', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2022-09-25 22:47:33', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', to_date('2023-12-30 11:42:17', 'SYYYY-MM-DD HH24:MI:SS'), '110', to_date('2022-02-23 13:14:33', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2023-12-30 11:42:17', 'SYYYY-MM-DD HH24:MI:SS'), '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', to_date('2024-03-16 23:11:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-02-23 19:08:03', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2024-03-16 23:11:38', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', to_date('2022-03-19 18:38:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2022-03-19 18:38:51', 'SYYYY-MM-DD HH24:MI:SS'), '0', 122); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', to_date('2024-03-24 22:21:05', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-03-19 21:50:58', 'SYYYY-MM-DD HH24:MI:SS'), NULL, to_date('2024-03-24 22:21:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', to_date('2022-04-30 02:55:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-04 09:37:14', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', to_date('2022-07-09 17:40:26', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-07-09 17:40:26', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', to_date('2024-03-17 09:10:27', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2022-07-09 17:44:43', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-04 09:48:05', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', to_date('2024-04-27 08:45:56', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-04-27 08:45:56', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE system_users_seq + START WITH 132; + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +CREATE TABLE yudao_demo01_contact +( + id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + sex smallint NOT NULL, + birthday date NOT NULL, + description varchar2(255) NOT NULL, + avatar varchar2(512) DEFAULT NULL NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE yudao_demo01_contact + ADD CONSTRAINT pk_yudao_demo01_contact PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo01_contact.id IS '编号'; +COMMENT ON COLUMN yudao_demo01_contact.name IS '名字'; +COMMENT ON COLUMN yudao_demo01_contact.sex IS '性别'; +COMMENT ON COLUMN yudao_demo01_contact.birthday IS '出生年'; +COMMENT ON COLUMN yudao_demo01_contact.description IS '简介'; +COMMENT ON COLUMN yudao_demo01_contact.avatar IS '头像'; +COMMENT ON COLUMN yudao_demo01_contact.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo01_contact.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo01_contact.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo01_contact.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo01_contact.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo01_contact IS '示例联系人表'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 2, to_date('2023-11-07 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '

天蚕土豆!呀

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', to_date('2023-11-15 23:34:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-15 23:47:39', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE yudao_demo01_contact_seq + START WITH 2; + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +CREATE TABLE yudao_demo02_category +( + id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + parent_id number NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE yudao_demo02_category + ADD CONSTRAINT pk_yudao_demo02_category PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo02_category.id IS '编号'; +COMMENT ON COLUMN yudao_demo02_category.name IS '名字'; +COMMENT ON COLUMN yudao_demo02_category.parent_id IS '父级编号'; +COMMENT ON COLUMN yudao_demo02_category.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo02_category.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo02_category.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo02_category.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo02_category.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo02_category IS '示例分类表'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 0, '1', to_date('2023-11-15 23:34:30', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:24:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '番茄', 0, '1', to_date('2023-11-16 20:24:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:24:15', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '怪怪', 0, '1', to_date('2023-11-16 20:24:32', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:24:32', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '小番茄', 2, '1', to_date('2023-11-16 20:24:39', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:24:39', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大番茄', 2, '1', to_date('2023-11-16 20:24:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 20:24:46', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', to_date('2023-11-24 19:29:34', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-24 19:29:34', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE yudao_demo02_category_seq + START WITH 7; + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +CREATE TABLE yudao_demo03_course +( + id number NOT NULL, + student_id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + score smallint NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE yudao_demo03_course + ADD CONSTRAINT pk_yudao_demo03_course PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_course.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_course.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_course.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_course.score IS '分数'; +COMMENT ON COLUMN yudao_demo03_course.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_course.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_course.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_course.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_course.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_course IS '学生课程表'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '语文', 66, '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, '数学', 22, '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '体育', 23, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 15:44:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '计算机', 11, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 15:44:40', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '体育', 23, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 15:47:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '计算机', 11, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 15:47:09', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '体育', 23, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:47:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '计算机', 11, '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:47:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '电脑', 33, '1', to_date('2023-11-17 00:20:42', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 16:20:45', 'SYYYY-MM-DD HH24:MI:SS'), '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, '滑雪', 12, '1', to_date('2023-11-17 13:13:20', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 13:13:20', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE yudao_demo03_course_seq + START WITH 14; + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +CREATE TABLE yudao_demo03_grade +( + id number NOT NULL, + student_id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + teacher varchar2(255) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE yudao_demo03_grade + ADD CONSTRAINT pk_yudao_demo03_grade PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_grade.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_grade.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_grade.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_grade.teacher IS '班主任'; +COMMENT ON COLUMN yudao_demo03_grade.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_grade.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_grade.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_grade.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_grade.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_grade IS '学生班级表'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, '三年 2 班', '周杰伦', '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '华为', '遥遥领先', '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-16 23:47:10', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, '小图', '小娃111', '1', to_date('2023-11-17 13:10:23', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 13:10:23', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE yudao_demo03_grade_seq + START WITH 10; + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +CREATE TABLE yudao_demo03_student +( + id number NOT NULL, + name varchar2(100) DEFAULT '' NULL, + sex smallint NOT NULL, + birthday date NOT NULL, + description varchar2(255) NOT NULL, + creator varchar2(64) DEFAULT '' NULL, + create_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater varchar2(64) DEFAULT '' NULL, + update_time date DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted number(1, 0) DEFAULT 0 NOT NULL, + tenant_id number DEFAULT 0 NOT NULL +); + +ALTER TABLE yudao_demo03_student + ADD CONSTRAINT pk_yudao_demo03_student PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_student.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_student.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_student.sex IS '性别'; +COMMENT ON COLUMN yudao_demo03_student.birthday IS '出生日期'; +COMMENT ON COLUMN yudao_demo03_student.description IS '简介'; +COMMENT ON COLUMN yudao_demo03_student.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_student.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_student.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_student.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_student.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_student IS '学生表'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '小白', 1, to_date('2023-11-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '

厉害

', '1', to_date('2023-11-16 23:21:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 16:49:06', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大黑', 2, to_date('2023-11-13 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '

你在教我做事?

', '1', to_date('2023-11-16 23:22:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 16:49:07', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, '小花', 1, to_date('2023-11-07 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '

哈哈哈

', '1', to_date('2023-11-17 00:04:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-17 16:49:08', 'SYYYY-MM-DD HH24:MI:SS'), '0', 1); +COMMIT; +-- @formatter:on + +CREATE SEQUENCE yudao_demo03_student_seq + START WITH 10; + diff --git a/ruoyi-vue-pro-master/sql/postgresql/quartz.sql b/ruoyi-vue-pro-master/sql/postgresql/quartz.sql new file mode 100644 index 0000000..4ec390c --- /dev/null +++ b/ruoyi-vue-pro-master/sql/postgresql/quartz.sql @@ -0,0 +1,253 @@ +-- ---------------------------- +-- qrtz_blob_triggers +-- ---------------------------- +CREATE TABLE qrtz_blob_triggers +( + sched_name varchar(120) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + blob_data bytea NULL, + PRIMARY KEY (sched_name, trigger_name, trigger_group) +); + +CREATE INDEX idx_qrtz_blob_triggers_sched_name ON qrtz_blob_triggers (sched_name, trigger_name, trigger_group); + +-- ---------------------------- +-- qrtz_calendars +-- ---------------------------- +CREATE TABLE qrtz_calendars +( + sched_name varchar(120) NOT NULL, + calendar_name varchar(190) NOT NULL, + calendar bytea NOT NULL, + PRIMARY KEY (sched_name, calendar_name) +); + + +-- ---------------------------- +-- qrtz_cron_triggers +-- ---------------------------- +CREATE TABLE qrtz_cron_triggers +( + sched_name varchar(120) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + cron_expression varchar(120) NOT NULL, + time_zone_id varchar(80) NULL DEFAULT NULL, + PRIMARY KEY (sched_name, trigger_name, trigger_group) +); + +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- qrtz_fired_triggers +-- ---------------------------- +CREATE TABLE qrtz_fired_triggers +( + sched_name varchar(120) NOT NULL, + entry_id varchar(95) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + instance_name varchar(190) NOT NULL, + fired_time int8 NOT NULL, + sched_time int8 NOT NULL, + priority int4 NOT NULL, + state varchar(16) NOT NULL, + job_name varchar(190) NULL DEFAULT NULL, + job_group varchar(190) NULL DEFAULT NULL, + is_nonconcurrent varchar(1) NULL DEFAULT NULL, + requests_recovery varchar(1) NULL DEFAULT NULL, + PRIMARY KEY (sched_name, entry_id) +); + +CREATE INDEX idx_qrtz_ft_trig_inst_name ON qrtz_fired_triggers (sched_name, instance_name); +CREATE INDEX idx_qrtz_ft_inst_job_req_rcvry ON qrtz_fired_triggers (sched_name, instance_name, requests_recovery); +CREATE INDEX idx_qrtz_ft_j_g ON qrtz_fired_triggers (sched_name, job_name, job_group); +CREATE INDEX idx_qrtz_ft_jg ON qrtz_fired_triggers (sched_name, job_group); +CREATE INDEX idx_qrtz_ft_t_g ON qrtz_fired_triggers (sched_name, trigger_name, trigger_group); +CREATE INDEX idx_qrtz_ft_tg ON qrtz_fired_triggers (sched_name, trigger_group); + +-- ---------------------------- +-- qrtz_job_details +-- ---------------------------- +CREATE TABLE qrtz_job_details +( + sched_name varchar(120) NOT NULL, + job_name varchar(190) NOT NULL, + job_group varchar(190) NOT NULL, + description varchar(250) NULL DEFAULT NULL, + job_class_name varchar(250) NOT NULL, + is_durable varchar(1) NOT NULL, + is_nonconcurrent varchar(1) NOT NULL, + is_update_data varchar(1) NOT NULL, + requests_recovery varchar(1) NOT NULL, + job_data bytea NULL, + PRIMARY KEY (sched_name, job_name, job_group) +); + +CREATE INDEX idx_qrtz_j_req_recovery ON qrtz_job_details (sched_name, requests_recovery); +CREATE INDEX idx_qrtz_j_grp ON qrtz_job_details (sched_name, job_group); + +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- qrtz_locks +-- ---------------------------- +CREATE TABLE qrtz_locks +( + sched_name varchar(120) NOT NULL, + lock_name varchar(40) NOT NULL, + PRIMARY KEY (sched_name, lock_name) +); + +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- qrtz_paused_trigger_grps +-- ---------------------------- +CREATE TABLE qrtz_paused_trigger_grps +( + sched_name varchar(120) NOT NULL, + trigger_group varchar(190) NOT NULL, + PRIMARY KEY (sched_name, trigger_group) +); + +-- ---------------------------- +-- qrtz_scheduler_state +-- ---------------------------- +CREATE TABLE qrtz_scheduler_state +( + sched_name varchar(120) NOT NULL, + instance_name varchar(190) NOT NULL, + last_checkin_time int8 NOT NULL, + checkin_interval int8 NOT NULL, + PRIMARY KEY (sched_name, instance_name) +); + +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + +-- ---------------------------- +-- qrtz_simple_triggers +-- ---------------------------- +CREATE TABLE qrtz_simple_triggers +( + sched_name varchar(120) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + repeat_count int8 NOT NULL, + repeat_interval int8 NOT NULL, + times_triggered int8 NOT NULL, + PRIMARY KEY (sched_name, trigger_name, trigger_group) +); + +-- ---------------------------- +-- qrtz_simprop_triggers +-- ---------------------------- +CREATE TABLE qrtz_simprop_triggers +( + sched_name varchar(120) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + str_prop_1 varchar(512) NULL DEFAULT NULL, + str_prop_2 varchar(512) NULL DEFAULT NULL, + str_prop_3 varchar(512) NULL DEFAULT NULL, + int_prop_1 int4 NULL DEFAULT NULL, + int_prop_2 int4 NULL DEFAULT NULL, + long_prop_1 int8 NULL DEFAULT NULL, + long_prop_2 int8 NULL DEFAULT NULL, + dec_prop_1 numeric(13, 4) NULL DEFAULT NULL, + dec_prop_2 numeric(13, 4) NULL DEFAULT NULL, + bool_prop_1 varchar(1) NULL DEFAULT NULL, + bool_prop_2 varchar(1) NULL DEFAULT NULL, + PRIMARY KEY (sched_name, trigger_name, trigger_group) +); + +-- ---------------------------- +-- qrtz_triggers +-- ---------------------------- +CREATE TABLE qrtz_triggers +( + sched_name varchar(120) NOT NULL, + trigger_name varchar(190) NOT NULL, + trigger_group varchar(190) NOT NULL, + job_name varchar(190) NOT NULL, + job_group varchar(190) NOT NULL, + description varchar(250) NULL DEFAULT NULL, + next_fire_time int8 NULL DEFAULT NULL, + prev_fire_time int8 NULL DEFAULT NULL, + priority int4 NULL DEFAULT NULL, + trigger_state varchar(16) NOT NULL, + trigger_type varchar(8) NOT NULL, + start_time int8 NOT NULL, + end_time int8 NULL DEFAULT NULL, + calendar_name varchar(190) NULL DEFAULT NULL, + misfire_instr int2 NULL DEFAULT NULL, + job_data bytea NULL, + PRIMARY KEY (sched_name, trigger_name, trigger_group) +); + +CREATE INDEX idx_qrtz_t_j ON qrtz_triggers (sched_name, job_name, job_group); +CREATE INDEX idx_qrtz_t_jg ON qrtz_triggers (sched_name, job_group); +CREATE INDEX idx_qrtz_t_c ON qrtz_triggers (sched_name, calendar_name); +CREATE INDEX idx_qrtz_t_g ON qrtz_triggers (sched_name, trigger_group); +CREATE INDEX idx_qrtz_t_state ON qrtz_triggers (sched_name, trigger_state); +CREATE INDEX idx_qrtz_t_n_state ON qrtz_triggers (sched_name, trigger_name, trigger_group, trigger_state); +CREATE INDEX idx_qrtz_t_n_g_state ON qrtz_triggers (sched_name, trigger_group, trigger_state); +CREATE INDEX idx_qrtz_t_next_fire_time ON qrtz_triggers (sched_name, next_fire_time); +CREATE INDEX idx_qrtz_t_nft_st ON qrtz_triggers (sched_name, trigger_state, next_fire_time); +CREATE INDEX idx_qrtz_t_nft_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time); +CREATE INDEX idx_qrtz_t_nft_st_misfire ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_state); +CREATE INDEX idx_qrtz_t_nft_st_misfire_grp ON qrtz_triggers (sched_name, misfire_instr, next_fire_time, trigger_group, + trigger_state); + +-- @formatter:off +BEGIN; +COMMIT; +-- @formatter:on + + +-- ---------------------------- +-- FK: qrtz_blob_triggers +-- ---------------------------- +ALTER TABLE qrtz_blob_triggers + ADD CONSTRAINT qrtz_blob_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, + trigger_name, + trigger_group); + +-- ---------------------------- +-- FK: qrtz_cron_triggers +-- ---------------------------- +ALTER TABLE qrtz_cron_triggers + ADD CONSTRAINT qrtz_cron_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group); + +-- ---------------------------- +-- FK: qrtz_simple_triggers +-- ---------------------------- +ALTER TABLE qrtz_simple_triggers + ADD CONSTRAINT qrtz_simple_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, + trigger_name, + trigger_group); + +-- ---------------------------- +-- FK: qrtz_simprop_triggers +-- ---------------------------- +ALTER TABLE qrtz_simprop_triggers + ADD CONSTRAINT qrtz_simprop_triggers_ibfk_1 FOREIGN KEY (sched_name, trigger_name, trigger_group) REFERENCES qrtz_triggers (sched_name, trigger_name, trigger_group); + +-- ---------------------------- +-- FK: qrtz_triggers +-- ---------------------------- +ALTER TABLE qrtz_triggers + ADD CONSTRAINT qrtz_triggers_ibfk_1 FOREIGN KEY (sched_name, job_name, job_group) REFERENCES qrtz_job_details (sched_name, job_name, job_group); diff --git a/ruoyi-vue-pro-master/sql/postgresql/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/postgresql/ruoyi-vue-pro.sql new file mode 100644 index 0000000..526d5a4 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/postgresql/ruoyi-vue-pro.sql @@ -0,0 +1,4723 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : PostgreSQL + + Date: 2024-05-08 00:11:06 +*/ + + +-- ---------------------------- +-- Table structure for dual +-- ---------------------------- +DROP TABLE IF EXISTS dual; +CREATE TABLE dual +( + id int2 +); + +COMMENT ON TABLE dual IS '数据库连接的表'; + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1); +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_access_log; +CREATE TABLE infra_api_access_log +( + id int8 NOT NULL, + trace_id varchar(64) NOT NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NOT NULL DEFAULT '', + request_url varchar(255) NOT NULL DEFAULT '', + request_params text NULL, + response_body text NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + operate_module varchar(50) NULL DEFAULT NULL, + operate_name varchar(50) NULL DEFAULT NULL, + operate_type int2 NULL DEFAULT 0, + begin_time timestamp NOT NULL, + end_time timestamp NOT NULL, + duration int4 NOT NULL, + result_code int4 NOT NULL DEFAULT 0, + result_msg varchar(512) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_access_log + ADD CONSTRAINT pk_infra_api_access_log PRIMARY KEY (id); + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time); + +COMMENT ON COLUMN infra_api_access_log.id IS '日志主键'; +COMMENT ON COLUMN infra_api_access_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN infra_api_access_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_access_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_access_log.application_name IS '应用名'; +COMMENT ON COLUMN infra_api_access_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_access_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_access_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_access_log.response_body IS '响应结果'; +COMMENT ON COLUMN infra_api_access_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_access_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_access_log.operate_module IS '操作模块'; +COMMENT ON COLUMN infra_api_access_log.operate_name IS '操作名'; +COMMENT ON COLUMN infra_api_access_log.operate_type IS '操作分类'; +COMMENT ON COLUMN infra_api_access_log.begin_time IS '开始请求时间'; +COMMENT ON COLUMN infra_api_access_log.end_time IS '结束请求时间'; +COMMENT ON COLUMN infra_api_access_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_api_access_log.result_code IS '结果码'; +COMMENT ON COLUMN infra_api_access_log.result_msg IS '结果提示'; +COMMENT ON COLUMN infra_api_access_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_access_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_access_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_access_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_access_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_access_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_access_log IS 'API 访问日志表'; + +DROP SEQUENCE IF EXISTS infra_api_access_log_seq; +CREATE SEQUENCE infra_api_access_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_error_log; +CREATE TABLE infra_api_error_log +( + id int4 NOT NULL, + trace_id varchar(64) NOT NULL, + user_id int4 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + application_name varchar(50) NOT NULL, + request_method varchar(16) NOT NULL, + request_url varchar(255) NOT NULL, + request_params varchar(8000) NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + exception_time timestamp NOT NULL, + exception_name varchar(128) NOT NULL DEFAULT '', + exception_message text NOT NULL, + exception_root_cause_message text NOT NULL, + exception_stack_trace text NOT NULL, + exception_class_name varchar(512) NOT NULL, + exception_file_name varchar(512) NOT NULL, + exception_method_name varchar(512) NOT NULL, + exception_line_number int4 NOT NULL, + process_status int2 NOT NULL, + process_time timestamp NULL DEFAULT NULL, + process_user_id int4 NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_api_error_log + ADD CONSTRAINT pk_infra_api_error_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_api_error_log.id IS '编号'; +COMMENT ON COLUMN infra_api_error_log.trace_id IS '链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。'; +COMMENT ON COLUMN infra_api_error_log.user_id IS '用户编号'; +COMMENT ON COLUMN infra_api_error_log.user_type IS '用户类型'; +COMMENT ON COLUMN infra_api_error_log.application_name IS '应用名 + * + * 目前读取 spring.application.name'; +COMMENT ON COLUMN infra_api_error_log.request_method IS '请求方法名'; +COMMENT ON COLUMN infra_api_error_log.request_url IS '请求地址'; +COMMENT ON COLUMN infra_api_error_log.request_params IS '请求参数'; +COMMENT ON COLUMN infra_api_error_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN infra_api_error_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN infra_api_error_log.exception_time IS '异常发生时间'; +COMMENT ON COLUMN infra_api_error_log.exception_name IS '异常名 + * + * {@link Throwable#getClass()} 的类全名'; +COMMENT ON COLUMN infra_api_error_log.exception_message IS '异常导致的消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '异常导致的根消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}'; +COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '异常的栈轨迹 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}'; +COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '异常发生的类全名 + * + * {@link StackTraceElement#getClassName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '异常发生的类文件 + * + * {@link StackTraceElement#getFileName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()}'; +COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()}'; +COMMENT ON COLUMN infra_api_error_log.process_status IS '处理状态'; +COMMENT ON COLUMN infra_api_error_log.process_time IS '处理时间'; +COMMENT ON COLUMN infra_api_error_log.process_user_id IS '处理用户编号'; +COMMENT ON COLUMN infra_api_error_log.creator IS '创建者'; +COMMENT ON COLUMN infra_api_error_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_api_error_log.updater IS '更新者'; +COMMENT ON COLUMN infra_api_error_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_api_error_log.deleted IS '是否删除'; +COMMENT ON COLUMN infra_api_error_log.tenant_id IS '租户编号'; +COMMENT ON TABLE infra_api_error_log IS '系统异常日志'; + +DROP SEQUENCE IF EXISTS infra_api_error_log_seq; +CREATE SEQUENCE infra_api_error_log_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_column; +CREATE TABLE infra_codegen_column +( + id int8 NOT NULL, + table_id int8 NOT NULL, + column_name varchar(200) NOT NULL, + data_type varchar(100) NOT NULL, + column_comment varchar(500) NOT NULL, + nullable bool NOT NULL, + primary_key bool NOT NULL, + ordinal_position int4 NOT NULL, + java_type varchar(32) NOT NULL, + java_field varchar(64) NOT NULL, + dict_type varchar(200) NULL DEFAULT '', + example varchar(64) NULL DEFAULT NULL, + create_operation bool NOT NULL, + update_operation bool NOT NULL, + list_operation bool NOT NULL, + list_operation_condition varchar(32) NOT NULL DEFAULT '=', + list_operation_result bool NOT NULL, + html_type varchar(32) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_column + ADD CONSTRAINT pk_infra_codegen_column PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_column.id IS '编号'; +COMMENT ON COLUMN infra_codegen_column.table_id IS '表编号'; +COMMENT ON COLUMN infra_codegen_column.column_name IS '字段名'; +COMMENT ON COLUMN infra_codegen_column.data_type IS '字段类型'; +COMMENT ON COLUMN infra_codegen_column.column_comment IS '字段描述'; +COMMENT ON COLUMN infra_codegen_column.nullable IS '是否允许为空'; +COMMENT ON COLUMN infra_codegen_column.primary_key IS '是否主键'; +COMMENT ON COLUMN infra_codegen_column.ordinal_position IS '排序'; +COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java 属性类型'; +COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java 属性名'; +COMMENT ON COLUMN infra_codegen_column.dict_type IS '字典类型'; +COMMENT ON COLUMN infra_codegen_column.example IS '数据示例'; +COMMENT ON COLUMN infra_codegen_column.create_operation IS '是否为 Create 创建操作的字段'; +COMMENT ON COLUMN infra_codegen_column.update_operation IS '是否为 Update 更新操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation IS '是否为 List 查询操作的字段'; +COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List 查询操作的条件类型'; +COMMENT ON COLUMN infra_codegen_column.list_operation_result IS '是否为 List 查询操作的返回字段'; +COMMENT ON COLUMN infra_codegen_column.html_type IS '显示类型'; +COMMENT ON COLUMN infra_codegen_column.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_column.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_column.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_column.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_column.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_column IS '代码生成表字段定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_column_seq; +CREATE SEQUENCE infra_codegen_column_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_table; +CREATE TABLE infra_codegen_table +( + id int8 NOT NULL, + data_source_config_id int8 NOT NULL, + scene int2 NOT NULL DEFAULT 1, + table_name varchar(200) NOT NULL DEFAULT '', + table_comment varchar(500) NOT NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + module_name varchar(30) NOT NULL, + business_name varchar(30) NOT NULL, + class_name varchar(100) NOT NULL DEFAULT '', + class_comment varchar(50) NOT NULL, + author varchar(50) NOT NULL, + template_type int2 NOT NULL DEFAULT 1, + front_type int2 NOT NULL, + parent_menu_id int8 NULL DEFAULT NULL, + master_table_id int8 NULL DEFAULT NULL, + sub_join_column_id int8 NULL DEFAULT NULL, + sub_join_many bool NULL DEFAULT NULL, + tree_parent_column_id int8 NULL DEFAULT NULL, + tree_name_column_id int8 NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_codegen_table + ADD CONSTRAINT pk_infra_codegen_table PRIMARY KEY (id); + +COMMENT ON COLUMN infra_codegen_table.id IS '编号'; +COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS '数据源配置的编号'; +COMMENT ON COLUMN infra_codegen_table.scene IS '生成场景'; +COMMENT ON COLUMN infra_codegen_table.table_name IS '表名称'; +COMMENT ON COLUMN infra_codegen_table.table_comment IS '表描述'; +COMMENT ON COLUMN infra_codegen_table.remark IS '备注'; +COMMENT ON COLUMN infra_codegen_table.module_name IS '模块名'; +COMMENT ON COLUMN infra_codegen_table.business_name IS '业务名'; +COMMENT ON COLUMN infra_codegen_table.class_name IS '类名称'; +COMMENT ON COLUMN infra_codegen_table.class_comment IS '类描述'; +COMMENT ON COLUMN infra_codegen_table.author IS '作者'; +COMMENT ON COLUMN infra_codegen_table.template_type IS '模板类型'; +COMMENT ON COLUMN infra_codegen_table.front_type IS '前端类型'; +COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '父菜单编号'; +COMMENT ON COLUMN infra_codegen_table.master_table_id IS '主表的编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS '子表关联主表的字段编号'; +COMMENT ON COLUMN infra_codegen_table.sub_join_many IS '主表与子表是否一对多'; +COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS '树表的父字段编号'; +COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS '树表的名字字段编号'; +COMMENT ON COLUMN infra_codegen_table.creator IS '创建者'; +COMMENT ON COLUMN infra_codegen_table.create_time IS '创建时间'; +COMMENT ON COLUMN infra_codegen_table.updater IS '更新者'; +COMMENT ON COLUMN infra_codegen_table.update_time IS '更新时间'; +COMMENT ON COLUMN infra_codegen_table.deleted IS '是否删除'; +COMMENT ON TABLE infra_codegen_table IS '代码生成表定义'; + +DROP SEQUENCE IF EXISTS infra_codegen_table_seq; +CREATE SEQUENCE infra_codegen_table_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_config; +CREATE TABLE infra_config +( + id int4 NOT NULL, + category varchar(50) NOT NULL, + type int2 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + config_key varchar(100) NOT NULL DEFAULT '', + value varchar(500) NOT NULL DEFAULT '', + visible bool NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_config + ADD CONSTRAINT pk_infra_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_config.id IS '参数主键'; +COMMENT ON COLUMN infra_config.category IS '参数分组'; +COMMENT ON COLUMN infra_config.type IS '参数类型'; +COMMENT ON COLUMN infra_config.name IS '参数名称'; +COMMENT ON COLUMN infra_config.config_key IS '参数键名'; +COMMENT ON COLUMN infra_config.value IS '参数键值'; +COMMENT ON COLUMN infra_config.visible IS '是否可见'; +COMMENT ON COLUMN infra_config.remark IS '备注'; +COMMENT ON COLUMN infra_config.creator IS '创建者'; +COMMENT ON COLUMN infra_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_config.updater IS '更新者'; +COMMENT ON COLUMN infra_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_config IS '参数配置表'; + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, '用户管理-账号初始密码', 'sys.user.init-password', '123456', '0', '初始化密码 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-04-03 17:22:28', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL 监控的地址', 'url.druid', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking 监控的地址', 'url.skywalking', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin 监控的地址', 'url.spring-boot-admin', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger 接口文档的地址', 'url.swagger', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, 'ui', 2, '腾讯地图 key', 'tencent.lbs.key', 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', '1', '腾讯地图 key', '1', '2023-06-03 19:16:27', '1', '2023-06-03 19:16:27', '0'); +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', '2023-12-03 09:55:16', '1', '2023-12-03 09:55:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_config_seq; +CREATE SEQUENCE infra_config_seq + START 13; + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_data_source_config; +CREATE TABLE infra_data_source_config +( + id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + url varchar(1024) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_data_source_config + ADD CONSTRAINT pk_infra_data_source_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_data_source_config.id IS '主键编号'; +COMMENT ON COLUMN infra_data_source_config.name IS '参数名称'; +COMMENT ON COLUMN infra_data_source_config.url IS '数据源连接'; +COMMENT ON COLUMN infra_data_source_config.username IS '用户名'; +COMMENT ON COLUMN infra_data_source_config.password IS '密码'; +COMMENT ON COLUMN infra_data_source_config.creator IS '创建者'; +COMMENT ON COLUMN infra_data_source_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_data_source_config.updater IS '更新者'; +COMMENT ON COLUMN infra_data_source_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_data_source_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_data_source_config IS '数据源配置表'; + +DROP SEQUENCE IF EXISTS infra_data_source_config_seq; +CREATE SEQUENCE infra_data_source_config_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +DROP TABLE IF EXISTS infra_file; +CREATE TABLE infra_file +( + id int8 NOT NULL, + config_id int8 NULL DEFAULT NULL, + name varchar(256) NULL DEFAULT NULL, + path varchar(512) NOT NULL, + url varchar(1024) NOT NULL, + type varchar(128) NULL DEFAULT NULL, + size int4 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file + ADD CONSTRAINT pk_infra_file PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file.id IS '文件编号'; +COMMENT ON COLUMN infra_file.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file.name IS '文件名'; +COMMENT ON COLUMN infra_file.path IS '文件路径'; +COMMENT ON COLUMN infra_file.url IS '文件 URL'; +COMMENT ON COLUMN infra_file.type IS '文件类型'; +COMMENT ON COLUMN infra_file.size IS '文件大小'; +COMMENT ON COLUMN infra_file.creator IS '创建者'; +COMMENT ON COLUMN infra_file.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file.updater IS '更新者'; +COMMENT ON COLUMN infra_file.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file.deleted IS '是否删除'; +COMMENT ON TABLE infra_file IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_seq; +CREATE SEQUENCE infra_file_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_config; +CREATE TABLE infra_file_config +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + storage int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + master bool NOT NULL, + config varchar(4096) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_config + ADD CONSTRAINT pk_infra_file_config PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_config.id IS '编号'; +COMMENT ON COLUMN infra_file_config.name IS '配置名'; +COMMENT ON COLUMN infra_file_config.storage IS '存储器'; +COMMENT ON COLUMN infra_file_config.remark IS '备注'; +COMMENT ON COLUMN infra_file_config.master IS '是否为主配置'; +COMMENT ON COLUMN infra_file_config.config IS '存储配置'; +COMMENT ON COLUMN infra_file_config.creator IS '创建者'; +COMMENT ON COLUMN infra_file_config.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_config.updater IS '更新者'; +COMMENT ON COLUMN infra_file_config.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_config.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_config IS '文件配置表'; + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '数据库', 1, '我是数据库', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2024-02-28 22:54:07', '0'); +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '七牛存储器', 20, '', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_file_config_seq; +CREATE SEQUENCE infra_file_config_seq + START 23; + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_content; +CREATE TABLE infra_file_content +( + id int8 NOT NULL, + config_id int8 NOT NULL, + path varchar(512) NOT NULL, + content bytea NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_file_content + ADD CONSTRAINT pk_infra_file_content PRIMARY KEY (id); + +COMMENT ON COLUMN infra_file_content.id IS '编号'; +COMMENT ON COLUMN infra_file_content.config_id IS '配置编号'; +COMMENT ON COLUMN infra_file_content.path IS '文件路径'; +COMMENT ON COLUMN infra_file_content.content IS '文件内容'; +COMMENT ON COLUMN infra_file_content.creator IS '创建者'; +COMMENT ON COLUMN infra_file_content.create_time IS '创建时间'; +COMMENT ON COLUMN infra_file_content.updater IS '更新者'; +COMMENT ON COLUMN infra_file_content.update_time IS '更新时间'; +COMMENT ON COLUMN infra_file_content.deleted IS '是否删除'; +COMMENT ON TABLE infra_file_content IS '文件表'; + +DROP SEQUENCE IF EXISTS infra_file_content_seq; +CREATE SEQUENCE infra_file_content_seq + START 1; + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +DROP TABLE IF EXISTS infra_job; +CREATE TABLE infra_job +( + id int8 NOT NULL, + name varchar(32) NOT NULL, + status int2 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + cron_expression varchar(32) NOT NULL, + retry_count int4 NOT NULL DEFAULT 0, + retry_interval int4 NOT NULL DEFAULT 0, + monitor_timeout int4 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job + ADD CONSTRAINT pk_infra_job PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job.id IS '任务编号'; +COMMENT ON COLUMN infra_job.name IS '任务名称'; +COMMENT ON COLUMN infra_job.status IS '任务状态'; +COMMENT ON COLUMN infra_job.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job.cron_expression IS 'CRON 表达式'; +COMMENT ON COLUMN infra_job.retry_count IS '重试次数'; +COMMENT ON COLUMN infra_job.retry_interval IS '重试间隔'; +COMMENT ON COLUMN infra_job.monitor_timeout IS '监控超时时间'; +COMMENT ON COLUMN infra_job.creator IS '创建者'; +COMMENT ON COLUMN infra_job.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job.updater IS '更新者'; +COMMENT ON COLUMN infra_job.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job.deleted IS '是否删除'; +COMMENT ON TABLE infra_job IS '定时任务表'; + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', '0'); +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2023-10-03 11:01:42', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS infra_job_seq; +CREATE SEQUENCE infra_job_seq + START 28; + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_job_log; +CREATE TABLE infra_job_log +( + id int8 NOT NULL, + job_id int8 NOT NULL, + handler_name varchar(64) NOT NULL, + handler_param varchar(255) NULL DEFAULT NULL, + execute_index int2 NOT NULL DEFAULT 1, + begin_time timestamp NOT NULL, + end_time timestamp NULL DEFAULT NULL, + duration int4 NULL DEFAULT NULL, + status int2 NOT NULL, + result varchar(4000) NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE infra_job_log + ADD CONSTRAINT pk_infra_job_log PRIMARY KEY (id); + +COMMENT ON COLUMN infra_job_log.id IS '日志编号'; +COMMENT ON COLUMN infra_job_log.job_id IS '任务编号'; +COMMENT ON COLUMN infra_job_log.handler_name IS '处理器的名字'; +COMMENT ON COLUMN infra_job_log.handler_param IS '处理器的参数'; +COMMENT ON COLUMN infra_job_log.execute_index IS '第几次执行'; +COMMENT ON COLUMN infra_job_log.begin_time IS '开始执行时间'; +COMMENT ON COLUMN infra_job_log.end_time IS '结束执行时间'; +COMMENT ON COLUMN infra_job_log.duration IS '执行时长'; +COMMENT ON COLUMN infra_job_log.status IS '任务状态'; +COMMENT ON COLUMN infra_job_log.result IS '结果数据'; +COMMENT ON COLUMN infra_job_log.creator IS '创建者'; +COMMENT ON COLUMN infra_job_log.create_time IS '创建时间'; +COMMENT ON COLUMN infra_job_log.updater IS '更新者'; +COMMENT ON COLUMN infra_job_log.update_time IS '更新时间'; +COMMENT ON COLUMN infra_job_log.deleted IS '是否删除'; +COMMENT ON TABLE infra_job_log IS '定时任务日志表'; + +DROP SEQUENCE IF EXISTS infra_job_log_seq; +CREATE SEQUENCE infra_job_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +DROP TABLE IF EXISTS system_dept; +CREATE TABLE system_dept +( + id int8 NOT NULL, + name varchar(30) NOT NULL DEFAULT '', + parent_id int8 NOT NULL DEFAULT 0, + sort int4 NOT NULL DEFAULT 0, + leader_user_id int8 NULL DEFAULT NULL, + phone varchar(11) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dept + ADD CONSTRAINT pk_system_dept PRIMARY KEY (id); + +COMMENT ON COLUMN system_dept.id IS '部门id'; +COMMENT ON COLUMN system_dept.name IS '部门名称'; +COMMENT ON COLUMN system_dept.parent_id IS '父部门id'; +COMMENT ON COLUMN system_dept.sort IS '显示顺序'; +COMMENT ON COLUMN system_dept.leader_user_id IS '负责人'; +COMMENT ON COLUMN system_dept.phone IS '联系电话'; +COMMENT ON COLUMN system_dept.email IS '邮箱'; +COMMENT ON COLUMN system_dept.status IS '部门状态(0正常 1停用)'; +COMMENT ON COLUMN system_dept.creator IS '创建者'; +COMMENT ON COLUMN system_dept.create_time IS '创建时间'; +COMMENT ON COLUMN system_dept.updater IS '更新者'; +COMMENT ON COLUMN system_dept.update_time IS '更新时间'; +COMMENT ON COLUMN system_dept.deleted IS '是否删除'; +COMMENT ON COLUMN system_dept.tenant_id IS '租户编号'; +COMMENT ON TABLE system_dept IS '部门表'; + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, '运维部门', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, '市场部门', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '财务部门', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '新部门', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', '0', 121); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '顶级部门', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', '0', 122); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, '产品部门', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', '0', 1); +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, '支持部门', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2023-12-02 09:47:38', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dept_seq; +CREATE SEQUENCE system_dept_seq + START 114; + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_data; +CREATE TABLE system_dict_data +( + id int8 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + label varchar(100) NOT NULL DEFAULT '', + value varchar(100) NOT NULL DEFAULT '', + dict_type varchar(100) NOT NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + color_type varchar(100) NULL DEFAULT '', + css_class varchar(100) NULL DEFAULT '', + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_dict_data + ADD CONSTRAINT pk_system_dict_data PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_data.id IS '字典编码'; +COMMENT ON COLUMN system_dict_data.sort IS '字典排序'; +COMMENT ON COLUMN system_dict_data.label IS '字典标签'; +COMMENT ON COLUMN system_dict_data.value IS '字典键值'; +COMMENT ON COLUMN system_dict_data.dict_type IS '字典类型'; +COMMENT ON COLUMN system_dict_data.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_data.color_type IS '颜色类型'; +COMMENT ON COLUMN system_dict_data.css_class IS 'css 样式'; +COMMENT ON COLUMN system_dict_data.remark IS '备注'; +COMMENT ON COLUMN system_dict_data.creator IS '创建者'; +COMMENT ON COLUMN system_dict_data.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_data.updater IS '更新者'; +COMMENT ON COLUMN system_dict_data.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_data.deleted IS '是否删除'; +COMMENT ON TABLE system_dict_data IS '字典数据表'; + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, '自定义', '2', 'infra_config_type', 0, 'primary', '', '参数类型 - 自定义', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '通知', '1', 'system_notice_type', 0, 'success', '', '通知', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '公告', '2', 'system_notice_type', 0, 'info', '', '公告', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '其它', '0', 'infra_operate_type', 0, 'default', '', '其它操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, '查询', '1', 'infra_operate_type', 0, 'info', '', '查询操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '新增', '2', 'infra_operate_type', 0, 'primary', '', '新增操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '修改', '3', 'infra_operate_type', 0, 'warning', '', '修改操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, '删除', '4', 'infra_operate_type', 0, 'danger', '', '删除操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '导出', '5', 'infra_operate_type', 0, 'default', '', '导出操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '导入', '6', 'infra_operate_type', 0, 'default', '', '导入操作', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '开启', '0', 'common_status', 0, 'primary', '', '开启状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, '关闭', '1', 'common_status', 0, 'info', '', '关闭状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, '目录', '1', 'system_menu_type', 0, '', '', '目录', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '菜单', '2', 'system_menu_type', 0, '', '', '菜单', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, '按钮', '3', 'system_menu_type', 0, '', '', '按钮', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '内置', '1', 'system_role_type', 0, 'danger', '', '内置角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, '自定义', '2', 'system_role_type', 0, 'primary', '', '自定义角色', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, '全部数据权限', '1', 'system_data_scope', 0, '', '', '全部数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, '指定部门数据权限', '2', 'system_data_scope', 0, '', '', '指定部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '本部门数据权限', '3', 'system_data_scope', 0, '', '', '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '本部门及以下数据权限', '4', 'system_data_scope', 0, '', '', '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '仅本人数据权限', '5', 'system_data_scope', 0, '', '', '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '成功', '0', 'system_login_result', 0, 'success', '', '登陆结果 - 成功', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '账号或密码不正确', '10', 'system_login_result', 0, 'primary', '', '登陆结果 - 账号或密码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '用户被禁用', '20', 'system_login_result', 0, 'warning', '', '登陆结果 - 用户被禁用', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '验证码不存在', '30', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不存在', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '验证码不正确', '31', 'system_login_result', 0, 'info', '', '登陆结果 - 验证码不正确', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, '未知异常', '100', 'system_login_result', 0, 'danger', '', '登陆结果 - 未知异常', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '是', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 是否类型 - 是', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '否', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 是否类型 - 否', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, '单表(增删改查)', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, '树表(增删改查)', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, '初始化中', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '运行中', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, '成功', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, '失败', '2', 'infra_job_log_status', 0, 'warning', '', '失败', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, '会员', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, '管理员', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2022-02-16 10:22:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, '未处理', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, '已处理', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, '已忽略', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, '阿里云', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2022-02-16 10:09:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '验证码', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '通知', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, '营销', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, '初始化', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, '发送成功', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, '发送失败', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '不发送', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, '等待结果', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '支付宝 PC 网站支付', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '支付宝 PC 网站支付', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '支付宝 Wap 网站支付', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '支付宝 Wap 网站支付', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '支付宝 App 支付', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '支付宝 App 支付', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '支付宝扫码支付', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '支付宝扫码支付', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '通知成功', '10', 'pay_notify_status', 0, 'success', '', '通知成功', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '通知失败', '20', 'pay_notify_status', 0, 'danger', '', '通知失败', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '等待通知', '0', 'pay_notify_status', 0, 'info', '', '未通知', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '支付成功', '10', 'pay_order_status', 0, 'success', '', '支付成功', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '支付关闭', '30', 'pay_order_status', 0, 'info', '', '支付关闭', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, '等待支付', '0', 'pay_order_status', 0, 'info', '', '未支付', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, '首页', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, '秒杀活动页', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, '砍价活动页', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, '限时折扣页', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, '满减送页', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, '本地磁盘', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP 服务器', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP 服务器', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 对象存储', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, '短信登录', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '密码模式', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '授权码模式', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '简化模式', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '客户端模式', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '刷新模式', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '销售中', '1', 'product_spu_status', 0, 'success', '', '商品 SPU 状态 - 销售中', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, '仓库中', '0', 'product_spu_status', 0, 'info', '', '商品 SPU 状态 - 仓库中', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, '回收站', '-1', 'product_spu_status', 0, 'default', '', '商品 SPU 状态 - 回收站', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '满减', '1', 'promotion_discount_type', 0, 'success', '', '优惠类型 - 满减', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, '折扣', '2', 'promotion_discount_type', 0, 'primary', '', '优惠类型 - 折扣', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '固定日期', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 固定日期', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, '领取之后', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '优惠劵模板的有限期类型 - 领取之后', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, '通用劵', '1', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 全部商品参与', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, '商品劵', '2', 'promotion_product_scope', 0, 'default', '', '营销的商品范围 - 指定商品参与', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, '未使用', '1', 'promotion_coupon_status', 0, 'primary', '', '优惠劵的状态 - 已领取', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, '已使用', '2', 'promotion_coupon_status', 0, 'success', '', '优惠劵的状态 - 已使用', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, '已过期', '3', 'promotion_coupon_status', 0, 'info', '', '优惠劵的状态 - 已过期', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, '直接领取', '1', 'promotion_coupon_take_type', 0, 'primary', '', '优惠劵的领取方式 - 直接领取', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, '指定发放', '2', 'promotion_coupon_take_type', 0, 'success', '', '优惠劵的领取方式 - 指定发放', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, '未开始', '10', 'promotion_activity_status', 0, 'primary', '', '促销活动的状态枚举 - 未开始', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '进行中', '20', 'promotion_activity_status', 0, 'success', '', '促销活动的状态枚举 - 进行中', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, '已结束', '30', 'promotion_activity_status', 0, 'info', '', '促销活动的状态枚举 - 已结束', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, '已关闭', '40', 'promotion_activity_status', 0, 'warning', '', '促销活动的状态枚举 - 已关闭', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, '满 N 元', '10', 'promotion_condition_type', 0, 'primary', '', '营销的条件类型 - 满 N 元', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, '满 N 件', '20', 'promotion_condition_type', 0, 'success', '', '营销的条件类型 - 满 N 件', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, '申请售后', '10', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 申请售后', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, '商品待退货', '20', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商品待退货', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '商家待收货', '30', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 商家待收货', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, '等待退款', '40', 'trade_after_sale_status', 0, 'primary', '', '交易售后状态 - 等待退款', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '退款成功', '50', 'trade_after_sale_status', 0, 'default', '', '交易售后状态 - 退款成功', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, '买家取消', '61', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 买家取消', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '商家拒绝', '62', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒绝', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '商家拒收货', '63', 'trade_after_sale_status', 0, 'info', '', '交易售后状态 - 商家拒收货', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '售中退款', '10', 'trade_after_sale_type', 0, 'success', '', '交易售后的类型 - 售中退款', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, '售后退款', '20', 'trade_after_sale_type', 0, 'primary', '', '交易售后的类型 - 售后退款', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '仅退款', '10', 'trade_after_sale_way', 0, 'primary', '', '交易售后的方式 - 仅退款', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '退货退款', '20', 'trade_after_sale_way', 0, 'success', '', '交易售后的方式 - 退货退款', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '微信小程序', '10', 'terminal', 0, 'default', '', '终端 - 微信小程序', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 网页', '20', 'terminal', 0, 'default', '', '终端 - H5 网页', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '微信公众号', '11', 'terminal', 0, 'default', '', '终端 - 微信公众号', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, '苹果 App', '31', 'terminal', 0, 'default', '', '终端 - 苹果 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '已完成', '30', 'trade_order_status', 0, 'success', '', '交易订单状态 - 已完成', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, '已取消', '40', 'trade_order_status', 0, 'danger', '', '交易订单状态 - 已取消', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, '未售后', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '交易订单项的售后状态 - 未售后', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, '售后中', '1', 'trade_order_item_after_sale_status', 0, 'primary', '', '交易订单项的售后状态 - 售后中', '1', '2022-12-10 20:59:21', '1', '2022-12-10 20:59:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, '已退款', '2', 'trade_order_item_after_sale_status', 0, 'success', '', '交易订单项的售后状态 - 已退款', '1', '2022-12-10 20:59:46', '1', '2022-12-10 20:59:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, '完全匹配', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '公众号自动回复的请求关键字匹配模式 - 完全匹配', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, '半匹配', '2', 'mp_auto_reply_request_match', 0, 'success', '', '公众号自动回复的请求关键字匹配模式 - 半匹配', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, '文本', 'text', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 文本', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, '图片', 'image', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图片', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '语音', 'voice', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 语音', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, '视频', 'video', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, '小视频', 'shortvideo', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 小视频', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, '图文', 'news', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 图文', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '音乐', 'music', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 音乐', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, '地理位置', 'location', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 地理位置', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '链接', 'link', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 链接', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '事件', 'event', 'mp_message_type', 0, 'default', '', '公众号的消息类型 - 事件', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, '初始化', '0', 'system_mail_send_status', 0, 'primary', '', '邮件发送状态 - 初始化\n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, '发送成功', '10', 'system_mail_send_status', 0, 'success', '', '邮件发送状态 - 发送成功', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, '发送失败', '20', 'system_mail_send_status', 0, 'danger', '', '邮件发送状态 - 发送失败', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '不发送', '30', 'system_mail_send_status', 0, 'info', '', '邮件发送状态 - 不发送', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '通知公告', '1', 'system_notify_template_type', 0, 'primary', '', '站内信模版的类型 - 通知公告', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, '系统消息', '2', 'system_notify_template_type', 0, 'success', '', '站内信模版的类型 - 系统消息', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, '订单积分抵扣', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, '签到', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '已退款', '20', 'pay_order_status', 0, 'danger', '', '已退款', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, '请求成功,但是结果失败', '21', 'pay_notify_status', 0, 'warning', '', '请求成功,但是结果失败', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, '请求失败', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '微信扫码支付', 'wx_native', 'pay_channel_code', 0, 'success', '', '微信扫码支付', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '微信条码支付', 'wx_bar', 'pay_channel_code', 0, 'success', '', '微信条码支付\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '支付单', '1', 'pay_notify_type', 0, 'primary', '', '支付单', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '退款单', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, '模拟支付', 'mock', 'pay_channel_code', 0, 'default', '', '模拟支付', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, '订单积分抵扣(整单取消)', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, '管理员调整', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '邀新奖励', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, '下单奖励', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, '下单奖励(整单取消)', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, '签到奖励', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '抽奖奖励', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, '快递发货', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, '用户自提', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, '品类劵', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '人人分销', '1', 'brokerage_enabled_condition', 0, '', '', '所有用户都可以分销', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, '指定分销', '2', 'brokerage_enabled_condition', 0, '', '', '仅可后台手动设置推广员', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '首次绑定', '1', 'brokerage_bind_mode', 0, '', '', '只要用户没有推广人,随时都可以绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, '注册绑定', '2', 'brokerage_bind_mode', 0, '', '', '仅新用户注册时才能绑定推广关系', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, '申请提现驳回', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '待结算', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, '已结算', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, '已取消', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '审核中', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, '审核通过', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, '提现成功', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '审核不通过', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, '提现失败', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '工商银行', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '建设银行', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, '农业银行', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, '中国银行', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, '交通银行', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '招商银行', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, '钱包', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, '订单积分奖励(整单取消)', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, '订单积分奖励(单个退款)', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, '下单奖励(单个退款)', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '支付宝', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '微信支付', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '其他', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, '金融业', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, '房地产', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, '商业服务', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '运输/物流', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '生产', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '政府', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, '文化传媒', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A (重点客户)', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B (普通客户)', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C (非优先客户)', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '促销', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '搜索引擎', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '广告', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, '转介绍', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, '线上注册', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, '线上咨询', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, '预约上门', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, '陌拜', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '电话咨询', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, '邮件咨询', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '钉钉', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, '企业微信', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '负责人', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, '只读', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, '读写', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, '未提交', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '审批中', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, '审核通过', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '审核不通过', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, '已取消', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '支票', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, '现金', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '邮政汇款', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '电汇', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, '网上转账', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '个', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '块', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, '只', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '把', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, '枚', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, '瓶', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '盒', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '台', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '吨', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, '千克', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '米', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '箱', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '套', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '打电话', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '发短信', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, '上门拜访', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '微信沟通', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '其它入库', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '其它入库(作废)', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '其它出库', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '其它出库(作废)', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, '未审核', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '已审核', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '调拨入库', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '调拨入库(作废)', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '调拨出库', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '调拨出库(作废)', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, '盘盈入库', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, '盘盈入库(作废)', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '盘亏出库', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '盘亏出库(作废)', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '销售出库', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '销售出库(作废)', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '销售退货入库', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '销售退货入库(作废)', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, '采购入库', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '天', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '周', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_data_seq; +CREATE SEQUENCE system_dict_data_seq + START 1537; + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_type; +CREATE TABLE system_dict_type +( + id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + type varchar(100) NOT NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + deleted_time timestamp NULL DEFAULT NULL +); + +ALTER TABLE system_dict_type + ADD CONSTRAINT pk_system_dict_type PRIMARY KEY (id); + +COMMENT ON COLUMN system_dict_type.id IS '字典主键'; +COMMENT ON COLUMN system_dict_type.name IS '字典名称'; +COMMENT ON COLUMN system_dict_type.type IS '字典类型'; +COMMENT ON COLUMN system_dict_type.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_dict_type.remark IS '备注'; +COMMENT ON COLUMN system_dict_type.creator IS '创建者'; +COMMENT ON COLUMN system_dict_type.create_time IS '创建时间'; +COMMENT ON COLUMN system_dict_type.updater IS '更新者'; +COMMENT ON COLUMN system_dict_type.update_time IS '更新时间'; +COMMENT ON COLUMN system_dict_type.deleted IS '是否删除'; +COMMENT ON COLUMN system_dict_type.deleted_time IS '删除时间'; +COMMENT ON TABLE system_dict_type IS '字典类型表'; + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, '用户性别', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '参数类型', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '通知类型', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '操作类型', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, '系统状态', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean 是否类型', 'infra_boolean_string', 0, 'boolean 转是否', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '登陆结果', 'system_login_result', 0, '登陆结果', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, '代码生成模板类型', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, '定时任务状态', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, '定时任务日志状态', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 异常数据的处理状态', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '短信渠道编码', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 授权类型', 'system_oauth2_grant_type', 0, 'OAuth 2.0 授权类型(模式)', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, '商品 SPU 状态', 'product_spu_status', 0, '商品 SPU 状态', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, '优惠类型', 'promotion_discount_type', 0, '优惠类型', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, '优惠劵模板的有限期类型', 'promotion_coupon_template_validity_type', 0, '优惠劵模板的有限期类型', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, '营销的商品范围', 'promotion_product_scope', 0, '营销的商品范围', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, '优惠劵的状态', 'promotion_coupon_status', 0, '优惠劵的状态', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, '优惠劵的领取方式', 'promotion_coupon_take_type', 0, '优惠劵的领取方式', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '促销活动的状态', 'promotion_activity_status', 0, '促销活动的状态', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, '营销的条件类型', 'promotion_condition_type', 0, '营销的条件类型', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, '交易售后状态', 'trade_after_sale_status', 0, '交易售后状态', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, '交易售后的类型', 'trade_after_sale_type', 0, '交易售后的类型', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, '交易售后的方式', 'trade_after_sale_way', 0, '交易售后的方式', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, '终端', 'terminal', 0, '终端', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '交易订单的类型', 'trade_order_type', 0, '交易订单的类型', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '交易订单的状态', 'trade_order_status', 0, '交易订单的状态', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '交易订单项的售后状态', 'trade_order_item_after_sale_status', 0, '交易订单项的售后状态', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, '公众号自动回复的请求关键字匹配模式', 'mp_auto_reply_request_match', 0, '公众号自动回复的请求关键字匹配模式', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, '公众号的消息类型', 'mp_message_type', 0, '公众号的消息类型', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, '邮件发送状态', 'system_mail_send_status', 0, '邮件发送状态', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, '站内信模版的类型', 'system_notify_template_type', 0, '站内信模版的类型', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, '代码生成的前端类型', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, '快递计费方式', 'trade_delivery_express_charge_mode', 0, '用于商城交易模块配送管理', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, '积分业务类型', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '支付通知类型', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, '会员经验业务类型', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '交易配送类型', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, '分佣模式', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, '分销关系绑定模式', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, '佣金提现类型', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, '佣金记录业务类型', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, '佣金记录状态', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, '佣金提现状态', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, '佣金提现银行', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, '砍价记录的状态', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, '拼团记录的状态', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, '回款-回款方式', 'crm_receivable_return_type', 0, '回款-回款方式', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM 客户行业', 'crm_customer_industry', 0, 'CRM 客户所属行业', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, '客户等级', 'crm_customer_level', 0, 'CRM 客户等级', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', '0', NULL); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM 数据权限的级别', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM 审批状态', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM 产品单位', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM 跟进方式', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', '0', '1970-01-01 00:00:00'); +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', '0', '1970-01-01 00:00:00'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_dict_type_seq; +CREATE SEQUENCE system_dict_type_seq + START 620; + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +DROP TABLE IF EXISTS system_login_log; +CREATE TABLE system_login_log +( + id int8 NOT NULL, + log_type int8 NOT NULL, + trace_id varchar(64) NOT NULL DEFAULT '', + user_id int8 NOT NULL DEFAULT 0, + user_type int2 NOT NULL DEFAULT 0, + username varchar(50) NOT NULL DEFAULT '', + result int2 NOT NULL, + user_ip varchar(50) NOT NULL, + user_agent varchar(512) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_login_log + ADD CONSTRAINT pk_system_login_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_login_log.id IS '访问ID'; +COMMENT ON COLUMN system_login_log.log_type IS '日志类型'; +COMMENT ON COLUMN system_login_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_login_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_login_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_login_log.username IS '用户账号'; +COMMENT ON COLUMN system_login_log.result IS '登陆结果'; +COMMENT ON COLUMN system_login_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_login_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_login_log.creator IS '创建者'; +COMMENT ON COLUMN system_login_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_login_log.updater IS '更新者'; +COMMENT ON COLUMN system_login_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_login_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_login_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_login_log IS '系统访问记录'; + +DROP SEQUENCE IF EXISTS system_login_log_seq; +CREATE SEQUENCE system_login_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_account; +CREATE TABLE system_mail_account +( + id int8 NOT NULL, + mail varchar(255) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + host varchar(255) NOT NULL, + port int4 NOT NULL, + ssl_enable bool NOT NULL DEFAULT '0', + starttls_enable bool NOT NULL DEFAULT '0', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_account + ADD CONSTRAINT pk_system_mail_account PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_account.id IS '主键'; +COMMENT ON COLUMN system_mail_account.mail IS '邮箱'; +COMMENT ON COLUMN system_mail_account.username IS '用户名'; +COMMENT ON COLUMN system_mail_account.password IS '密码'; +COMMENT ON COLUMN system_mail_account.host IS 'SMTP 服务器域名'; +COMMENT ON COLUMN system_mail_account.port IS 'SMTP 服务器端口'; +COMMENT ON COLUMN system_mail_account.ssl_enable IS '是否开启 SSL'; +COMMENT ON COLUMN system_mail_account.starttls_enable IS '是否开启 STARTTLS'; +COMMENT ON COLUMN system_mail_account.creator IS '创建者'; +COMMENT ON COLUMN system_mail_account.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_account.updater IS '更新者'; +COMMENT ON COLUMN system_mail_account.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_account.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_account IS '邮箱账号表'; + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', '0'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', '1'); +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', '1'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_account_seq; +CREATE SEQUENCE system_mail_account_seq + START 5; + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_log; +CREATE TABLE system_mail_log +( + id int8 NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + to_mail varchar(255) NOT NULL, + account_id int8 NOT NULL, + from_mail varchar(255) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_nickname varchar(255) NULL DEFAULT NULL, + template_title varchar(255) NOT NULL, + template_content varchar(10240) NOT NULL, + template_params varchar(255) NOT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + send_message_id varchar(255) NULL DEFAULT NULL, + send_exception varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_log + ADD CONSTRAINT pk_system_mail_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_log.id IS '编号'; +COMMENT ON COLUMN system_mail_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_mail_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_mail_log.to_mail IS '接收邮箱地址'; +COMMENT ON COLUMN system_mail_log.account_id IS '邮箱账号编号'; +COMMENT ON COLUMN system_mail_log.from_mail IS '发送邮箱地址'; +COMMENT ON COLUMN system_mail_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_mail_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_mail_log.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_mail_log.template_title IS '邮件标题'; +COMMENT ON COLUMN system_mail_log.template_content IS '邮件内容'; +COMMENT ON COLUMN system_mail_log.template_params IS '邮件参数'; +COMMENT ON COLUMN system_mail_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_mail_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_mail_log.send_message_id IS '发送返回的消息 ID'; +COMMENT ON COLUMN system_mail_log.send_exception IS '发送异常'; +COMMENT ON COLUMN system_mail_log.creator IS '创建者'; +COMMENT ON COLUMN system_mail_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_log.updater IS '更新者'; +COMMENT ON COLUMN system_mail_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_log.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_log IS '邮件日志表'; + +DROP SEQUENCE IF EXISTS system_mail_log_seq; +CREATE SEQUENCE system_mail_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_template; +CREATE TABLE system_mail_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(63) NOT NULL, + account_id int8 NOT NULL, + nickname varchar(255) NULL DEFAULT NULL, + title varchar(255) NOT NULL, + content varchar(10240) NOT NULL, + params varchar(255) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_mail_template + ADD CONSTRAINT pk_system_mail_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_mail_template.id IS '编号'; +COMMENT ON COLUMN system_mail_template.name IS '模板名称'; +COMMENT ON COLUMN system_mail_template.code IS '模板编码'; +COMMENT ON COLUMN system_mail_template.account_id IS '发送的邮箱账号编号'; +COMMENT ON COLUMN system_mail_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_mail_template.title IS '模板标题'; +COMMENT ON COLUMN system_mail_template.content IS '模板内容'; +COMMENT ON COLUMN system_mail_template.params IS '参数数组'; +COMMENT ON COLUMN system_mail_template.status IS '开启状态'; +COMMENT ON COLUMN system_mail_template.remark IS '备注'; +COMMENT ON COLUMN system_mail_template.creator IS '创建者'; +COMMENT ON COLUMN system_mail_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_mail_template.updater IS '更新者'; +COMMENT ON COLUMN system_mail_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_mail_template.deleted IS '是否删除'; +COMMENT ON TABLE system_mail_template IS '邮件模版表'; + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '

您的验证码是{code},名字是{name}

', '["code","name"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', '["key01","key02"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', '0'); +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '

45

', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_mail_template_seq; +CREATE SEQUENCE system_mail_template_seq + START 16; + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_menu; +CREATE TABLE system_menu +( + id int8 NOT NULL, + name varchar(50) NOT NULL, + permission varchar(100) NOT NULL DEFAULT '', + type int2 NOT NULL, + sort int4 NOT NULL DEFAULT 0, + parent_id int8 NOT NULL DEFAULT 0, + path varchar(200) NULL DEFAULT '', + icon varchar(100) NULL DEFAULT '#', + component varchar(255) NULL DEFAULT NULL, + component_name varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + visible bool NOT NULL DEFAULT '1', + keep_alive bool NOT NULL DEFAULT '1', + always_show bool NOT NULL DEFAULT '1', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_menu + ADD CONSTRAINT pk_system_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_menu.id IS '菜单ID'; +COMMENT ON COLUMN system_menu.name IS '菜单名称'; +COMMENT ON COLUMN system_menu.permission IS '权限标识'; +COMMENT ON COLUMN system_menu.type IS '菜单类型'; +COMMENT ON COLUMN system_menu.sort IS '显示顺序'; +COMMENT ON COLUMN system_menu.parent_id IS '父菜单ID'; +COMMENT ON COLUMN system_menu.path IS '路由地址'; +COMMENT ON COLUMN system_menu.icon IS '菜单图标'; +COMMENT ON COLUMN system_menu.component IS '组件路径'; +COMMENT ON COLUMN system_menu.component_name IS '组件名'; +COMMENT ON COLUMN system_menu.status IS '菜单状态'; +COMMENT ON COLUMN system_menu.visible IS '是否可见'; +COMMENT ON COLUMN system_menu.keep_alive IS '是否缓存'; +COMMENT ON COLUMN system_menu.always_show IS '是否总是显示'; +COMMENT ON COLUMN system_menu.creator IS '创建者'; +COMMENT ON COLUMN system_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_menu.updater IS '更新者'; +COMMENT ON COLUMN system_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_menu.deleted IS '是否删除'; +COMMENT ON TABLE system_menu IS '菜单权限表'; + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, '系统管理', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:04:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, '基础设施', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA 示例', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, '用户管理', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:02:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, '角色管理', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '菜单管理', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '重置密码', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '菜单查询', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '菜单新增', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '菜单修改', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '菜单删除', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, '岗位查询', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, '岗位新增', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, '岗位修改', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, '岗位删除', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, '岗位导出', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, '操作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '日志导出', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, '令牌列表', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, '令牌删除', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '任务新增', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '任务修改', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, '任务删除', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '状态修改', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '任务导出', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '生成修改', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, '生成删除', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '导入代码', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, '预览代码', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, '生成代码', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, '设置角色菜单权限', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, '设置角色数据权限', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '请假申请创建', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, '应用信息', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '支付应用信息查询', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '支付应用信息创建', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '支付应用信息更新', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '支付应用信息删除', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, '秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '支付商户信息查询', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '支付商户信息创建', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '支付商户信息更新', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '支付商户信息删除', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '支付商户信息导出', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '租户列表', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '租户查询', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '租户创建', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '租户更新', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '租户删除', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '租户导出', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, '秘钥解析', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '退款订单', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '退款订单查询', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, '退款订单创建', 'pay:refund:create', 3, 2, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, '退款订单更新', 'pay:refund:update', 3, 3, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, '退款订单删除', 'pay:refund:delete', 3, 4, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '退款订单导出', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '支付订单', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '支付订单查询', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, '支付订单创建', 'pay:order:create', 3, 2, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, '支付订单更新', 'pay:order:update', 3, 3, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, '支付订单删除', 'pay:order:delete', 3, 4, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, '用户组删除', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '流程定义查询', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, '流程任务分配规则查询', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '流程任务分配规则创建', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '流程任务分配规则更新', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, '流程实例的创建', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, '流程实例的取消', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, '流程任务的查询', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, '流程任务的更新', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '租户管理', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '租户套餐', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '租户套餐查询', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '租户套餐创建', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '租户套餐更新', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '租户套餐删除', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, '文件配置', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, '文件配置查询', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, '文件配置创建', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, '数据源配置更新', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, '数据源配置删除', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, '数据源配置导出', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, '应用管理', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, '客户端查询', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, '客户端创建', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, '客户端更新', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, '客户端删除', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '报表管理', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '报表设计器', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'GoView', 0, '1', '1', '1', '1', '2022-07-10 20:26:36', '1', '2024-02-29 12:33:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, '商品中心', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, '商品分类', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, '分类查询', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, '分类创建', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '分类更新', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, '分类删除', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, '商品品牌', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, '品牌查询', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, '品牌创建', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, '品牌更新', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, '品牌删除', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, '商品列表', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', '2022-07-30 14:22:58', '1', '2023-08-21 10:27:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, '商品查询', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, '商品创建', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, '商品更新', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, '商品删除', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, '商品属性', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, '规格查询', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '规格创建', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '规格更新', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, '规格删除', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Banner查询', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner创建', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner更新', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Banner删除', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, '营销中心', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, '优惠劵列表', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, '优惠劵模板查询', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, '优惠劵模板创建', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, '优惠劵模板更新', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, '优惠劵模板删除', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, '领取记录', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, '优惠劵查询', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, '优惠劵删除', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '满减送', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, '满减送活动查询', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, '满减送活动创建', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, '满减送活动更新', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, '满减送活动删除', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, '满减送活动关闭', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, '限时折扣', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, '限时折扣活动查询', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, '限时折扣活动创建', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, '限时折扣活动更新', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, '限时折扣活动删除', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, '限时折扣活动关闭', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, '秒杀商品', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, '秒杀活动查询', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, '秒杀活动创建', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, '秒杀活动更新', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, '秒杀活动删除', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, '秒杀时段', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, '秒杀时段查询', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, '秒杀时段创建', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, '秒杀时段更新', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, '秒杀时段删除', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '订单中心', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, '售后退款', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, '售后查询', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, '秒杀活动关闭', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, '订单列表', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '地区管理', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, '公众号管理', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '账号管理', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '新增账号', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '修改账号', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, '查询账号', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, '删除账号', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, '生成二维码', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, '清空 API 配额', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, '数据统计', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, '标签管理', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, '查询标签', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, '新增标签', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '修改标签', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, '删除标签', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, '同步标签', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '粉丝管理', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, '查询粉丝', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '修改粉丝', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, '同步粉丝', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, '消息管理', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, '图文发表记录', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, '查询发布列表', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, '发布草稿', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, '删除发布记录', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, '图文草稿箱', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '新建草稿', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '修改草稿', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, '查询草稿', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, '删除草稿', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, '素材管理', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, '上传临时素材', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, '上传永久素材', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, '删除素材', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, '上传图文图片', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, '查询素材', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '菜单管理', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', '2023-01-14 17:43:54', '1', '2024-02-29 12:42:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, '自动回复', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, '查询回复', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, '新增回复', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '修改回复', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, '删除回复', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, '查询菜单', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '保存菜单', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, '1', '1', '1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot 开发文档', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:46:28', '1', '2023-12-02 21:32:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud 开发文档', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, '接入示例', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, '商品导出', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '配送管理', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, '快递发货', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, '门店自提', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, '快递公司', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', '2023-05-18 09:27:21', '1', '2023-08-30 21:02:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, '快递公司查询', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, '快递公司创建', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, '快递公司更新', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, '快递公司删除', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, '快递公司导出', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '运费模版', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '快递运费模板查询', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '快递运费模板创建', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '快递运费模板更新', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '快递运费模板删除', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '快递运费模板导出', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, '门店管理', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, '自提门店查询', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, '自提门店创建', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, '自提门店更新', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, '自提门店删除', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, '自提门店导出', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, '积分签到规则更新', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, '积分签到规则删除', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, '会员积分', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, '用户积分记录查询', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, '签到记录', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, '用户签到积分查询', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, '用户签到积分删除', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, '会员签到', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, '回调通知', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '支付通知查询', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, '拼团活动', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, '拼团商品', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, '拼团活动查询', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, '拼团活动创建', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, '拼团活动更新', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, '拼团活动删除', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, '拼团活动关闭', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, '砍价活动', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, '砍价商品', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, '砍价活动查询', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, '砍价活动创建', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, '砍价活动更新', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, '砍价活动删除', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, '砍价活动关闭', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, '会员管理', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, '会员用户查询', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, '会员用户更新', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, '会员标签', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, '会员标签查询', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, '会员标签创建', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, '会员标签更新', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, '会员标签删除', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, '会员等级', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, '会员等级查询', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, '会员等级创建', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, '会员等级更新', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, '会员等级删除', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, '会员分组', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, '用户分组查询', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, '用户分组创建', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, '用户分组更新', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, '用户分组删除', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, '用户等级修改', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, '商品评论', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '评论查询', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '添加自评', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '商家回复', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '显隐评论', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, '优惠劵发送', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '交易配置', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, '交易中心配置查询', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, '交易中心配置保存', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '分销管理', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, '分销用户', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, '分销用户查询', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, '分销用户推广人查询', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, '分销用户推广订单查询', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, '分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, '分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, '分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, '佣金记录', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, '佣金记录查询', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, '佣金提现', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, '佣金提现查询', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, '佣金提现审核', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, '统计中心', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, '交易统计', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, '交易统计查询', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '助力记录查询', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, '分类创建', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '分类更新', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, '分类删除', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, '文章列表', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '文章管理查询', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '文章管理创建', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '文章管理更新', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '文章管理删除', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, '内容管理', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '商城首页', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '核销订单', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, '优惠活动', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, '客户管理', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, '客户查询', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, '客户创建', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, '客户更新', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, '客户删除', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, '客户导出', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM 系统', '', 1, 200, 0, '/crm', 'ep:avatar', '', '', 0, '1', '1', '1', '1', '2023-10-29 17:08:30', '1', '2024-02-04 15:37:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, '合同管理', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, '合同查询', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, '合同创建', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, '合同更新', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, '合同删除', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, '合同导出', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '线索管理', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, '线索查询', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '线索创建', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '线索更新', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, '线索删除', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '线索导出', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '商机管理', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '商机查询', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '商机创建', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '商机更新', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '商机删除', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '商机导出', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, '联系人管理', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, '联系人查询', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, '联系人创建', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, '联系人更新', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, '联系人删除', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, '联系人导出', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, '回款管理', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, '回款管理查询', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, '回款管理创建', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, '回款管理更新', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, '回款管理删除', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, '回款管理导出', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, '回款计划', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, '回款计划查询', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, '回款计划创建', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, '回款计划更新', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, '回款计划删除', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, '回款计划导出', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '商城装修', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, '装修模板', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, '装修模板查询', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, '装修模板创建', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, '装修模板更新', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, '装修模板删除', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, '装修模板使用', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, '装修页面', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, '装修页面查询', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, '装修页面创建', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, '装修页面更新', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, '装修页面删除', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '三方登录', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, '三方应用', '', 2, 1, 2447, 'client', 'ep:set-up', 'views/system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', '2023-11-04 12:17:19', '1', '2023-11-04 12:17:19', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, '三方应用查询', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, '三方应用创建', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, '客户公海配置', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, '客户公海配置保存', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, '客户限制配置', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, '客户限制配置查询', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, '客户限制配置创建', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, '客户限制配置更新', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, '产品更新', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, '产品删除', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, '产品导出', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, '产品分类配置', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, '产品分类查询', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, '产品分类创建', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, '产品分类更新', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, '产品分类删除', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '关联商机', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, '取关商机', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, '商品统计', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, '客户公海', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, '订单查询', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '订单更新', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '支付&退款案例', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, '转账案例', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/transfer/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:51:16', '1', '2024-01-18 23:51:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, '钱包管理', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, '充值套餐', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, '钱包余额', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, '产品信息', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, '产品查询', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, '产品创建', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, '产品更新', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, '产品删除', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, '产品导出', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, '产品分类', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, '分类查询', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, '分类创建', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '分类更新', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, '分类删除', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, '分类导出', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, '产品单位', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, '单位查询', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, '单位创建', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, '单位更新', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, '单位删除', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, '单位导出', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '库存管理', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, '仓库信息', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, '仓库查询', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, '仓库创建', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, '仓库更新', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, '仓库删除', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, '仓库导出', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, '产品库存', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, '库存查询', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '库存导出', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, '出入库明细', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, '库存明细查询', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, '库存明细导出', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '其它入库', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, '其它入库单查询', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, '其它入库单创建', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, '其它入库单更新', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, '其它入库单删除', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, '其它入库单导出', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, '采购管理', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, '供应商信息', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, '供应商查询', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, '供应商创建', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, '供应商更新', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, '供应商删除', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, '供应商导出', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, '其它入库单审批', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '其它出库', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, '其它出库单查询', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, '其它出库单创建', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, '其它出库单更新', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, '其它出库单删除', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, '其它出库单导出', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, '其它出库单审批', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '销售管理', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, '客户信息', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, '客户查询', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, '客户创建', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, '客户更新', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, '客户删除', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, '客户导出', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '库存调拨', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, '库存调度单查询', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, '库存调度单创建', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, '库存调度单更新', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, '库存调度单删除', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, '库存调度单导出', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, '库存调度单审批', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '库存盘点', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '库存盘点单查询', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '库存盘点单创建', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '库存盘点单更新', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '库存盘点单删除', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '库存盘点单导出', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '库存盘点单审批', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '销售订单', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '销售订单查询', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '销售订单创建', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '销售订单更新', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '销售订单删除', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '销售订单导出', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '销售订单审批', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '财务管理', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '结算账户', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '结算账户查询', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '结算账户创建', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '结算账户更新', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '结算账户删除', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '结算账户导出', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '销售出库', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '销售出库查询', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '销售出库创建', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '销售出库更新', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '销售出库删除', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '销售出库导出', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '销售出库审批', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '销售退货', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '销售退货查询', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '销售退货创建', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '销售退货更新', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '销售退货删除', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '销售退货导出', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '销售退货审批', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, '采购订单', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, '采购订单查询', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, '采购订单创建', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, '采购订单更新', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, '采购订单删除', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, '采购订单导出', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, '采购订单审批', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, '采购入库', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, '采购入库查询', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, '采购入库创建', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, '采购入库更新', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, '采购入库删除', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, '采购入库导出', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, '采购入库审批', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, '采购退货', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, '采购退货查询', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, '采购退货创建', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, '采购退货更新', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, '采购退货删除', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, '采购退货导出', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, '采购退货审批', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '付款单', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, '付款单查询', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '付款单创建', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '付款单更新', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, '付款单删除', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '付款单导出', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '付款单审批', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, '收款单', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, '收款单查询', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, '收款单创建', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, '收款单更新', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, '收款单删除', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, '收款单导出', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, '收款单审批', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '待办事项', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP 首页', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '商机状态配置', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '商机状态查询', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '商机状态创建', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '商机状态更新', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '商机状态删除', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, '合同配置', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0'); +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_menu_seq; +CREATE SEQUENCE system_menu_seq + START 2758; + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +DROP TABLE IF EXISTS system_notice; +CREATE TABLE system_notice +( + id int8 NOT NULL, + title varchar(50) NOT NULL, + content text NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notice + ADD CONSTRAINT pk_system_notice PRIMARY KEY (id); + +COMMENT ON COLUMN system_notice.id IS '公告ID'; +COMMENT ON COLUMN system_notice.title IS '公告标题'; +COMMENT ON COLUMN system_notice.content IS '公告内容'; +COMMENT ON COLUMN system_notice.type IS '公告类型(1通知 2公告)'; +COMMENT ON COLUMN system_notice.status IS '公告状态(0正常 1关闭)'; +COMMENT ON COLUMN system_notice.creator IS '创建者'; +COMMENT ON COLUMN system_notice.create_time IS '创建时间'; +COMMENT ON COLUMN system_notice.updater IS '更新者'; +COMMENT ON COLUMN system_notice.update_time IS '更新时间'; +COMMENT ON COLUMN system_notice.deleted IS '是否删除'; +COMMENT ON COLUMN system_notice.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notice IS '通知公告表'; + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '芋道的公众', '

新版本内容133

', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '

11112222

', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', '0', 1); +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '我是测试标题', '

哈哈哈哈123

', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', '0', 121); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notice_seq; +CREATE SEQUENCE system_notice_seq + START 5; + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_message; +CREATE TABLE system_notify_message +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + template_id int8 NOT NULL, + template_code varchar(64) NOT NULL, + template_nickname varchar(63) NOT NULL, + template_content varchar(1024) NOT NULL, + template_type int4 NOT NULL, + template_params varchar(255) NOT NULL, + read_status bool NOT NULL, + read_time timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_message + ADD CONSTRAINT pk_system_notify_message PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_message.id IS '用户ID'; +COMMENT ON COLUMN system_notify_message.user_id IS '用户id'; +COMMENT ON COLUMN system_notify_message.user_type IS '用户类型'; +COMMENT ON COLUMN system_notify_message.template_id IS '模版编号'; +COMMENT ON COLUMN system_notify_message.template_code IS '模板编码'; +COMMENT ON COLUMN system_notify_message.template_nickname IS '模版发送人名称'; +COMMENT ON COLUMN system_notify_message.template_content IS '模版内容'; +COMMENT ON COLUMN system_notify_message.template_type IS '模版类型'; +COMMENT ON COLUMN system_notify_message.template_params IS '模版参数'; +COMMENT ON COLUMN system_notify_message.read_status IS '是否已读'; +COMMENT ON COLUMN system_notify_message.read_time IS '阅读时间'; +COMMENT ON COLUMN system_notify_message.creator IS '创建者'; +COMMENT ON COLUMN system_notify_message.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_message.updater IS '更新者'; +COMMENT ON COLUMN system_notify_message.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_message.deleted IS '是否删除'; +COMMENT ON COLUMN system_notify_message.tenant_id IS '租户编号'; +COMMENT ON TABLE system_notify_message IS '站内信消息表'; + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:44:08', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', '我是 1,我开始 2 了', 1, '{"name":"1","what":"2"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 11:45:04', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', '系统消息', '你好,欢迎 哈哈 加入大家庭!', 2, '{"name":"哈哈"}', '0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-02-10 00:47:04', '1', '2023-01-28 22:21:42', '1', '2023-02-10 00:47:04', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', '我是 芋艿,我开始 写代码 了', 1, '{"name":"芋艿","what":"写代码"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 22:22:07', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', '我是 2,我开始 3 了', 1, '{"name":"2","what":"3"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:45:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', '系统消息', '你好,欢迎 123 加入大家庭!', 2, '{"name":"123"}', '1', '2023-01-29 10:52:06', '1', '2023-01-28 23:50:21', '1', '2023-01-29 10:52:06', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', '0', 1); +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_notify_message_seq; +CREATE SEQUENCE system_notify_message_seq + START 11; + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_template; +CREATE TABLE system_notify_template +( + id int8 NOT NULL, + name varchar(63) NOT NULL, + code varchar(64) NOT NULL, + nickname varchar(255) NOT NULL, + content varchar(1024) NOT NULL, + type int2 NOT NULL, + params varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_notify_template + ADD CONSTRAINT pk_system_notify_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_notify_template.id IS '主键'; +COMMENT ON COLUMN system_notify_template.name IS '模板名称'; +COMMENT ON COLUMN system_notify_template.code IS '模版编码'; +COMMENT ON COLUMN system_notify_template.nickname IS '发送人名称'; +COMMENT ON COLUMN system_notify_template.content IS '模版内容'; +COMMENT ON COLUMN system_notify_template.type IS '类型'; +COMMENT ON COLUMN system_notify_template.params IS '参数数组'; +COMMENT ON COLUMN system_notify_template.status IS '状态'; +COMMENT ON COLUMN system_notify_template.remark IS '备注'; +COMMENT ON COLUMN system_notify_template.creator IS '创建者'; +COMMENT ON COLUMN system_notify_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_notify_template.updater IS '更新者'; +COMMENT ON COLUMN system_notify_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_notify_template.deleted IS '是否删除'; +COMMENT ON TABLE system_notify_template IS '站内信模板表'; + +DROP SEQUENCE IF EXISTS system_notify_template_seq; +CREATE SEQUENCE system_notify_template_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_access_token; +CREATE TABLE system_oauth2_access_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + user_info varchar(512) NOT NULL, + access_token varchar(255) NOT NULL, + refresh_token varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_access_token + ADD CONSTRAINT pk_system_oauth2_access_token PRIMARY KEY (id); + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token); +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token); + +COMMENT ON COLUMN system_oauth2_access_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_access_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_access_token.user_info IS '用户信息'; +COMMENT ON COLUMN system_oauth2_access_token.access_token IS '访问令牌'; +COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_access_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_access_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_access_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_access_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_access_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_access_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_access_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_access_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 访问令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq; +CREATE SEQUENCE system_oauth2_access_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_approve; +CREATE TABLE system_oauth2_approve +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scope varchar(255) NOT NULL DEFAULT '', + approved bool NOT NULL DEFAULT '0', + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_approve + ADD CONSTRAINT pk_system_oauth2_approve PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_approve.id IS '编号'; +COMMENT ON COLUMN system_oauth2_approve.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_approve.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_approve.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_approve.scope IS '授权范围'; +COMMENT ON COLUMN system_oauth2_approve.approved IS '是否接受'; +COMMENT ON COLUMN system_oauth2_approve.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_approve.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_approve.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_approve.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_approve.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_approve.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 批准表'; + +DROP SEQUENCE IF EXISTS system_oauth2_approve_seq; +CREATE SEQUENCE system_oauth2_approve_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_client; +CREATE TABLE system_oauth2_client +( + id int8 NOT NULL, + client_id varchar(255) NOT NULL, + secret varchar(255) NOT NULL, + name varchar(255) NOT NULL, + logo varchar(255) NOT NULL, + description varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + access_token_validity_seconds int4 NOT NULL, + refresh_token_validity_seconds int4 NOT NULL, + redirect_uris varchar(255) NOT NULL, + authorized_grant_types varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + auto_approve_scopes varchar(255) NULL DEFAULT NULL, + authorities varchar(255) NULL DEFAULT NULL, + resource_ids varchar(255) NULL DEFAULT NULL, + additional_information varchar(4096) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_client + ADD CONSTRAINT pk_system_oauth2_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_client.id IS '编号'; +COMMENT ON COLUMN system_oauth2_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_client.secret IS '客户端密钥'; +COMMENT ON COLUMN system_oauth2_client.name IS '应用名'; +COMMENT ON COLUMN system_oauth2_client.logo IS '应用图标'; +COMMENT ON COLUMN system_oauth2_client.description IS '应用描述'; +COMMENT ON COLUMN system_oauth2_client.status IS '状态'; +COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS '访问令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS '刷新令牌的有效期'; +COMMENT ON COLUMN system_oauth2_client.redirect_uris IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS '授权类型'; +COMMENT ON COLUMN system_oauth2_client.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS '自动通过的授权范围'; +COMMENT ON COLUMN system_oauth2_client.authorities IS '权限'; +COMMENT ON COLUMN system_oauth2_client.resource_ids IS '资源'; +COMMENT ON COLUMN system_oauth2_client.additional_information IS '附加信息'; +COMMENT ON COLUMN system_oauth2_client.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_client.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_client.deleted IS '是否删除'; +COMMENT ON TABLE system_oauth2_client IS 'OAuth2 客户端表'; + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', '我是描述', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2024-02-22 16:31:52', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', '啦啦啦啦', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2023-12-02 21:01:01', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2022-09-29 13:28:31', '0'); +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2022-10-04 20:31:21', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_oauth2_client_seq; +CREATE SEQUENCE system_oauth2_client_seq + START 43; + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_code; +CREATE TABLE system_oauth2_code +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + code varchar(32) NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT '', + expires_time timestamp NOT NULL, + redirect_uri varchar(255) NULL DEFAULT NULL, + state varchar(255) NOT NULL DEFAULT '', + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_code + ADD CONSTRAINT pk_system_oauth2_code PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_code.id IS '编号'; +COMMENT ON COLUMN system_oauth2_code.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_code.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_code.code IS '授权码'; +COMMENT ON COLUMN system_oauth2_code.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_code.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_code.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_code.redirect_uri IS '可重定向的 URI 地址'; +COMMENT ON COLUMN system_oauth2_code.state IS '状态'; +COMMENT ON COLUMN system_oauth2_code.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_code.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_code IS 'OAuth2 授权码表'; + +DROP SEQUENCE IF EXISTS system_oauth2_code_seq; +CREATE SEQUENCE system_oauth2_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_refresh_token; +CREATE TABLE system_oauth2_refresh_token +( + id int8 NOT NULL, + user_id int8 NOT NULL, + refresh_token varchar(32) NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + scopes varchar(255) NULL DEFAULT NULL, + expires_time timestamp NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_oauth2_refresh_token + ADD CONSTRAINT pk_system_oauth2_refresh_token PRIMARY KEY (id); + +COMMENT ON COLUMN system_oauth2_refresh_token.id IS '编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS '用户编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS '刷新令牌'; +COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS '用户类型'; +COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS '客户端编号'; +COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS '授权范围'; +COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS '过期时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.creator IS '创建者'; +COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS '创建时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.updater IS '更新者'; +COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS '更新时间'; +COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '是否删除'; +COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '租户编号'; +COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; + +DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq; +CREATE SEQUENCE system_oauth2_refresh_token_seq + START 1; + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +DROP TABLE IF EXISTS system_operate_log; +CREATE TABLE system_operate_log +( + id int8 NOT NULL, + trace_id varchar(64) NOT NULL DEFAULT '', + user_id int8 NOT NULL, + user_type int2 NOT NULL DEFAULT 0, + type varchar(50) NOT NULL, + sub_type varchar(50) NOT NULL, + biz_id int8 NOT NULL, + action varchar(2000) NOT NULL DEFAULT '', + extra varchar(2000) NOT NULL DEFAULT '', + request_method varchar(16) NULL DEFAULT '', + request_url varchar(255) NULL DEFAULT '', + user_ip varchar(50) NULL DEFAULT NULL, + user_agent varchar(200) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_operate_log + ADD CONSTRAINT pk_system_operate_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_operate_log.id IS '日志主键'; +COMMENT ON COLUMN system_operate_log.trace_id IS '链路追踪编号'; +COMMENT ON COLUMN system_operate_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_operate_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_operate_log.type IS '操作模块类型'; +COMMENT ON COLUMN system_operate_log.sub_type IS '操作名'; +COMMENT ON COLUMN system_operate_log.biz_id IS '操作数据模块编号'; +COMMENT ON COLUMN system_operate_log.action IS '操作内容'; +COMMENT ON COLUMN system_operate_log.extra IS '拓展字段'; +COMMENT ON COLUMN system_operate_log.request_method IS '请求方法名'; +COMMENT ON COLUMN system_operate_log.request_url IS '请求地址'; +COMMENT ON COLUMN system_operate_log.user_ip IS '用户 IP'; +COMMENT ON COLUMN system_operate_log.user_agent IS '浏览器 UA'; +COMMENT ON COLUMN system_operate_log.creator IS '创建者'; +COMMENT ON COLUMN system_operate_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_operate_log.updater IS '更新者'; +COMMENT ON COLUMN system_operate_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_operate_log.deleted IS '是否删除'; +COMMENT ON COLUMN system_operate_log.tenant_id IS '租户编号'; +COMMENT ON TABLE system_operate_log IS '操作日志记录 V2 版本'; + +DROP SEQUENCE IF EXISTS system_operate_log_seq; +CREATE SEQUENCE system_operate_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +DROP TABLE IF EXISTS system_post; +CREATE TABLE system_post +( + id int8 NOT NULL, + code varchar(64) NOT NULL, + name varchar(50) NOT NULL, + sort int4 NOT NULL, + status int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_post + ADD CONSTRAINT pk_system_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_post.id IS '岗位ID'; +COMMENT ON COLUMN system_post.code IS '岗位编码'; +COMMENT ON COLUMN system_post.name IS '岗位名称'; +COMMENT ON COLUMN system_post.sort IS '显示顺序'; +COMMENT ON COLUMN system_post.status IS '状态(0正常 1停用)'; +COMMENT ON COLUMN system_post.remark IS '备注'; +COMMENT ON COLUMN system_post.creator IS '创建者'; +COMMENT ON COLUMN system_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_post.updater IS '更新者'; +COMMENT ON COLUMN system_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_post IS '岗位信息表'; + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 10:04:37', '0', 1); +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', '人力资源', 5, 0, '', '1', '2024-03-24 20:45:40', '1', '2024-03-24 20:45:40', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_post_seq; +CREATE SEQUENCE system_post_seq + START 6; + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +DROP TABLE IF EXISTS system_role; +CREATE TABLE system_role +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + code varchar(100) NOT NULL, + sort int4 NOT NULL, + data_scope int2 NOT NULL DEFAULT 1, + data_scope_dept_ids varchar(500) NOT NULL DEFAULT '', + status int2 NOT NULL, + type int2 NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role + ADD CONSTRAINT pk_system_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_role.id IS '角色ID'; +COMMENT ON COLUMN system_role.name IS '角色名称'; +COMMENT ON COLUMN system_role.code IS '角色权限字符串'; +COMMENT ON COLUMN system_role.sort IS '显示顺序'; +COMMENT ON COLUMN system_role.data_scope IS '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +COMMENT ON COLUMN system_role.data_scope_dept_ids IS '数据范围(指定部门数组)'; +COMMENT ON COLUMN system_role.status IS '角色状态(0正常 1停用)'; +COMMENT ON COLUMN system_role.type IS '角色类型'; +COMMENT ON COLUMN system_role.remark IS '备注'; +COMMENT ON COLUMN system_role.creator IS '创建者'; +COMMENT ON COLUMN system_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_role.updater IS '更新者'; +COMMENT ON COLUMN system_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role IS '角色信息表'; + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '我想测试', '', '2021-01-06 13:49:35', '1', '2024-03-24 22:22:45', '0', 1); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_seq; +CREATE SEQUENCE system_role_seq + START 112; + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_role_menu; +CREATE TABLE system_role_menu +( + id int8 NOT NULL, + role_id int8 NOT NULL, + menu_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_role_menu + ADD CONSTRAINT pk_system_role_menu PRIMARY KEY (id); + +COMMENT ON COLUMN system_role_menu.id IS '自增编号'; +COMMENT ON COLUMN system_role_menu.role_id IS '角色ID'; +COMMENT ON COLUMN system_role_menu.menu_id IS '菜单ID'; +COMMENT ON COLUMN system_role_menu.creator IS '创建者'; +COMMENT ON COLUMN system_role_menu.create_time IS '创建时间'; +COMMENT ON COLUMN system_role_menu.updater IS '更新者'; +COMMENT ON COLUMN system_role_menu.update_time IS '更新时间'; +COMMENT ON COLUMN system_role_menu.deleted IS '是否删除'; +COMMENT ON COLUMN system_role_menu.tenant_id IS '租户编号'; +COMMENT ON TABLE system_role_menu IS '角色和菜单关联表'; + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_role_menu_seq; +CREATE SEQUENCE system_role_menu_seq + START 5779; + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_channel; +CREATE TABLE system_sms_channel +( + id int8 NOT NULL, + signature varchar(12) NOT NULL, + code varchar(63) NOT NULL, + status int2 NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_key varchar(128) NOT NULL, + api_secret varchar(128) NULL DEFAULT NULL, + callback_url varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_channel + ADD CONSTRAINT pk_system_sms_channel PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_channel.id IS '编号'; +COMMENT ON COLUMN system_sms_channel.signature IS '短信签名'; +COMMENT ON COLUMN system_sms_channel.code IS '渠道编码'; +COMMENT ON COLUMN system_sms_channel.status IS '开启状态'; +COMMENT ON COLUMN system_sms_channel.remark IS '备注'; +COMMENT ON COLUMN system_sms_channel.api_key IS '短信 API 的账号'; +COMMENT ON COLUMN system_sms_channel.api_secret IS '短信 API 的秘钥'; +COMMENT ON COLUMN system_sms_channel.callback_url IS '短信发送回调 URL'; +COMMENT ON COLUMN system_sms_channel.creator IS '创建者'; +COMMENT ON COLUMN system_sms_channel.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_channel.updater IS '更新者'; +COMMENT ON COLUMN system_sms_channel.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_channel.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_channel IS '短信渠道'; + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2023-12-02 22:10:17', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', '0'); +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, '测试演示', 'DEBUG_DING_TALK', 0, '仅测试', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2022-04-10 23:07:59', '1', '2023-12-02 22:10:08', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_channel_seq; +CREATE SEQUENCE system_sms_channel_seq + START 7; + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_code; +CREATE TABLE system_sms_code +( + id int8 NOT NULL, + mobile varchar(11) NOT NULL, + code varchar(6) NOT NULL, + create_ip varchar(15) NOT NULL, + scene int2 NOT NULL, + today_index int2 NOT NULL, + used int2 NOT NULL, + used_time timestamp NULL DEFAULT NULL, + used_ip varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_code + ADD CONSTRAINT pk_system_sms_code PRIMARY KEY (id); + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile); + +COMMENT ON COLUMN system_sms_code.id IS '编号'; +COMMENT ON COLUMN system_sms_code.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_code.code IS '验证码'; +COMMENT ON COLUMN system_sms_code.create_ip IS '创建 IP'; +COMMENT ON COLUMN system_sms_code.scene IS '发送场景'; +COMMENT ON COLUMN system_sms_code.today_index IS '今日发送的第几条'; +COMMENT ON COLUMN system_sms_code.used IS '是否使用'; +COMMENT ON COLUMN system_sms_code.used_time IS '使用时间'; +COMMENT ON COLUMN system_sms_code.used_ip IS '使用 IP'; +COMMENT ON COLUMN system_sms_code.creator IS '创建者'; +COMMENT ON COLUMN system_sms_code.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_code.updater IS '更新者'; +COMMENT ON COLUMN system_sms_code.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_code.deleted IS '是否删除'; +COMMENT ON COLUMN system_sms_code.tenant_id IS '租户编号'; +COMMENT ON TABLE system_sms_code IS '手机验证码'; + +DROP SEQUENCE IF EXISTS system_sms_code_seq; +CREATE SEQUENCE system_sms_code_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_log; +CREATE TABLE system_sms_log +( + id int8 NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + template_id int8 NOT NULL, + template_code varchar(63) NOT NULL, + template_type int2 NOT NULL, + template_content varchar(255) NOT NULL, + template_params varchar(255) NOT NULL, + api_template_id varchar(63) NOT NULL, + mobile varchar(11) NOT NULL, + user_id int8 NULL DEFAULT NULL, + user_type int2 NULL DEFAULT NULL, + send_status int2 NOT NULL DEFAULT 0, + send_time timestamp NULL DEFAULT NULL, + api_send_code varchar(63) NULL DEFAULT NULL, + api_send_msg varchar(255) NULL DEFAULT NULL, + api_request_id varchar(255) NULL DEFAULT NULL, + api_serial_no varchar(255) NULL DEFAULT NULL, + receive_status int2 NOT NULL DEFAULT 0, + receive_time timestamp NULL DEFAULT NULL, + api_receive_code varchar(63) NULL DEFAULT NULL, + api_receive_msg varchar(255) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_log + ADD CONSTRAINT pk_system_sms_log PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_log.id IS '编号'; +COMMENT ON COLUMN system_sms_log.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_log.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_log.template_id IS '模板编号'; +COMMENT ON COLUMN system_sms_log.template_code IS '模板编码'; +COMMENT ON COLUMN system_sms_log.template_type IS '短信类型'; +COMMENT ON COLUMN system_sms_log.template_content IS '短信内容'; +COMMENT ON COLUMN system_sms_log.template_params IS '短信参数'; +COMMENT ON COLUMN system_sms_log.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_log.mobile IS '手机号'; +COMMENT ON COLUMN system_sms_log.user_id IS '用户编号'; +COMMENT ON COLUMN system_sms_log.user_type IS '用户类型'; +COMMENT ON COLUMN system_sms_log.send_status IS '发送状态'; +COMMENT ON COLUMN system_sms_log.send_time IS '发送时间'; +COMMENT ON COLUMN system_sms_log.api_send_code IS '短信 API 发送结果的编码'; +COMMENT ON COLUMN system_sms_log.api_send_msg IS '短信 API 发送失败的提示'; +COMMENT ON COLUMN system_sms_log.api_request_id IS '短信 API 发送返回的唯一请求 ID'; +COMMENT ON COLUMN system_sms_log.api_serial_no IS '短信 API 发送返回的序号'; +COMMENT ON COLUMN system_sms_log.receive_status IS '接收状态'; +COMMENT ON COLUMN system_sms_log.receive_time IS '接收时间'; +COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API 接收结果的编码'; +COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API 接收结果的说明'; +COMMENT ON COLUMN system_sms_log.creator IS '创建者'; +COMMENT ON COLUMN system_sms_log.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_log.updater IS '更新者'; +COMMENT ON COLUMN system_sms_log.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_log.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_log IS '短信日志'; + +DROP SEQUENCE IF EXISTS system_sms_log_seq; +CREATE SEQUENCE system_sms_log_seq + START 1; + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_template; +CREATE TABLE system_sms_template +( + id int8 NOT NULL, + type int2 NOT NULL, + status int2 NOT NULL, + code varchar(63) NOT NULL, + name varchar(63) NOT NULL, + content varchar(255) NOT NULL, + params varchar(255) NOT NULL, + remark varchar(255) NULL DEFAULT NULL, + api_template_id varchar(63) NOT NULL, + channel_id int8 NOT NULL, + channel_code varchar(63) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_sms_template + ADD CONSTRAINT pk_system_sms_template PRIMARY KEY (id); + +COMMENT ON COLUMN system_sms_template.id IS '编号'; +COMMENT ON COLUMN system_sms_template.type IS '模板类型'; +COMMENT ON COLUMN system_sms_template.status IS '开启状态'; +COMMENT ON COLUMN system_sms_template.code IS '模板编码'; +COMMENT ON COLUMN system_sms_template.name IS '模板名称'; +COMMENT ON COLUMN system_sms_template.content IS '模板内容'; +COMMENT ON COLUMN system_sms_template.params IS '参数数组'; +COMMENT ON COLUMN system_sms_template.remark IS '备注'; +COMMENT ON COLUMN system_sms_template.api_template_id IS '短信 API 的模板编号'; +COMMENT ON COLUMN system_sms_template.channel_id IS '短信渠道编号'; +COMMENT ON COLUMN system_sms_template.channel_code IS '短信渠道编码'; +COMMENT ON COLUMN system_sms_template.creator IS '创建者'; +COMMENT ON COLUMN system_sms_template.create_time IS '创建时间'; +COMMENT ON COLUMN system_sms_template.updater IS '更新者'; +COMMENT ON COLUMN system_sms_template.update_time IS '更新时间'; +COMMENT ON COLUMN system_sms_template.deleted IS '是否删除'; +COMMENT ON TABLE system_sms_template IS '短信模板'; + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '["operation","code"]', '测试备注', '4383920', 6, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2023-12-02 22:32:47', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '["name"]', 'f哈哈哈', '4383920', 6, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2022-12-10 21:26:09', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '["name","code"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '["code"]', NULL, '4372216', 6, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2022-12-10 21:25:59', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '【工作流】流程被通过', '您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', '演示模板', '我就是测试一下下', '[]', NULL, 'biubiubiu', 6, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2023-03-24 23:45:07', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', '会员用户 - 修改手机', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', '会员用户 - 修改密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', '0'); +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', '会员用户 - 重置密码', '您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_sms_template_seq; +CREATE SEQUENCE system_sms_template_seq + START 17; + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +DROP TABLE IF EXISTS system_social_client; +CREATE TABLE system_social_client +( + id int8 NOT NULL, + name varchar(255) NOT NULL, + social_type int2 NOT NULL, + user_type int2 NOT NULL, + client_id varchar(255) NOT NULL, + client_secret varchar(255) NOT NULL, + agent_id varchar(255) NULL DEFAULT NULL, + status int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_client + ADD CONSTRAINT pk_system_social_client PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_client.id IS '编号'; +COMMENT ON COLUMN system_social_client.name IS '应用名'; +COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; +COMMENT ON COLUMN system_social_client.status IS '状态'; +COMMENT ON COLUMN system_social_client.creator IS '创建者'; +COMMENT ON COLUMN system_social_client.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_client.updater IS '更新者'; +COMMENT ON COLUMN system_social_client.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_client.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_client.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_client IS '社交客户端表'; + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '钉钉', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '钉钉(王土豆)', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', '1', 121); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '微信公众号', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', '1', 1); +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '微信小程序', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', '1', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_social_client_seq; +CREATE SEQUENCE system_social_client_seq + START 44; + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user; +CREATE TABLE system_social_user +( + id int8 NOT NULL, + type int2 NOT NULL, + openid varchar(32) NOT NULL, + token varchar(256) NULL DEFAULT NULL, + raw_token_info varchar(1024) NOT NULL, + nickname varchar(32) NOT NULL, + avatar varchar(255) NULL DEFAULT NULL, + raw_user_info varchar(1024) NOT NULL, + code varchar(256) NOT NULL, + state varchar(256) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user + ADD CONSTRAINT pk_system_social_user PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user.type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user.openid IS '社交 openid'; +COMMENT ON COLUMN system_social_user.token IS '社交 token'; +COMMENT ON COLUMN system_social_user.raw_token_info IS '原始 Token 数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.nickname IS '用户昵称'; +COMMENT ON COLUMN system_social_user.avatar IS '用户头像'; +COMMENT ON COLUMN system_social_user.raw_user_info IS '原始用户数据,一般是 JSON 格式'; +COMMENT ON COLUMN system_social_user.code IS '最后一次的认证 code'; +COMMENT ON COLUMN system_social_user.state IS '最后一次的认证 state'; +COMMENT ON COLUMN system_social_user.creator IS '创建者'; +COMMENT ON COLUMN system_social_user.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user.updater IS '更新者'; +COMMENT ON COLUMN system_social_user.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user IS '社交用户表'; + +DROP SEQUENCE IF EXISTS system_social_user_seq; +CREATE SEQUENCE system_social_user_seq + START 1; + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user_bind; +CREATE TABLE system_social_user_bind +( + id int8 NOT NULL, + user_id int8 NOT NULL, + user_type int2 NOT NULL, + social_type int2 NOT NULL, + social_user_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_social_user_bind + ADD CONSTRAINT pk_system_social_user_bind PRIMARY KEY (id); + +COMMENT ON COLUMN system_social_user_bind.id IS '主键(自增策略)'; +COMMENT ON COLUMN system_social_user_bind.user_id IS '用户编号'; +COMMENT ON COLUMN system_social_user_bind.user_type IS '用户类型'; +COMMENT ON COLUMN system_social_user_bind.social_type IS '社交平台的类型'; +COMMENT ON COLUMN system_social_user_bind.social_user_id IS '社交用户的编号'; +COMMENT ON COLUMN system_social_user_bind.creator IS '创建者'; +COMMENT ON COLUMN system_social_user_bind.create_time IS '创建时间'; +COMMENT ON COLUMN system_social_user_bind.updater IS '更新者'; +COMMENT ON COLUMN system_social_user_bind.update_time IS '更新时间'; +COMMENT ON COLUMN system_social_user_bind.deleted IS '是否删除'; +COMMENT ON COLUMN system_social_user_bind.tenant_id IS '租户编号'; +COMMENT ON TABLE system_social_user_bind IS '社交绑定表'; + +DROP SEQUENCE IF EXISTS system_social_user_bind_seq; +CREATE SEQUENCE system_social_user_bind_seq + START 1; + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant; +CREATE TABLE system_tenant +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + contact_user_id int8 NULL DEFAULT NULL, + contact_name varchar(30) NOT NULL, + contact_mobile varchar(500) NULL DEFAULT NULL, + status int2 NOT NULL DEFAULT 0, + website varchar(256) NULL DEFAULT '', + package_id int8 NOT NULL, + expire_time timestamp NOT NULL, + account_count int4 NOT NULL, + creator varchar(64) NOT NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant + ADD CONSTRAINT pk_system_tenant PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant.id IS '租户编号'; +COMMENT ON COLUMN system_tenant.name IS '租户名'; +COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号'; +COMMENT ON COLUMN system_tenant.contact_name IS '联系人'; +COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机'; +COMMENT ON COLUMN system_tenant.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant.website IS '绑定域名'; +COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号'; +COMMENT ON COLUMN system_tenant.expire_time IS '过期时间'; +COMMENT ON COLUMN system_tenant.account_count IS '账号数量'; +COMMENT ON COLUMN system_tenant.creator IS '创建者'; +COMMENT ON COLUMN system_tenant.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant.updater IS '更新者'; +COMMENT ON COLUMN system_tenant.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant IS '租户表'; + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', '0'); +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_seq; +CREATE SEQUENCE system_tenant_seq + START 123; + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant_package; +CREATE TABLE system_tenant_package +( + id int8 NOT NULL, + name varchar(30) NOT NULL, + status int2 NOT NULL DEFAULT 0, + remark varchar(256) NULL DEFAULT '', + menu_ids varchar(4096) NOT NULL, + creator varchar(64) NOT NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_tenant_package + ADD CONSTRAINT pk_system_tenant_package PRIMARY KEY (id); + +COMMENT ON COLUMN system_tenant_package.id IS '套餐编号'; +COMMENT ON COLUMN system_tenant_package.name IS '套餐名'; +COMMENT ON COLUMN system_tenant_package.status IS '租户状态(0正常 1停用)'; +COMMENT ON COLUMN system_tenant_package.remark IS '备注'; +COMMENT ON COLUMN system_tenant_package.menu_ids IS '关联的菜单编号'; +COMMENT ON COLUMN system_tenant_package.creator IS '创建者'; +COMMENT ON COLUMN system_tenant_package.create_time IS '创建时间'; +COMMENT ON COLUMN system_tenant_package.updater IS '更新者'; +COMMENT ON COLUMN system_tenant_package.update_time IS '更新时间'; +COMMENT ON COLUMN system_tenant_package.deleted IS '是否删除'; +COMMENT ON TABLE system_tenant_package IS '租户套餐表'; + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-03-30 17:53:17', '0'); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_tenant_package_seq; +CREATE SEQUENCE system_tenant_package_seq + START 112; + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +DROP TABLE IF EXISTS system_user_post; +CREATE TABLE system_user_post +( + id int8 NOT NULL, + user_id int8 NOT NULL DEFAULT 0, + post_id int8 NOT NULL DEFAULT 0, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_post + ADD CONSTRAINT pk_system_user_post PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_post.id IS 'id'; +COMMENT ON COLUMN system_user_post.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_post.post_id IS '岗位ID'; +COMMENT ON COLUMN system_user_post.creator IS '创建者'; +COMMENT ON COLUMN system_user_post.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_post.updater IS '更新者'; +COMMENT ON COLUMN system_user_post.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_post.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_post.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_post IS '用户岗位表'; + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_post_seq; +CREATE SEQUENCE system_user_post_seq + START 125; + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +DROP TABLE IF EXISTS system_user_role; +CREATE TABLE system_user_role +( + id int8 NOT NULL, + user_id int8 NOT NULL, + role_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_user_role + ADD CONSTRAINT pk_system_user_role PRIMARY KEY (id); + +COMMENT ON COLUMN system_user_role.id IS '自增编号'; +COMMENT ON COLUMN system_user_role.user_id IS '用户ID'; +COMMENT ON COLUMN system_user_role.role_id IS '角色ID'; +COMMENT ON COLUMN system_user_role.creator IS '创建者'; +COMMENT ON COLUMN system_user_role.create_time IS '创建时间'; +COMMENT ON COLUMN system_user_role.updater IS '更新者'; +COMMENT ON COLUMN system_user_role.update_time IS '更新时间'; +COMMENT ON COLUMN system_user_role.deleted IS '是否删除'; +COMMENT ON COLUMN system_user_role.tenant_id IS '租户编号'; +COMMENT ON TABLE system_user_role IS '用户和角色关联表'; + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', '0', 121); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', '0', 1); +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_user_role_seq; +CREATE SEQUENCE system_user_role_seq + START 39; + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +DROP TABLE IF EXISTS system_users; +CREATE TABLE system_users +( + id int8 NOT NULL, + username varchar(30) NOT NULL, + password varchar(100) NOT NULL DEFAULT '', + nickname varchar(30) NOT NULL, + remark varchar(500) NULL DEFAULT NULL, + dept_id int8 NULL DEFAULT NULL, + post_ids varchar(255) NULL DEFAULT NULL, + email varchar(50) NULL DEFAULT '', + mobile varchar(11) NULL DEFAULT '', + sex int2 NULL DEFAULT 0, + avatar varchar(512) NULL DEFAULT '', + status int2 NOT NULL DEFAULT 0, + login_ip varchar(50) NULL DEFAULT '', + login_date timestamp NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE system_users + ADD CONSTRAINT pk_system_users PRIMARY KEY (id); + +COMMENT ON COLUMN system_users.id IS '用户ID'; +COMMENT ON COLUMN system_users.username IS '用户账号'; +COMMENT ON COLUMN system_users.password IS '密码'; +COMMENT ON COLUMN system_users.nickname IS '用户昵称'; +COMMENT ON COLUMN system_users.remark IS '备注'; +COMMENT ON COLUMN system_users.dept_id IS '部门ID'; +COMMENT ON COLUMN system_users.post_ids IS '岗位编号数组'; +COMMENT ON COLUMN system_users.email IS '用户邮箱'; +COMMENT ON COLUMN system_users.mobile IS '手机号码'; +COMMENT ON COLUMN system_users.sex IS '用户性别'; +COMMENT ON COLUMN system_users.avatar IS '头像地址'; +COMMENT ON COLUMN system_users.status IS '帐号状态(0正常 1停用)'; +COMMENT ON COLUMN system_users.login_ip IS '最后登录IP'; +COMMENT ON COLUMN system_users.login_date IS '最后登录时间'; +COMMENT ON COLUMN system_users.creator IS '创建者'; +COMMENT ON COLUMN system_users.create_time IS '创建时间'; +COMMENT ON COLUMN system_users.updater IS '更新者'; +COMMENT ON COLUMN system_users.update_time IS '更新时间'; +COMMENT ON COLUMN system_users.deleted IS '是否删除'; +COMMENT ON COLUMN system_users.tenant_id IS '租户编号'; +COMMENT ON TABLE system_users IS '用户信息表'; + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-29 21:50:32', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-29 21:50:32', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', '0', 118); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', '0', 119); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', '0', 120); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', '0', 121); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', '0', 122); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', '0', 1); +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS system_users_seq; +CREATE SEQUENCE system_users_seq + START 132; + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo01_contact; +CREATE TABLE yudao_demo01_contact +( + id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + avatar varchar(512) NULL DEFAULT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo01_contact + ADD CONSTRAINT pk_yudao_demo01_contact PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo01_contact.id IS '编号'; +COMMENT ON COLUMN yudao_demo01_contact.name IS '名字'; +COMMENT ON COLUMN yudao_demo01_contact.sex IS '性别'; +COMMENT ON COLUMN yudao_demo01_contact.birthday IS '出生年'; +COMMENT ON COLUMN yudao_demo01_contact.description IS '简介'; +COMMENT ON COLUMN yudao_demo01_contact.avatar IS '头像'; +COMMENT ON COLUMN yudao_demo01_contact.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo01_contact.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo01_contact.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo01_contact.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo01_contact.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo01_contact IS '示例联系人表'; + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 2, '2023-11-07 00:00:00', '

天蚕土豆!呀

', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq; +CREATE SEQUENCE yudao_demo01_contact_seq + START 2; + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo02_category; +CREATE TABLE yudao_demo02_category +( + id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + parent_id int8 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo02_category + ADD CONSTRAINT pk_yudao_demo02_category PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo02_category.id IS '编号'; +COMMENT ON COLUMN yudao_demo02_category.name IS '名字'; +COMMENT ON COLUMN yudao_demo02_category.parent_id IS '父级编号'; +COMMENT ON COLUMN yudao_demo02_category.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo02_category.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo02_category.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo02_category.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo02_category.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo02_category IS '示例分类表'; + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '土豆', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '番茄', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '怪怪', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '小番茄', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大番茄', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', '0', 1); +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo02_category_seq; +CREATE SEQUENCE yudao_demo02_category_seq + START 7; + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_course; +CREATE TABLE yudao_demo03_course +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + score int2 NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_course + ADD CONSTRAINT pk_yudao_demo03_course PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_course.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_course.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_course.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_course.score IS '分数'; +COMMENT ON COLUMN yudao_demo03_course.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_course.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_course.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_course.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_course.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_course IS '学生课程表'; + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', '1', 1); +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_course_seq; +CREATE SEQUENCE yudao_demo03_course_seq + START 14; + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_grade; +CREATE TABLE yudao_demo03_grade +( + id int8 NOT NULL, + student_id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + teacher varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_grade + ADD CONSTRAINT pk_yudao_demo03_grade PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_grade.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_grade.student_id IS '学生编号'; +COMMENT ON COLUMN yudao_demo03_grade.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_grade.teacher IS '班主任'; +COMMENT ON COLUMN yudao_demo03_grade.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_grade.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_grade.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_grade.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_grade.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_grade IS '学生班级表'; + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', '0', 1); +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq; +CREATE SEQUENCE yudao_demo03_grade_seq + START 10; + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_student; +CREATE TABLE yudao_demo03_student +( + id int8 NOT NULL, + name varchar(100) NOT NULL DEFAULT '', + sex int2 NOT NULL, + birthday timestamp NOT NULL, + description varchar(255) NOT NULL, + creator varchar(64) NULL DEFAULT '', + create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + updater varchar(64) NULL DEFAULT '', + update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted int2 NOT NULL DEFAULT 0, + tenant_id int8 NOT NULL DEFAULT 0 +); + +ALTER TABLE yudao_demo03_student + ADD CONSTRAINT pk_yudao_demo03_student PRIMARY KEY (id); + +COMMENT ON COLUMN yudao_demo03_student.id IS '编号'; +COMMENT ON COLUMN yudao_demo03_student.name IS '名字'; +COMMENT ON COLUMN yudao_demo03_student.sex IS '性别'; +COMMENT ON COLUMN yudao_demo03_student.birthday IS '出生日期'; +COMMENT ON COLUMN yudao_demo03_student.description IS '简介'; +COMMENT ON COLUMN yudao_demo03_student.creator IS '创建者'; +COMMENT ON COLUMN yudao_demo03_student.create_time IS '创建时间'; +COMMENT ON COLUMN yudao_demo03_student.updater IS '更新者'; +COMMENT ON COLUMN yudao_demo03_student.update_time IS '更新时间'; +COMMENT ON COLUMN yudao_demo03_student.deleted IS '是否删除'; +COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '租户编号'; +COMMENT ON TABLE yudao_demo03_student IS '学生表'; + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +BEGIN; +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '

厉害

', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '

你在教我做事?

', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', '0', 1); +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '

哈哈哈

', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', '0', 1); +COMMIT; +-- @formatter:on + +DROP SEQUENCE IF EXISTS yudao_demo03_student_seq; +CREATE SEQUENCE yudao_demo03_student_seq + START 10; + diff --git a/ruoyi-vue-pro-master/sql/sqlserver/quartz.sql b/ruoyi-vue-pro-master/sql/sqlserver/quartz.sql new file mode 100644 index 0000000..7fd2417 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/sqlserver/quartz.sql @@ -0,0 +1,533 @@ +/* + 注意:仅仅需要 Quartz 定时任务的场景,可选!!! + + Date: 30/04/2024 09:54:18 +*/ + +-- ---------------------------- +-- Table structure for QRTZ_BLOB_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [BLOB_DATA] varbinary(max) NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_BLOB_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_CALENDARS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_CALENDARS] + GO + +CREATE TABLE [dbo].[QRTZ_CALENDARS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [CALENDAR_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [CALENDAR] varbinary(max) NOT NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_CALENDARS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_CALENDARS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_CRON_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [CRON_EXPRESSION] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TIME_ZONE_ID] varchar(80) COLLATE SQL_Latin1_General_CP1_CI_AS NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_CRON_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_FIRED_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [ENTRY_ID] varchar(95) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [FIRED_TIME] bigint NOT NULL, + [SCHED_TIME] bigint NOT NULL, + [PRIORITY] int NOT NULL, + [STATE] varchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_FIRED_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_JOB_DETAILS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_JOB_DETAILS] + GO + +CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [DESCRIPTION] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [JOB_CLASS_NAME] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [IS_DURABLE] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [IS_NONCONCURRENT] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [IS_UPDATE_DATA] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [REQUESTS_RECOVERY] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_DATA] varbinary(max) NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_JOB_DETAILS +-- ---------------------------- +BEGIN TRANSACTION +GO + +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_LOCKS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_LOCKS] + GO + +CREATE TABLE [dbo].[QRTZ_LOCKS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [LOCK_NAME] varchar(40) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_LOCKS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_LOCKS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] + GO + +CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_SCHEDULER_STATE +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE] + GO + +CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [INSTANCE_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [LAST_CHECKIN_TIME] bigint NOT NULL, + [CHECKIN_INTERVAL] bigint NOT NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_SCHEDULER_STATE +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [REPEAT_COUNT] bigint NOT NULL, + [REPEAT_INTERVAL] bigint NOT NULL, + [TIMES_TRIGGERED] bigint NOT NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [STR_PROP_1] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [STR_PROP_2] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [STR_PROP_3] varchar(512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [INT_PROP_1] int NULL, + [INT_PROP_2] int NULL, + [LONG_PROP_1] bigint NULL, + [LONG_PROP_2] bigint NULL, + [DEC_PROP_1] numeric(13,4) NULL, + [DEC_PROP_2] numeric(13,4) NULL, + [BOOL_PROP_1] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [BOOL_PROP_2] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + + +-- ---------------------------- +-- Table structure for QRTZ_TRIGGERS +-- ---------------------------- +IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND type IN ('U')) +DROP TABLE [dbo].[QRTZ_TRIGGERS] + GO + +CREATE TABLE [dbo].[QRTZ_TRIGGERS] ( + [SCHED_NAME] varchar(120) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [JOB_GROUP] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [DESCRIPTION] varchar(250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [NEXT_FIRE_TIME] bigint NULL, + [PREV_FIRE_TIME] bigint NULL, + [PRIORITY] int NULL, + [TRIGGER_STATE] varchar(16) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [TRIGGER_TYPE] varchar(8) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + [START_TIME] bigint NOT NULL, + [END_TIME] bigint NULL, + [CALENDAR_NAME] varchar(200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, + [MISFIRE_INSTR] smallint NULL, + [JOB_DATA] varbinary(max) NULL + ) + GO + +ALTER TABLE [dbo].[QRTZ_TRIGGERS] SET (LOCK_ESCALATION = TABLE) + GO + + +-- ---------------------------- +-- Records of QRTZ_TRIGGERS +-- ---------------------------- +BEGIN TRANSACTION +GO + +COMMIT +GO + +-- ---------------------------- +-- Primary Key structure for table QRTZ_CALENDARS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_CALENDARS] ADD CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [CALENDAR_NAME]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Indexes structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +CREATE NONCLUSTERED INDEX [IX_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] +ON [dbo].[QRTZ_CRON_TRIGGERS] ( + [SCHED_NAME] ASC, + [TRIGGER_NAME] ASC, + [TRIGGER_GROUP] ASC +) +GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_FIRED_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [ENTRY_ID]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_JOB_DETAILS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] ADD CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [JOB_NAME], [JOB_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_LOCKS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_LOCKS] ADD CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [LOCK_NAME]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ADD CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SCHEDULER_STATE +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] ADD CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED ([SCHED_NAME], [INSTANCE_NAME]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Indexes structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +CREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] +ON [dbo].[QRTZ_SIMPLE_TRIGGERS] ( + [SCHED_NAME] ASC, + [TRIGGER_NAME] ASC, + [TRIGGER_GROUP] ASC +) +GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Indexes structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +CREATE NONCLUSTERED INDEX [IX_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] +ON [dbo].[QRTZ_SIMPROP_TRIGGERS] ( + [SCHED_NAME] ASC, + [TRIGGER_NAME] ASC, + [TRIGGER_GROUP] ASC +) +GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + + +-- ---------------------------- +-- Indexes structure for table QRTZ_TRIGGERS +-- ---------------------------- +CREATE NONCLUSTERED INDEX [IX_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] +ON [dbo].[QRTZ_TRIGGERS] ( + [SCHED_NAME] ASC, + [TRIGGER_NAME] ASC, + [TRIGGER_GROUP] ASC +) +GO + + +-- ---------------------------- +-- Primary Key structure for table QRTZ_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] + GO + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_BLOB_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_BLOB_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION + GO + + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_CRON_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION + GO + + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION + GO + + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) REFERENCES [dbo].[QRTZ_TRIGGERS] ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]) ON DELETE CASCADE ON UPDATE NO ACTION + GO + + +-- ---------------------------- +-- Foreign Keys structure for table QRTZ_TRIGGERS +-- ---------------------------- +ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY ([SCHED_NAME], [JOB_NAME], [JOB_GROUP]) REFERENCES [dbo].[QRTZ_JOB_DETAILS] ([SCHED_NAME], [JOB_NAME], [JOB_GROUP]) ON DELETE NO ACTION ON UPDATE NO ACTION + GO \ No newline at end of file diff --git a/ruoyi-vue-pro-master/sql/sqlserver/ruoyi-vue-pro.sql b/ruoyi-vue-pro-master/sql/sqlserver/ruoyi-vue-pro.sql new file mode 100644 index 0000000..9368057 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/sqlserver/ruoyi-vue-pro.sql @@ -0,0 +1,11310 @@ +/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : Microsoft SQL Server + + Date: 2024-05-08 00:22:09 + Date: 2024-05-10 22:07:48 +*/ + + +-- ---------------------------- +-- Table structure for dual +-- ---------------------------- +DROP TABLE IF EXISTS dual +GO +CREATE TABLE dual +( + id int +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据库连接的表', + 'SCHEMA', N'dbo', + 'TABLE', N'dual' +GO + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1) +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_api_access_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_access_log +GO +CREATE TABLE infra_api_access_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id nvarchar(64) DEFAULT '' NOT NULL, + user_id bigint DEFAULT 0 NOT NULL, + user_type tinyint DEFAULT 0 NOT NULL, + application_name nvarchar(50) NOT NULL, + request_method nvarchar(16) DEFAULT '' NOT NULL, + request_url nvarchar(255) DEFAULT '' NOT NULL, + request_params nvarchar(max) NULL, + response_body nvarchar(max) NULL, + user_ip nvarchar(50) NOT NULL, + user_agent nvarchar(512) NOT NULL, + operate_module nvarchar(50) DEFAULT NULL NULL, + operate_name nvarchar(50) DEFAULT NULL NULL, + operate_type tinyint DEFAULT 0 NULL, + begin_time datetime2 NOT NULL, + end_time datetime2 NOT NULL, + duration int NOT NULL, + result_code int DEFAULT 0 NOT NULL, + result_msg nvarchar(512) DEFAULT '' NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志主键', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'链路追踪编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'trace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'application_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求方法名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'request_method' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求地址', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'request_url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求参数', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'request_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'响应结果', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'response_body' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'user_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'浏览器 UA', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'user_agent' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作模块', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'operate_module' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'operate_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作分类', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'operate_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'开始请求时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'begin_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'结束请求时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'end_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行时长', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'duration' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'结果码', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'result_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'结果提示', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'result_msg' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'API 访问日志表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_access_log' +GO + +-- ---------------------------- +-- Table structure for infra_api_error_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_api_error_log +GO +CREATE TABLE infra_api_error_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id nvarchar(64) NOT NULL, + user_id int DEFAULT 0 NOT NULL, + user_type tinyint DEFAULT 0 NOT NULL, + application_name nvarchar(50) NOT NULL, + request_method nvarchar(16) NOT NULL, + request_url nvarchar(255) NOT NULL, + request_params nvarchar(4000) NOT NULL, + user_ip nvarchar(50) NOT NULL, + user_agent nvarchar(512) NOT NULL, + exception_time datetime2 NOT NULL, + exception_name nvarchar(128) DEFAULT '' NOT NULL, + exception_message nvarchar(max) NOT NULL, + exception_root_cause_message nvarchar(max) NOT NULL, + exception_stack_trace nvarchar(max) NOT NULL, + exception_class_name nvarchar(512) NOT NULL, + exception_file_name nvarchar(512) NOT NULL, + exception_method_name nvarchar(512) NOT NULL, + exception_line_number int NOT NULL, + process_status tinyint NOT NULL, + process_time datetime2 DEFAULT NULL NULL, + process_user_id int DEFAULT 0 NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'trace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用名 + * + * 目前读取 spring.application.name', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'application_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求方法名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'request_method' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求地址', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'request_url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求参数', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'request_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'user_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'浏览器 UA', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'user_agent' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常发生时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常名 + * + * {@link Throwable#getClass()} 的类全名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常导致的消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getMessage(Throwable)}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常导致的根消息 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getRootCauseMessage(Throwable)}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_root_cause_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常的栈轨迹 + * + * {@link cn.iocoder.common.framework.util.ExceptionUtil#getServiceException(Exception)}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_stack_trace' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常发生的类全名 + * + * {@link StackTraceElement#getClassName()}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_class_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常发生的类文件 + * + * {@link StackTraceElement#getFileName()}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_file_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_method_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()}', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'exception_line_number' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理状态', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'process_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'process_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'process_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统异常日志', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_api_error_log' +GO + +-- ---------------------------- +-- Table structure for infra_codegen_column +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_column +GO +CREATE TABLE infra_codegen_column +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + table_id bigint NOT NULL, + column_name nvarchar(200) NOT NULL, + data_type nvarchar(100) NOT NULL, + column_comment nvarchar(500) NOT NULL, + nullable varchar(1) NOT NULL, + primary_key varchar(1) NOT NULL, + ordinal_position int NOT NULL, + java_type nvarchar(32) NOT NULL, + java_field nvarchar(64) NOT NULL, + dict_type nvarchar(200) DEFAULT '' NULL, + example nvarchar(64) DEFAULT NULL NULL, + create_operation varchar(1) NOT NULL, + update_operation varchar(1) NOT NULL, + list_operation varchar(1) NOT NULL, + list_operation_condition nvarchar(32) DEFAULT '=' NOT NULL, + list_operation_result varchar(1) NOT NULL, + html_type nvarchar(32) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'表编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'table_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字段名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'column_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字段类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'data_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字段描述', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'column_comment' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否允许为空', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'nullable' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否主键', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'primary_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'排序', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'ordinal_position' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Java 属性类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'java_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Java 属性名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'java_field' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'dict_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据示例', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'example' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否为 Create 创建操作的字段', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'create_operation' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否为 Update 更新操作的字段', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'update_operation' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否为 List 查询操作的字段', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'list_operation' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'List 查询操作的条件类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'list_operation_condition' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否为 List 查询操作的返回字段', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'list_operation_result' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'显示类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'html_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'代码生成表字段定义', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_column' +GO + +-- ---------------------------- +-- Table structure for infra_codegen_table +-- ---------------------------- +DROP TABLE IF EXISTS infra_codegen_table +GO +CREATE TABLE infra_codegen_table +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + data_source_config_id bigint NOT NULL, + scene tinyint DEFAULT 1 NOT NULL, + table_name nvarchar(200) DEFAULT '' NOT NULL, + table_comment nvarchar(500) DEFAULT '' NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + module_name nvarchar(30) NOT NULL, + business_name nvarchar(30) NOT NULL, + class_name nvarchar(100) DEFAULT '' NOT NULL, + class_comment nvarchar(50) NOT NULL, + author nvarchar(50) NOT NULL, + template_type tinyint DEFAULT 1 NOT NULL, + front_type tinyint NOT NULL, + parent_menu_id bigint DEFAULT NULL NULL, + master_table_id bigint DEFAULT NULL NULL, + sub_join_column_id bigint DEFAULT NULL NULL, + sub_join_many varchar(1) DEFAULT NULL NULL, + tree_parent_column_id bigint DEFAULT NULL NULL, + tree_name_column_id bigint DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据源配置的编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'data_source_config_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'生成场景', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'表名称', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'table_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'表描述', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'table_comment' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模块名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'module_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'business_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'类名称', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'class_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'类描述', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'class_comment' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'作者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'author' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'template_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'前端类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'front_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父菜单编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'parent_menu_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主表的编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'master_table_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'子表关联主表的字段编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'sub_join_column_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主表与子表是否一对多', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'sub_join_many' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'树表的父字段编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'tree_parent_column_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'树表的名字字段编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'tree_name_column_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'代码生成表定义', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_codegen_table' +GO + +-- ---------------------------- +-- Table structure for infra_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_config +GO +CREATE TABLE infra_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + category nvarchar(50) NOT NULL, + type tinyint NOT NULL, + name nvarchar(100) DEFAULT '' NOT NULL, + config_key nvarchar(100) DEFAULT '' NOT NULL, + value nvarchar(500) DEFAULT '' NOT NULL, + visible varchar(1) NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数主键', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数分组', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'category' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数名称', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数键名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'config_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数键值', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否可见', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'visible' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_config' +GO + +-- ---------------------------- +-- Records of infra_config +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT infra_config ON +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, N'biz', 1, N'用户管理-账号初始密码', N'sys.user.init-password', N'123456', N'0', N'初始化密码 123456', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-03 17:22:28', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, N'url', 2, N'MySQL 监控的地址', N'url.druid', N'', N'1', N'', N'1', N'2023-04-07 13:41:16', N'1', N'2023-04-07 14:33:38', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, N'url', 2, N'SkyWalking 监控的地址', N'url.skywalking', N'', N'1', N'', N'1', N'2023-04-07 13:41:16', N'1', N'2023-04-07 14:57:03', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, N'url', 2, N'Spring Boot Admin 监控的地址', N'url.spring-boot-admin', N'', N'1', N'', N'1', N'2023-04-07 13:41:16', N'1', N'2023-04-07 14:52:07', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, N'url', 2, N'Swagger 接口文档的地址', N'url.swagger', N'', N'1', N'', N'1', N'2023-04-07 13:41:16', N'1', N'2023-04-07 14:59:00', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (11, N'ui', 2, N'腾讯地图 key', N'tencent.lbs.key', N'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E', N'1', N'腾讯地图 key', N'1', N'2023-06-03 19:16:27', N'1', N'2023-06-03 19:16:27', N'0') +GO +INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, N'test2', 2, N'test3', N'test4', N'test5', N'1', N'test6', N'1', N'2023-12-03 09:55:16', N'1', N'2023-12-03 09:55:27', N'0') +GO +SET IDENTITY_INSERT infra_config OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_data_source_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_data_source_config +GO +CREATE TABLE infra_data_source_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(100) DEFAULT '' NOT NULL, + url nvarchar(1024) NOT NULL, + username nvarchar(255) NOT NULL, + password nvarchar(255) DEFAULT '' NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数名称', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据源连接', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据源配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_data_source_config' +GO + +-- ---------------------------- +-- Table structure for infra_file +-- ---------------------------- +DROP TABLE IF EXISTS infra_file +GO +CREATE TABLE infra_file +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + config_id bigint DEFAULT NULL NULL, + name nvarchar(256) DEFAULT NULL NULL, + path nvarchar(512) NOT NULL, + url nvarchar(1024) NOT NULL, + type nvarchar(128) DEFAULT NULL NULL, + size int NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'config_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件路径', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'path' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件 URL', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件类型', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件大小', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'size' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file' +GO + +-- ---------------------------- +-- Table structure for infra_file_config +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_config +GO +CREATE TABLE infra_file_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(63) NOT NULL, + storage tinyint NOT NULL, + remark nvarchar(255) DEFAULT NULL NULL, + master varchar(1) NOT NULL, + config nvarchar(4000) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置名', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'存储器', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'storage' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否为主配置', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'master' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'存储配置', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'config' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_config' +GO + +-- ---------------------------- +-- Records of infra_file_config +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT infra_file_config ON +GO +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, N'数据库', 1, N'我是数据库', N'0', N'{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', N'1', N'2022-03-15 23:56:24', N'1', N'2024-02-28 22:54:07', N'0') +GO +INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, N'七牛存储器', 20, N'', N'1', N'{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY"}', N'1', N'2024-01-13 22:11:12', N'1', N'2024-04-03 19:38:34', N'0') +GO +SET IDENTITY_INSERT infra_file_config OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_file_content +-- ---------------------------- +DROP TABLE IF EXISTS infra_file_content +GO +CREATE TABLE infra_file_content +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + config_id bigint NOT NULL, + path nvarchar(512) NOT NULL, + content varbinary(max) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'config_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件路径', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'path' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件内容', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'文件表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_file_content' +GO + +-- ---------------------------- +-- Table structure for infra_job +-- ---------------------------- +DROP TABLE IF EXISTS infra_job +GO +CREATE TABLE infra_job +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(32) NOT NULL, + status tinyint NOT NULL, + handler_name nvarchar(64) NOT NULL, + handler_param nvarchar(255) DEFAULT NULL NULL, + cron_expression nvarchar(32) NOT NULL, + retry_count int DEFAULT 0 NOT NULL, + retry_interval int DEFAULT 0 NOT NULL, + monitor_timeout int DEFAULT 0 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务名称', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理器的名字', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'handler_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理器的参数', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'handler_param' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'cron_expression' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试间隔', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'retry_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'监控超时时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'monitor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'定时任务表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job' +GO + +-- ---------------------------- +-- Records of infra_job +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT infra_job ON +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, N'支付通知 Job', 2, N'payNotifyJob', NULL, N'* * * * * ?', 0, 0, 0, N'1', N'2021-10-27 08:34:42', N'1', N'2023-07-09 20:51:41', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, N'支付订单同步 Job', 2, N'payOrderSyncJob', NULL, N'0 0/1 * * * ?', 0, 0, 0, N'1', N'2023-07-22 14:36:26', N'1', N'2023-07-22 15:39:08', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, N'支付订单过期 Job', 2, N'payOrderExpireJob', NULL, N'0 0/1 * * * ?', 0, 0, 0, N'1', N'2023-07-22 15:36:23', N'1', N'2023-07-22 15:39:54', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, N'退款订单的同步 Job', 2, N'payRefundSyncJob', NULL, N'0 0/1 * * * ?', 0, 0, 0, N'1', N'2023-07-23 21:03:44', N'1', N'2023-07-23 21:09:00', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, N'交易订单的自动过期 Job', 2, N'tradeOrderAutoCancelJob', N'', N'0 * * * * ?', 3, 0, 0, N'1', N'2023-09-25 23:43:26', N'1', N'2023-09-26 19:23:30', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, N'交易订单的自动收货 Job', 2, N'tradeOrderAutoReceiveJob', N'', N'0 * * * * ?', 3, 0, 0, N'1', N'2023-09-26 19:23:53', N'1', N'2023-09-26 23:38:08', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, N'交易订单的自动评论 Job', 2, N'tradeOrderAutoCommentJob', N'', N'0 * * * * ?', 3, 0, 0, N'1', N'2023-09-26 23:38:29', N'1', N'2023-09-27 11:03:10', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, N'佣金解冻 Job', 2, N'brokerageRecordUnfreezeJob', N'', N'0 * * * * ?', 3, 0, 0, N'1', N'2023-09-28 22:01:46', N'1', N'2023-09-28 22:01:56', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, N'访问日志清理 Job', 2, N'accessLogCleanJob', N'', N'0 0 0 * * ?', 3, 0, 0, N'1', N'2023-10-03 10:59:41', N'1', N'2023-10-03 11:01:10', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, N'错误日志清理 Job', 2, N'errorLogCleanJob', N'', N'0 0 0 * * ?', 3, 0, 0, N'1', N'2023-10-03 11:00:43', N'1', N'2023-10-03 11:01:12', N'0') +GO +INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, N'任务日志清理 Job', 2, N'jobLogCleanJob', N'', N'0 0 0 * * ?', 3, 0, 0, N'1', N'2023-10-03 11:01:33', N'1', N'2023-10-03 11:01:42', N'0') +GO +SET IDENTITY_INSERT infra_job OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for infra_job_log +-- ---------------------------- +DROP TABLE IF EXISTS infra_job_log +GO +CREATE TABLE infra_job_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + job_id bigint NOT NULL, + handler_name nvarchar(64) NOT NULL, + handler_param nvarchar(255) DEFAULT NULL NULL, + execute_index tinyint DEFAULT 1 NOT NULL, + begin_time datetime2 NOT NULL, + end_time datetime2 DEFAULT NULL NULL, + duration int DEFAULT NULL NULL, + status tinyint NOT NULL, + result nvarchar(4000) DEFAULT '' NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理器的名字', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'handler_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'处理器的参数', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'handler_param' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'第几次执行', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'execute_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'开始执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'begin_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'结束执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'end_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行时长', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'duration' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'结果数据', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'result' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'定时任务日志表', + 'SCHEMA', N'dbo', + 'TABLE', N'infra_job_log' +GO + +-- ---------------------------- +-- Table structure for system_dept +-- ---------------------------- +DROP TABLE IF EXISTS system_dept +GO +CREATE TABLE system_dept +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(30) DEFAULT '' NOT NULL, + parent_id bigint DEFAULT 0 NOT NULL, + sort int DEFAULT 0 NOT NULL, + leader_user_id bigint DEFAULT NULL NULL, + phone nvarchar(11) DEFAULT NULL NULL, + email nvarchar(50) DEFAULT NULL NULL, + status tinyint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'显示顺序', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'leader_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'联系电话', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'phone' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮箱', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'email' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dept' +GO + +-- ---------------------------- +-- Records of system_dept +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_dept ON +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, N'芋道源码', 0, 0, 1, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2023-11-14 23:30:36', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, N'深圳总公司', 100, 1, 104, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2023-12-02 09:53:35', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, N'长沙分公司', 100, 2, NULL, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'', N'2021-12-15 05:01:40', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, N'研发部门', 101, 1, 104, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2024-03-24 20:56:04', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, N'市场部门', 101, 2, NULL, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'', N'2021-12-15 05:01:38', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, N'测试部门', 101, 3, NULL, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2022-05-16 20:25:15', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, N'财务部门', 101, 4, 103, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'103', N'2022-01-15 21:32:22', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, N'运维部门', 101, 5, 1, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2023-12-02 09:28:22', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, N'市场部门', 102, 1, NULL, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'1', N'2022-02-16 08:35:45', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, N'财务部门', 102, 2, NULL, N'15888888888', N'ry@qq.com', 0, N'admin', N'2021-01-05 17:03:47', N'', N'2021-12-15 05:01:29', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, N'新部门', 0, 1, NULL, NULL, NULL, 0, N'110', N'2022-02-23 20:46:30', N'110', N'2022-02-23 20:46:30', N'0', 121) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, N'顶级部门', 0, 1, NULL, NULL, NULL, 0, N'113', N'2022-03-07 21:44:50', N'113', N'2022-03-07 21:44:50', N'0', 122) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, N'产品部门', 101, 100, 1, NULL, NULL, 1, N'1', N'2023-12-02 09:45:13', N'1', N'2023-12-02 09:45:31', N'0', 1) +GO +INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, N'支持部门', 102, 3, 104, NULL, NULL, 1, N'1', N'2023-12-02 09:47:38', N'1', N'2023-12-02 09:47:38', N'0', 1) +GO +SET IDENTITY_INSERT system_dept OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_data +GO +CREATE TABLE system_dict_data +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + sort int DEFAULT 0 NOT NULL, + label nvarchar(100) DEFAULT '' NOT NULL, + value nvarchar(100) DEFAULT '' NOT NULL, + dict_type nvarchar(100) DEFAULT '' NOT NULL, + status tinyint DEFAULT 0 NOT NULL, + color_type nvarchar(100) DEFAULT '' NULL, + css_class nvarchar(100) DEFAULT '' NULL, + remark nvarchar(500) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典排序', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典标签', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'label' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典键值', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'dict_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'颜色类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'color_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'css 样式', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'css_class' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典数据表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_data' +GO + +-- ---------------------------- +-- Records of system_dict_data +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_dict_data ON +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, N'男', N'1', N'system_user_sex', 0, N'default', N'A', N'性别男', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-03-29 00:14:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, N'女', N'2', N'system_user_sex', 0, N'success', N'', N'性别女', N'admin', N'2021-01-05 17:03:48', N'1', N'2023-11-15 23:30:37', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, N'正常', N'1', N'infra_job_status', 0, N'success', N'', N'正常状态', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 19:33:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, N'暂停', N'2', N'infra_job_status', 0, N'danger', N'', N'停用状态', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 19:33:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, N'系统内置', N'1', N'infra_config_type', 0, N'danger', N'', N'参数类型 - 系统内置', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 19:06:02', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, N'自定义', N'2', N'infra_config_type', 0, N'primary', N'', N'参数类型 - 自定义', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 19:06:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, N'通知', N'1', N'system_notice_type', 0, N'success', N'', N'通知', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 13:05:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, N'公告', N'2', N'system_notice_type', 0, N'info', N'', N'公告', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 13:06:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, N'其它', N'0', N'infra_operate_type', 0, N'default', N'', N'其它操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, N'查询', N'1', N'infra_operate_type', 0, N'info', N'', N'查询操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, N'新增', N'2', N'infra_operate_type', 0, N'primary', N'', N'新增操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, N'修改', N'3', N'infra_operate_type', 0, N'warning', N'', N'修改操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, N'删除', N'4', N'infra_operate_type', 0, N'danger', N'', N'删除操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:23', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, N'导出', N'5', N'infra_operate_type', 0, N'default', N'', N'导出操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, N'导入', N'6', N'infra_operate_type', 0, N'default', N'', N'导入操作', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:25', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, N'开启', N'0', N'common_status', 0, N'primary', N'', N'开启状态', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 08:00:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, N'关闭', N'1', N'common_status', 0, N'info', N'', N'关闭状态', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 08:00:44', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, N'目录', N'1', N'system_menu_type', 0, N'', N'', N'目录', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:43:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, N'菜单', N'2', N'system_menu_type', 0, N'', N'', N'菜单', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:43:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, N'按钮', N'3', N'system_menu_type', 0, N'', N'', N'按钮', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:43:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, N'内置', N'1', N'system_role_type', 0, N'danger', N'', N'内置角色', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 13:02:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, N'自定义', N'2', N'system_role_type', 0, N'primary', N'', N'自定义角色', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-02-16 13:02:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, N'全部数据权限', N'1', N'system_data_scope', 0, N'', N'', N'全部数据权限', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:47:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, N'指定部门数据权限', N'2', N'system_data_scope', 0, N'', N'', N'指定部门数据权限', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:47:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, N'本部门数据权限', N'3', N'system_data_scope', 0, N'', N'', N'本部门数据权限', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:47:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, N'本部门及以下数据权限', N'4', N'system_data_scope', 0, N'', N'', N'本部门及以下数据权限', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:47:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, N'仅本人数据权限', N'5', N'system_data_scope', 0, N'', N'', N'仅本人数据权限', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:47:23', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, N'成功', N'0', N'system_login_result', 0, N'success', N'', N'登陆结果 - 成功', N'', N'2021-01-18 06:17:36', N'1', N'2022-02-16 13:23:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, N'账号或密码不正确', N'10', N'system_login_result', 0, N'primary', N'', N'登陆结果 - 账号或密码不正确', N'', N'2021-01-18 06:17:54', N'1', N'2022-02-16 13:24:27', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, N'用户被禁用', N'20', N'system_login_result', 0, N'warning', N'', N'登陆结果 - 用户被禁用', N'', N'2021-01-18 06:17:54', N'1', N'2022-02-16 13:23:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, N'验证码不存在', N'30', N'system_login_result', 0, N'info', N'', N'登陆结果 - 验证码不存在', N'', N'2021-01-18 06:17:54', N'1', N'2022-02-16 13:24:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, N'验证码不正确', N'31', N'system_login_result', 0, N'info', N'', N'登陆结果 - 验证码不正确', N'', N'2021-01-18 06:17:54', N'1', N'2022-02-16 13:24:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, N'未知异常', N'100', N'system_login_result', 0, N'danger', N'', N'登陆结果 - 未知异常', N'', N'2021-01-18 06:17:54', N'1', N'2022-02-16 13:24:23', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, N'是', N'true', N'infra_boolean_string', 0, N'danger', N'', N'Boolean 是否类型 - 是', N'', N'2021-01-19 03:20:55', N'1', N'2022-03-15 23:01:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, N'否', N'false', N'infra_boolean_string', 0, N'info', N'', N'Boolean 是否类型 - 否', N'', N'2021-01-19 03:20:55', N'1', N'2022-03-15 23:09:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, N'单表(增删改查)', N'1', N'infra_codegen_template_type', 0, N'', N'', NULL, N'', N'2021-02-05 07:09:06', N'', N'2022-03-10 16:33:15', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, N'树表(增删改查)', N'2', N'infra_codegen_template_type', 0, N'', N'', NULL, N'', N'2021-02-05 07:14:46', N'', N'2022-03-10 16:33:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, N'初始化中', N'0', N'infra_job_status', 0, N'primary', N'', NULL, N'', N'2021-02-07 07:46:49', N'1', N'2022-02-16 19:33:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, N'运行中', N'0', N'infra_job_log_status', 0, N'primary', N'', N'RUNNING', N'', N'2021-02-08 10:04:24', N'1', N'2022-02-16 19:07:48', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, N'成功', N'1', N'infra_job_log_status', 0, N'success', N'', NULL, N'', N'2021-02-08 10:06:57', N'1', N'2022-02-16 19:07:52', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, N'失败', N'2', N'infra_job_log_status', 0, N'warning', N'', N'失败', N'', N'2021-02-08 10:07:38', N'1', N'2022-02-16 19:07:56', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, N'会员', N'1', N'user_type', 0, N'primary', N'', NULL, N'', N'2021-02-26 00:16:27', N'1', N'2022-02-16 10:22:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, N'管理员', N'2', N'user_type', 0, N'success', N'', NULL, N'', N'2021-02-26 00:16:34', N'1', N'2022-02-16 10:22:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, N'未处理', N'0', N'infra_api_error_log_process_status', 0, N'primary', N'', NULL, N'', N'2021-02-26 07:07:19', N'1', N'2022-02-16 20:14:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, N'已处理', N'1', N'infra_api_error_log_process_status', 0, N'success', N'', NULL, N'', N'2021-02-26 07:07:26', N'1', N'2022-02-16 20:14:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, N'已忽略', N'2', N'infra_api_error_log_process_status', 0, N'danger', N'', NULL, N'', N'2021-02-26 07:07:34', N'1', N'2022-02-16 20:14:14', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 2, N'阿里云', N'ALIYUN', N'system_sms_channel_code', 0, N'primary', N'', NULL, N'1', N'2021-04-05 01:05:26', N'1', N'2022-02-16 10:09:52', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, N'验证码', N'1', N'system_sms_template_type', 0, N'warning', N'', NULL, N'1', N'2021-04-05 21:50:57', N'1', N'2022-02-16 12:48:30', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, N'通知', N'2', N'system_sms_template_type', 0, N'primary', N'', NULL, N'1', N'2021-04-05 21:51:08', N'1', N'2022-02-16 12:48:27', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, N'营销', N'3', N'system_sms_template_type', 0, N'danger', N'', NULL, N'1', N'2021-04-05 21:51:15', N'1', N'2022-02-16 12:48:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, N'初始化', N'0', N'system_sms_send_status', 0, N'primary', N'', NULL, N'1', N'2021-04-11 20:18:33', N'1', N'2022-02-16 10:26:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, N'发送成功', N'10', N'system_sms_send_status', 0, N'success', N'', NULL, N'1', N'2021-04-11 20:18:43', N'1', N'2022-02-16 10:25:56', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, N'发送失败', N'20', N'system_sms_send_status', 0, N'danger', N'', NULL, N'1', N'2021-04-11 20:18:49', N'1', N'2022-02-16 10:26:03', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, N'不发送', N'30', N'system_sms_send_status', 0, N'info', N'', NULL, N'1', N'2021-04-11 20:19:44', N'1', N'2022-02-16 10:26:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, N'等待结果', N'0', N'system_sms_receive_status', 0, N'primary', N'', NULL, N'1', N'2021-04-11 20:27:43', N'1', N'2022-02-16 10:28:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, N'接收成功', N'10', N'system_sms_receive_status', 0, N'success', N'', NULL, N'1', N'2021-04-11 20:29:25', N'1', N'2022-02-16 10:28:28', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, N'接收失败', N'20', N'system_sms_receive_status', 0, N'danger', N'', NULL, N'1', N'2021-04-11 20:29:31', N'1', N'2022-02-16 10:28:32', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, N'调试(钉钉)', N'DEBUG_DING_TALK', N'system_sms_channel_code', 0, N'info', N'', NULL, N'1', N'2021-04-13 00:20:37', N'1', N'2022-02-16 10:10:00', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, N'账号登录', N'100', N'system_login_type', 0, N'primary', N'', N'账号登录', N'1', N'2021-10-06 00:52:02', N'1', N'2022-02-16 13:11:34', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, N'社交登录', N'101', N'system_login_type', 0, N'info', N'', N'社交登录', N'1', N'2021-10-06 00:52:17', N'1', N'2022-02-16 13:11:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, N'主动登出', N'200', N'system_login_type', 0, N'primary', N'', N'主动登出', N'1', N'2021-10-06 00:52:58', N'1', N'2022-02-16 13:11:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, N'强制登出', N'202', N'system_login_type', 0, N'danger', N'', N'强制退出', N'1', N'2021-10-06 00:53:41', N'1', N'2022-02-16 13:11:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, N'病假', N'1', N'bpm_oa_leave_type', 0, N'primary', N'', NULL, N'1', N'2021-09-21 22:35:28', N'1', N'2022-02-16 10:00:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, N'事假', N'2', N'bpm_oa_leave_type', 0, N'info', N'', NULL, N'1', N'2021-09-21 22:36:11', N'1', N'2022-02-16 10:00:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, N'婚假', N'3', N'bpm_oa_leave_type', 0, N'warning', N'', NULL, N'1', N'2021-09-21 22:36:38', N'1', N'2022-02-16 10:00:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, N'微信公众号支付', N'wx_pub', N'pay_channel_code', 0, N'success', N'', N'微信公众号支付', N'1', N'2021-12-03 10:40:24', N'1', N'2023-07-19 20:08:47', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, N'微信小程序支付', N'wx_lite', N'pay_channel_code', 0, N'success', N'', N'微信小程序支付', N'1', N'2021-12-03 10:41:06', N'1', N'2023-07-19 20:08:50', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, N'微信 App 支付', N'wx_app', N'pay_channel_code', 0, N'success', N'', N'微信 App 支付', N'1', N'2021-12-03 10:41:20', N'1', N'2023-07-19 20:08:56', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, N'支付宝 PC 网站支付', N'alipay_pc', N'pay_channel_code', 0, N'primary', N'', N'支付宝 PC 网站支付', N'1', N'2021-12-03 10:42:09', N'1', N'2023-07-19 20:09:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, N'支付宝 Wap 网站支付', N'alipay_wap', N'pay_channel_code', 0, N'primary', N'', N'支付宝 Wap 网站支付', N'1', N'2021-12-03 10:42:26', N'1', N'2023-07-19 20:09:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, N'支付宝 App 支付', N'alipay_app', N'pay_channel_code', 0, N'primary', N'', N'支付宝 App 支付', N'1', N'2021-12-03 10:42:55', N'1', N'2023-07-19 20:09:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, N'支付宝扫码支付', N'alipay_qr', N'pay_channel_code', 0, N'primary', N'', N'支付宝扫码支付', N'1', N'2021-12-03 10:43:10', N'1', N'2023-07-19 20:09:28', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, N'通知成功', N'10', N'pay_notify_status', 0, N'success', N'', N'通知成功', N'1', N'2021-12-03 11:02:41', N'1', N'2023-07-19 10:08:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, N'通知失败', N'20', N'pay_notify_status', 0, N'danger', N'', N'通知失败', N'1', N'2021-12-03 11:02:59', N'1', N'2023-07-19 10:08:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, N'等待通知', N'0', N'pay_notify_status', 0, N'info', N'', N'未通知', N'1', N'2021-12-03 11:03:10', N'1', N'2023-07-19 10:08:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, N'支付成功', N'10', N'pay_order_status', 0, N'success', N'', N'支付成功', N'1', N'2021-12-03 11:18:29', N'1', N'2023-07-19 18:04:28', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, N'支付关闭', N'30', N'pay_order_status', 0, N'info', N'', N'支付关闭', N'1', N'2021-12-03 11:18:42', N'1', N'2023-07-19 18:05:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, N'等待支付', N'0', N'pay_order_status', 0, N'info', N'', N'未支付', N'1', N'2021-12-03 11:18:18', N'1', N'2023-07-19 18:04:15', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, N'首页', N'1', N'promotion_banner_position', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, N'秒杀活动页', N'2', N'promotion_banner_position', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, N'砍价活动页', N'3', N'promotion_banner_position', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, N'限时折扣页', N'4', N'promotion_banner_position', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, N'满减送页', N'5', N'promotion_banner_position', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, N'等待退款', N'0', N'pay_refund_status', 0, N'info', N'', N'等待退款', N'1', N'2021-12-10 16:44:59', N'1', N'2023-07-19 10:14:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, N'退款失败', N'20', N'pay_refund_status', 0, N'danger', N'', N'退款失败', N'1', N'2021-12-10 16:45:10', N'1', N'2023-07-19 10:15:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, N'退款成功', N'10', N'pay_refund_status', 0, N'success', N'', N'退款成功', N'1', N'2021-12-10 16:46:26', N'1', N'2023-07-19 10:15:00', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, N'审批中', N'1', N'bpm_process_instance_status', 0, N'default', N'', N'流程实例的状态 - 进行中', N'1', N'2022-01-07 23:47:22', N'1', N'2024-03-16 16:11:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, N'审批通过', N'2', N'bpm_process_instance_status', 0, N'success', N'', N'流程实例的状态 - 已完成', N'1', N'2022-01-07 23:47:49', N'1', N'2024-03-16 16:11:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, N'审批中', N'1', N'bpm_task_status', 0, N'primary', N'', N'流程实例的结果 - 处理中', N'1', N'2022-01-07 23:48:32', N'1', N'2024-03-08 22:41:37', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, N'审批通过', N'2', N'bpm_task_status', 0, N'success', N'', N'流程实例的结果 - 通过', N'1', N'2022-01-07 23:48:45', N'1', N'2024-03-08 22:41:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, N'审批不通过', N'3', N'bpm_task_status', 0, N'danger', N'', N'流程实例的结果 - 不通过', N'1', N'2022-01-07 23:48:55', N'1', N'2024-03-08 22:41:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, N'已取消', N'4', N'bpm_task_status', 0, N'info', N'', N'流程实例的结果 - 撤销', N'1', N'2022-01-07 23:49:06', N'1', N'2024-03-08 22:41:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, N'流程表单', N'10', N'bpm_model_form_type', 0, N'', N'', N'流程的表单类型 - 流程表单', N'103', N'2022-01-11 23:51:30', N'103', N'2022-01-11 23:51:30', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, N'业务表单', N'20', N'bpm_model_form_type', 0, N'', N'', N'流程的表单类型 - 业务表单', N'103', N'2022-01-11 23:51:47', N'103', N'2022-01-11 23:51:47', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, N'角色', N'10', N'bpm_task_candidate_strategy', 0, N'info', N'', N'任务分配规则的类型 - 角色', N'103', N'2022-01-12 23:21:22', N'1', N'2024-03-06 02:53:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, N'部门的成员', N'20', N'bpm_task_candidate_strategy', 0, N'primary', N'', N'任务分配规则的类型 - 部门的成员', N'103', N'2022-01-12 23:21:47', N'1', N'2024-03-06 02:53:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, N'部门的负责人', N'21', N'bpm_task_candidate_strategy', 0, N'primary', N'', N'任务分配规则的类型 - 部门的负责人', N'103', N'2022-01-12 23:33:36', N'1', N'2024-03-06 02:53:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, N'用户', N'30', N'bpm_task_candidate_strategy', 0, N'info', N'', N'任务分配规则的类型 - 用户', N'103', N'2022-01-12 23:34:02', N'1', N'2024-03-06 02:53:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, N'用户组', N'40', N'bpm_task_candidate_strategy', 0, N'warning', N'', N'任务分配规则的类型 - 用户组', N'103', N'2022-01-12 23:34:21', N'1', N'2024-03-06 02:53:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, N'流程表达式', N'60', N'bpm_task_candidate_strategy', 0, N'danger', N'', N'任务分配规则的类型 - 流程表达式', N'103', N'2022-01-12 23:34:43', N'1', N'2024-03-06 02:53:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, N'岗位', N'22', N'bpm_task_candidate_strategy', 0, N'success', N'', N'任务分配规则的类型 - 岗位', N'103', N'2022-01-14 18:41:55', N'1', N'2024-03-06 02:53:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, N'管理后台', N'1', N'infra_codegen_scene', 0, N'', N'', N'代码生成的场景枚举 - 管理后台', N'1', N'2022-02-02 13:15:06', N'1', N'2022-03-10 16:32:59', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, N'用户 APP', N'2', N'infra_codegen_scene', 0, N'', N'', N'代码生成的场景枚举 - 用户 APP', N'1', N'2022-02-02 13:15:19', N'1', N'2022-03-10 16:33:03', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, N'数据库', N'1', N'infra_file_storage', 0, N'default', N'', NULL, N'1', N'2022-03-15 00:25:28', N'1', N'2022-03-15 00:25:28', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, N'本地磁盘', N'10', N'infra_file_storage', 0, N'default', N'', NULL, N'1', N'2022-03-15 00:25:41', N'1', N'2022-03-15 00:25:56', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, N'FTP 服务器', N'11', N'infra_file_storage', 0, N'default', N'', NULL, N'1', N'2022-03-15 00:26:06', N'1', N'2022-03-15 00:26:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, N'SFTP 服务器', N'12', N'infra_file_storage', 0, N'default', N'', NULL, N'1', N'2022-03-15 00:26:22', N'1', N'2022-03-15 00:26:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, N'S3 对象存储', N'20', N'infra_file_storage', 0, N'default', N'', NULL, N'1', N'2022-03-15 00:26:31', N'1', N'2022-03-15 00:26:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, N'短信登录', N'103', N'system_login_type', 0, N'default', N'', NULL, N'1', N'2022-05-09 23:57:58', N'1', N'2022-05-09 23:58:09', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, N'password', N'password', N'system_oauth2_grant_type', 0, N'default', N'', N'密码模式', N'1', N'2022-05-12 00:22:05', N'1', N'2022-05-11 16:26:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, N'authorization_code', N'authorization_code', N'system_oauth2_grant_type', 0, N'primary', N'', N'授权码模式', N'1', N'2022-05-12 00:22:59', N'1', N'2022-05-11 16:26:02', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, N'implicit', N'implicit', N'system_oauth2_grant_type', 0, N'success', N'', N'简化模式', N'1', N'2022-05-12 00:23:40', N'1', N'2022-05-11 16:26:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, N'client_credentials', N'client_credentials', N'system_oauth2_grant_type', 0, N'default', N'', N'客户端模式', N'1', N'2022-05-12 00:23:51', N'1', N'2022-05-11 16:26:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, N'refresh_token', N'refresh_token', N'system_oauth2_grant_type', 0, N'info', N'', N'刷新模式', N'1', N'2022-05-12 00:24:02', N'1', N'2022-05-11 16:26:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, N'销售中', N'1', N'product_spu_status', 0, N'success', N'', N'商品 SPU 状态 - 销售中', N'1', N'2022-10-24 21:19:47', N'1', N'2022-10-24 21:20:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, N'仓库中', N'0', N'product_spu_status', 0, N'info', N'', N'商品 SPU 状态 - 仓库中', N'1', N'2022-10-24 21:20:54', N'1', N'2022-10-24 21:21:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, N'回收站', N'-1', N'product_spu_status', 0, N'default', N'', N'商品 SPU 状态 - 回收站', N'1', N'2022-10-24 21:21:11', N'1', N'2022-10-24 21:21:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, N'满减', N'1', N'promotion_discount_type', 0, N'success', N'', N'优惠类型 - 满减', N'1', N'2022-11-01 12:46:41', N'1', N'2022-11-01 12:50:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, N'折扣', N'2', N'promotion_discount_type', 0, N'primary', N'', N'优惠类型 - 折扣', N'1', N'2022-11-01 12:46:51', N'1', N'2022-11-01 12:50:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, N'固定日期', N'1', N'promotion_coupon_template_validity_type', 0, N'default', N'', N'优惠劵模板的有限期类型 - 固定日期', N'1', N'2022-11-02 00:07:34', N'1', N'2022-11-04 00:07:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, N'领取之后', N'2', N'promotion_coupon_template_validity_type', 0, N'default', N'', N'优惠劵模板的有限期类型 - 领取之后', N'1', N'2022-11-02 00:07:54', N'1', N'2022-11-04 00:07:52', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, N'通用劵', N'1', N'promotion_product_scope', 0, N'default', N'', N'营销的商品范围 - 全部商品参与', N'1', N'2022-11-02 00:28:22', N'1', N'2023-09-28 00:27:42', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, N'商品劵', N'2', N'promotion_product_scope', 0, N'default', N'', N'营销的商品范围 - 指定商品参与', N'1', N'2022-11-02 00:28:34', N'1', N'2023-09-28 00:27:44', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, N'未使用', N'1', N'promotion_coupon_status', 0, N'primary', N'', N'优惠劵的状态 - 已领取', N'1', N'2022-11-04 00:15:08', N'1', N'2023-10-03 12:54:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, N'已使用', N'2', N'promotion_coupon_status', 0, N'success', N'', N'优惠劵的状态 - 已使用', N'1', N'2022-11-04 00:15:21', N'1', N'2022-11-04 19:16:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, N'已过期', N'3', N'promotion_coupon_status', 0, N'info', N'', N'优惠劵的状态 - 已过期', N'1', N'2022-11-04 00:15:43', N'1', N'2022-11-04 19:16:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, N'直接领取', N'1', N'promotion_coupon_take_type', 0, N'primary', N'', N'优惠劵的领取方式 - 直接领取', N'1', N'2022-11-04 19:13:00', N'1', N'2022-11-04 19:13:25', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, N'指定发放', N'2', N'promotion_coupon_take_type', 0, N'success', N'', N'优惠劵的领取方式 - 指定发放', N'1', N'2022-11-04 19:13:13', N'1', N'2022-11-04 19:14:48', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, N'未开始', N'10', N'promotion_activity_status', 0, N'primary', N'', N'促销活动的状态枚举 - 未开始', N'1', N'2022-11-04 22:54:49', N'1', N'2022-11-04 22:55:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, N'进行中', N'20', N'promotion_activity_status', 0, N'success', N'', N'促销活动的状态枚举 - 进行中', N'1', N'2022-11-04 22:55:06', N'1', N'2022-11-04 22:55:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, N'已结束', N'30', N'promotion_activity_status', 0, N'info', N'', N'促销活动的状态枚举 - 已结束', N'1', N'2022-11-04 22:55:41', N'1', N'2022-11-04 22:55:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, N'已关闭', N'40', N'promotion_activity_status', 0, N'warning', N'', N'促销活动的状态枚举 - 已关闭', N'1', N'2022-11-04 22:56:10', N'1', N'2022-11-04 22:56:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, N'满 N 元', N'10', N'promotion_condition_type', 0, N'primary', N'', N'营销的条件类型 - 满 N 元', N'1', N'2022-11-04 22:59:45', N'1', N'2022-11-04 22:59:45', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, N'满 N 件', N'20', N'promotion_condition_type', 0, N'success', N'', N'营销的条件类型 - 满 N 件', N'1', N'2022-11-04 23:00:02', N'1', N'2022-11-04 23:00:02', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, N'申请售后', N'10', N'trade_after_sale_status', 0, N'primary', N'', N'交易售后状态 - 申请售后', N'1', N'2022-11-19 20:53:33', N'1', N'2022-11-19 20:54:42', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, N'商品待退货', N'20', N'trade_after_sale_status', 0, N'primary', N'', N'交易售后状态 - 商品待退货', N'1', N'2022-11-19 20:54:36', N'1', N'2022-11-19 20:58:58', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, N'商家待收货', N'30', N'trade_after_sale_status', 0, N'primary', N'', N'交易售后状态 - 商家待收货', N'1', N'2022-11-19 20:56:56', N'1', N'2022-11-19 20:59:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, N'等待退款', N'40', N'trade_after_sale_status', 0, N'primary', N'', N'交易售后状态 - 等待退款', N'1', N'2022-11-19 20:59:54', N'1', N'2022-11-19 21:00:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, N'退款成功', N'50', N'trade_after_sale_status', 0, N'default', N'', N'交易售后状态 - 退款成功', N'1', N'2022-11-19 21:00:33', N'1', N'2022-11-19 21:00:33', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, N'买家取消', N'61', N'trade_after_sale_status', 0, N'info', N'', N'交易售后状态 - 买家取消', N'1', N'2022-11-19 21:01:29', N'1', N'2022-11-19 21:01:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, N'商家拒绝', N'62', N'trade_after_sale_status', 0, N'info', N'', N'交易售后状态 - 商家拒绝', N'1', N'2022-11-19 21:02:17', N'1', N'2022-11-19 21:02:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, N'商家拒收货', N'63', N'trade_after_sale_status', 0, N'info', N'', N'交易售后状态 - 商家拒收货', N'1', N'2022-11-19 21:02:37', N'1', N'2022-11-19 21:03:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, N'售中退款', N'10', N'trade_after_sale_type', 0, N'success', N'', N'交易售后的类型 - 售中退款', N'1', N'2022-11-19 21:05:05', N'1', N'2022-11-19 21:38:23', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, N'售后退款', N'20', N'trade_after_sale_type', 0, N'primary', N'', N'交易售后的类型 - 售后退款', N'1', N'2022-11-19 21:05:32', N'1', N'2022-11-19 21:38:32', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, N'仅退款', N'10', N'trade_after_sale_way', 0, N'primary', N'', N'交易售后的方式 - 仅退款', N'1', N'2022-11-19 21:39:19', N'1', N'2022-11-19 21:39:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, N'退货退款', N'20', N'trade_after_sale_way', 0, N'success', N'', N'交易售后的方式 - 退货退款', N'1', N'2022-11-19 21:39:38', N'1', N'2022-11-19 21:39:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, N'微信小程序', N'10', N'terminal', 0, N'default', N'', N'终端 - 微信小程序', N'1', N'2022-12-10 10:51:11', N'1', N'2022-12-10 10:51:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, N'H5 网页', N'20', N'terminal', 0, N'default', N'', N'终端 - H5 网页', N'1', N'2022-12-10 10:51:30', N'1', N'2022-12-10 10:51:59', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, N'微信公众号', N'11', N'terminal', 0, N'default', N'', N'终端 - 微信公众号', N'1', N'2022-12-10 10:54:16', N'1', N'2022-12-10 10:52:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, N'苹果 App', N'31', N'terminal', 0, N'default', N'', N'终端 - 苹果 App', N'1', N'2022-12-10 10:54:42', N'1', N'2022-12-10 10:52:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, N'安卓 App', N'32', N'terminal', 0, N'default', N'', N'终端 - 安卓 App', N'1', N'2022-12-10 10:55:02', N'1', N'2022-12-10 10:59:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, N'普通订单', N'0', N'trade_order_type', 0, N'default', N'', N'交易订单的类型 - 普通订单', N'1', N'2022-12-10 16:34:14', N'1', N'2022-12-10 16:34:14', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, N'秒杀订单', N'1', N'trade_order_type', 0, N'default', N'', N'交易订单的类型 - 秒杀订单', N'1', N'2022-12-10 16:34:26', N'1', N'2022-12-10 16:34:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, N'拼团订单', N'2', N'trade_order_type', 0, N'default', N'', N'交易订单的类型 - 拼团订单', N'1', N'2022-12-10 16:34:36', N'1', N'2022-12-10 16:34:36', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, N'砍价订单', N'3', N'trade_order_type', 0, N'default', N'', N'交易订单的类型 - 砍价订单', N'1', N'2022-12-10 16:34:48', N'1', N'2022-12-10 16:34:48', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, N'待支付', N'0', N'trade_order_status', 0, N'default', N'', N'交易订单状态 - 待支付', N'1', N'2022-12-10 16:49:29', N'1', N'2022-12-10 16:49:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, N'待发货', N'10', N'trade_order_status', 0, N'primary', N'', N'交易订单状态 - 待发货', N'1', N'2022-12-10 16:49:53', N'1', N'2022-12-10 16:51:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, N'已发货', N'20', N'trade_order_status', 0, N'primary', N'', N'交易订单状态 - 已发货', N'1', N'2022-12-10 16:50:13', N'1', N'2022-12-10 16:51:31', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, N'已完成', N'30', N'trade_order_status', 0, N'success', N'', N'交易订单状态 - 已完成', N'1', N'2022-12-10 16:50:30', N'1', N'2022-12-10 16:51:06', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, N'已取消', N'40', N'trade_order_status', 0, N'danger', N'', N'交易订单状态 - 已取消', N'1', N'2022-12-10 16:50:50', N'1', N'2022-12-10 16:51:00', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, N'未售后', N'0', N'trade_order_item_after_sale_status', 0, N'info', N'', N'交易订单项的售后状态 - 未售后', N'1', N'2022-12-10 20:58:42', N'1', N'2022-12-10 20:59:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 1, N'售后中', N'1', N'trade_order_item_after_sale_status', 0, N'primary', N'', N'交易订单项的售后状态 - 售后中', N'1', N'2022-12-10 20:59:21', N'1', N'2022-12-10 20:59:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 2, N'已退款', N'2', N'trade_order_item_after_sale_status', 0, N'success', N'', N'交易订单项的售后状态 - 已退款', N'1', N'2022-12-10 20:59:46', N'1', N'2022-12-10 20:59:46', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, N'完全匹配', N'1', N'mp_auto_reply_request_match', 0, N'primary', N'', N'公众号自动回复的请求关键字匹配模式 - 完全匹配', N'1', N'2023-01-16 23:30:39', N'1', N'2023-01-16 23:31:00', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, N'半匹配', N'2', N'mp_auto_reply_request_match', 0, N'success', N'', N'公众号自动回复的请求关键字匹配模式 - 半匹配', N'1', N'2023-01-16 23:30:55', N'1', N'2023-01-16 23:31:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, N'文本', N'text', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 文本', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 22:17:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, N'图片', N'image', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 图片', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:19:47', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, N'语音', N'voice', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 语音', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:20:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, N'视频', N'video', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 视频', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:21:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, N'小视频', N'shortvideo', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 小视频', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:19:59', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, N'图文', N'news', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 图文', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:22:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, N'音乐', N'music', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 音乐', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:22:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, N'地理位置', N'location', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 地理位置', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:23:51', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, N'链接', N'link', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 链接', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:24:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, N'事件', N'event', N'mp_message_type', 0, N'default', N'', N'公众号的消息类型 - 事件', N'1', N'2023-01-17 22:17:32', N'1', N'2023-01-17 14:24:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, N'初始化', N'0', N'system_mail_send_status', 0, N'primary', N'', N'邮件发送状态 - 初始化\n', N'1', N'2023-01-26 09:53:49', N'1', N'2023-01-26 16:36:14', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, N'发送成功', N'10', N'system_mail_send_status', 0, N'success', N'', N'邮件发送状态 - 发送成功', N'1', N'2023-01-26 09:54:28', N'1', N'2023-01-26 16:36:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, N'发送失败', N'20', N'system_mail_send_status', 0, N'danger', N'', N'邮件发送状态 - 发送失败', N'1', N'2023-01-26 09:54:50', N'1', N'2023-01-26 16:36:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, N'不发送', N'30', N'system_mail_send_status', 0, N'info', N'', N'邮件发送状态 - 不发送', N'1', N'2023-01-26 09:55:06', N'1', N'2023-01-26 16:36:36', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, N'通知公告', N'1', N'system_notify_template_type', 0, N'primary', N'', N'站内信模版的类型 - 通知公告', N'1', N'2023-01-28 10:35:59', N'1', N'2023-01-28 10:35:59', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, N'系统消息', N'2', N'system_notify_template_type', 0, N'success', N'', N'站内信模版的类型 - 系统消息', N'1', N'2023-01-28 10:36:20', N'1', N'2023-01-28 10:36:25', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, N'支付宝条码支付', N'alipay_bar', N'pay_channel_code', 0, N'primary', N'', N'支付宝条码支付', N'1', N'2023-02-18 23:32:24', N'1', N'2023-07-19 20:09:23', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, N'Vue2 Element UI 标准模版', N'10', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2023-04-13 00:03:55', N'1', N'2023-04-13 00:03:55', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, N'Vue3 Element Plus 标准模版', N'20', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2023-04-13 00:04:08', N'1', N'2023-04-13 00:04:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1233, 21, N'Vue3 Element Plus Schema 模版', N'21', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2023-04-13 00:04:26', N'1', N'2023-04-13 00:04:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, N'Vue3 vben 模版', N'30', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2023-04-13 00:04:26', N'1', N'2023-04-13 00:04:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, N'按件', N'1', N'trade_delivery_express_charge_mode', 0, N'', N'', N'', N'1', N'2023-05-21 22:46:40', N'1', N'2023-05-21 22:46:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, N'按重量', N'2', N'trade_delivery_express_charge_mode', 0, N'', N'', N'', N'1', N'2023-05-21 22:46:58', N'1', N'2023-05-21 22:46:58', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, N'按体积', N'3', N'trade_delivery_express_charge_mode', 0, N'', N'', N'', N'1', N'2023-05-21 22:47:18', N'1', N'2023-05-21 22:47:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, N'订单积分抵扣', N'11', N'member_point_biz_type', 0, N'', N'', N'', N'1', N'2023-06-10 12:15:27', N'1', N'2023-10-11 07:41:43', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, N'签到', N'1', N'member_point_biz_type', 0, N'', N'', N'', N'1', N'2023-06-10 12:15:48', N'1', N'2023-08-20 11:59:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, N'已退款', N'20', N'pay_order_status', 0, N'danger', N'', N'已退款', N'1', N'2023-07-19 18:05:37', N'1', N'2023-07-19 18:05:37', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, N'请求成功,但是结果失败', N'21', N'pay_notify_status', 0, N'warning', N'', N'请求成功,但是结果失败', N'1', N'2023-07-19 18:10:47', N'1', N'2023-07-19 18:11:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, N'请求失败', N'22', N'pay_notify_status', 0, N'warning', N'', NULL, N'1', N'2023-07-19 18:11:05', N'1', N'2023-07-19 18:11:27', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, N'微信扫码支付', N'wx_native', N'pay_channel_code', 0, N'success', N'', N'微信扫码支付', N'1', N'2023-07-19 20:07:47', N'1', N'2023-07-19 20:09:03', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, N'微信条码支付', N'wx_bar', N'pay_channel_code', 0, N'success', N'', N'微信条码支付\n', N'1', N'2023-07-19 20:08:06', N'1', N'2023-07-19 20:09:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, N'支付单', N'1', N'pay_notify_type', 0, N'primary', N'', N'支付单', N'1', N'2023-07-20 12:23:17', N'1', N'2023-07-20 12:23:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, N'退款单', N'2', N'pay_notify_type', 0, N'danger', N'', NULL, N'1', N'2023-07-20 12:23:26', N'1', N'2023-07-20 12:23:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, N'模拟支付', N'mock', N'pay_channel_code', 0, N'default', N'', N'模拟支付', N'1', N'2023-07-29 11:10:51', N'1', N'2023-07-29 03:14:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, N'订单积分抵扣(整单取消)', N'12', N'member_point_biz_type', 0, N'', N'', N'', N'1', N'2023-08-20 12:00:03', N'1', N'2023-10-11 07:42:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, N'管理员调整', N'0', N'member_experience_biz_type', 0, N'', N'', NULL, N'', N'2023-08-22 12:41:01', N'', N'2023-08-22 12:41:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, N'邀新奖励', N'1', N'member_experience_biz_type', 0, N'', N'', NULL, N'', N'2023-08-22 12:41:01', N'', N'2023-08-22 12:41:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, N'下单奖励', N'11', N'member_experience_biz_type', 0, N'success', N'', NULL, N'', N'2023-08-22 12:41:01', N'1', N'2023-10-11 07:45:09', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, N'下单奖励(整单取消)', N'12', N'member_experience_biz_type', 0, N'warning', N'', NULL, N'', N'2023-08-22 12:41:01', N'1', N'2023-10-11 07:45:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, N'签到奖励', N'4', N'member_experience_biz_type', 0, N'', N'', NULL, N'', N'2023-08-22 12:41:01', N'', N'2023-08-22 12:41:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, N'抽奖奖励', N'5', N'member_experience_biz_type', 0, N'', N'', NULL, N'', N'2023-08-22 12:41:01', N'', N'2023-08-22 12:41:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, N'快递发货', N'1', N'trade_delivery_type', 0, N'', N'', N'', N'1', N'2023-08-23 00:04:55', N'1', N'2023-08-23 00:04:55', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, N'用户自提', N'2', N'trade_delivery_type', 0, N'', N'', N'', N'1', N'2023-08-23 00:05:05', N'1', N'2023-08-23 00:05:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, N'品类劵', N'3', N'promotion_product_scope', 0, N'default', N'', N'', N'1', N'2023-09-01 23:43:07', N'1', N'2023-09-28 00:27:47', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, N'人人分销', N'1', N'brokerage_enabled_condition', 0, N'', N'', N'所有用户都可以分销', N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, N'指定分销', N'2', N'brokerage_enabled_condition', 0, N'', N'', N'仅可后台手动设置推广员', N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, N'首次绑定', N'1', N'brokerage_bind_mode', 0, N'', N'', N'只要用户没有推广人,随时都可以绑定推广关系', N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, N'注册绑定', N'2', N'brokerage_bind_mode', 0, N'', N'', N'仅新用户注册时才能绑定推广关系', N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, N'覆盖绑定', N'3', N'brokerage_bind_mode', 0, N'', N'', N'如果用户已经有推广人,推广人会被变更', N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, N'钱包', N'1', N'brokerage_withdraw_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, N'银行卡', N'2', N'brokerage_withdraw_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, N'微信', N'3', N'brokerage_withdraw_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, N'支付宝', N'4', N'brokerage_withdraw_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, N'订单返佣', N'1', N'brokerage_record_biz_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, N'申请提现', N'2', N'brokerage_record_biz_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, N'申请提现驳回', N'3', N'brokerage_record_biz_type', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, N'待结算', N'0', N'brokerage_record_status', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, N'已结算', N'1', N'brokerage_record_status', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, N'已取消', N'2', N'brokerage_record_status', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, N'审核中', N'0', N'brokerage_withdraw_status', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, N'审核通过', N'10', N'brokerage_withdraw_status', 0, N'success', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, N'提现成功', N'11', N'brokerage_withdraw_status', 0, N'success', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, N'审核不通过', N'20', N'brokerage_withdraw_status', 0, N'danger', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, N'提现失败', N'21', N'brokerage_withdraw_status', 0, N'danger', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, N'工商银行', N'0', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, N'建设银行', N'1', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, N'农业银行', N'2', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, N'中国银行', N'3', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, N'交通银行', N'4', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, N'招商银行', N'5', N'brokerage_bank_name', 0, N'', N'', NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, N'钱包', N'wallet', N'pay_channel_code', 0, N'primary', N'', N'', N'1', N'2023-10-01 21:46:19', N'1', N'2023-10-01 21:48:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, N'砍价中', N'1', N'promotion_bargain_record_status', 0, N'default', N'', N'', N'1', N'2023-10-05 10:41:26', N'1', N'2023-10-05 10:41:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, N'砍价成功', N'2', N'promotion_bargain_record_status', 0, N'success', N'', N'', N'1', N'2023-10-05 10:41:39', N'1', N'2023-10-05 10:41:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, N'砍价失败', N'3', N'promotion_bargain_record_status', 0, N'warning', N'', N'', N'1', N'2023-10-05 10:41:57', N'1', N'2023-10-05 10:41:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 1, N'拼团中', N'1', N'promotion_combination_record_status', 0, N'', N'', N'', N'1', N'2023-10-08 07:24:44', N'1', N'2023-10-08 07:24:44', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 2, N'拼团成功', N'2', N'promotion_combination_record_status', 0, N'success', N'', N'', N'1', N'2023-10-08 07:24:56', N'1', N'2023-10-08 07:24:56', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 3, N'拼团失败', N'3', N'promotion_combination_record_status', 0, N'warning', N'', N'', N'1', N'2023-10-08 07:25:11', N'1', N'2023-10-08 07:25:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, N'管理员修改', N'2', N'member_point_biz_type', 0, N'default', N'', N'', N'1', N'2023-10-11 07:41:34', N'1', N'2023-10-11 07:41:34', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, N'订单积分抵扣(单个退款)', N'13', N'member_point_biz_type', 0, N'', N'', N'', N'1', N'2023-10-11 07:42:29', N'1', N'2023-10-11 07:42:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, N'订单积分奖励', N'21', N'member_point_biz_type', 0, N'default', N'', N'', N'1', N'2023-10-11 07:42:44', N'1', N'2023-10-11 07:42:44', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, N'订单积分奖励(整单取消)', N'22', N'member_point_biz_type', 0, N'default', N'', N'', N'1', N'2023-10-11 07:42:55', N'1', N'2023-10-11 07:43:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, N'订单积分奖励(单个退款)', N'23', N'member_point_biz_type', 0, N'default', N'', N'', N'1', N'2023-10-11 07:43:16', N'1', N'2023-10-11 07:43:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, N'下单奖励(单个退款)', N'13', N'member_experience_biz_type', 0, N'warning', N'', N'', N'1', N'2023-10-11 07:45:24', N'1', N'2023-10-11 07:45:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, N'网上转账', N'5', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:55:24', N'1', N'2023-10-18 21:55:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, N'支付宝', N'6', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:55:38', N'1', N'2023-10-18 21:55:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, N'微信支付', N'7', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:55:53', N'1', N'2023-10-18 21:55:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, N'其他', N'8', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:56:06', N'1', N'2023-10-18 21:56:06', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, N'IT', N'1', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:02:15', N'1', N'2024-02-18 23:30:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, N'金融业', N'2', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:02:29', N'1', N'2024-02-18 23:30:43', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, N'房地产', N'3', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:02:41', N'1', N'2024-02-18 23:30:48', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, N'商业服务', N'4', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:02:54', N'1', N'2024-02-18 23:30:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, N'运输/物流', N'5', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:03:03', N'1', N'2024-02-18 23:31:00', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, N'生产', N'6', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:03:13', N'1', N'2024-02-18 23:31:08', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, N'政府', N'7', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:03:27', N'1', N'2024-02-18 23:31:13', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, N'文化传媒', N'8', N'crm_customer_industry', 0, N'default', N'', N'', N'1', N'2023-10-28 23:03:37', N'1', N'2024-02-18 23:31:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, N'A (重点客户)', N'1', N'crm_customer_level', 0, N'primary', N'', N'', N'1', N'2023-10-28 23:07:13', N'1', N'2023-10-28 23:07:13', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, N'B (普通客户)', N'2', N'crm_customer_level', 0, N'info', N'', N'', N'1', N'2023-10-28 23:07:35', N'1', N'2023-10-28 23:07:35', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, N'C (非优先客户)', N'3', N'crm_customer_level', 0, N'default', N'', N'', N'1', N'2023-10-28 23:07:53', N'1', N'2023-10-28 23:07:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, N'促销', N'1', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:08:29', N'1', N'2023-10-28 23:08:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, N'搜索引擎', N'2', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:08:39', N'1', N'2023-10-28 23:08:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, N'广告', N'3', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:08:47', N'1', N'2023-10-28 23:08:47', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, N'转介绍', N'4', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:08:58', N'1', N'2023-10-28 23:08:58', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, N'线上注册', N'5', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:09:12', N'1', N'2023-10-28 23:09:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, N'线上咨询', N'6', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:09:22', N'1', N'2023-10-28 23:09:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, N'预约上门', N'7', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:09:39', N'1', N'2023-10-28 23:09:39', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, N'陌拜', N'8', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:10:04', N'1', N'2023-10-28 23:10:04', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, N'电话咨询', N'9', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:10:18', N'1', N'2023-10-28 23:10:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, N'邮件咨询', N'10', N'crm_customer_source', 0, N'default', N'', N'', N'1', N'2023-10-28 23:10:33', N'1', N'2023-10-28 23:10:33', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, N'Gitee', N'10', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:04:42', N'1', N'2023-11-04 13:04:42', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, N'钉钉', N'20', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:04:54', N'1', N'2023-11-04 13:04:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, N'企业微信', N'30', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:09', N'1', N'2023-11-04 13:05:09', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, N'微信公众平台', N'31', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:18', N'1', N'2023-11-04 13:05:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, N'微信开放平台', N'32', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:30', N'1', N'2023-11-04 13:05:30', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, N'微信小程序', N'34', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:38', N'1', N'2023-11-04 13:07:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, N'上架', N'1', N'crm_product_status', 0, N'success', N'', N'', N'1', N'2023-10-30 21:49:34', N'1', N'2023-10-30 21:49:34', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, N'下架', N'0', N'crm_product_status', 0, N'success', N'', N'', N'1', N'2023-10-30 21:49:13', N'1', N'2023-10-30 21:49:13', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, N'子表', N'15', N'infra_codegen_template_type', 0, N'default', N'', N'', N'1', N'2023-11-13 23:06:16', N'1', N'2023-11-13 23:06:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, N'主表(标准模式)', N'10', N'infra_codegen_template_type', 0, N'default', N'', N'', N'1', N'2023-11-14 12:32:49', N'1', N'2023-11-14 12:32:49', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, N'主表(ERP 模式)', N'11', N'infra_codegen_template_type', 0, N'default', N'', N'', N'1', N'2023-11-14 12:33:05', N'1', N'2023-11-14 12:33:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, N'主表(内嵌模式)', N'12', N'infra_codegen_template_type', 0, N'', N'', N'', N'1', N'2023-11-14 12:33:31', N'1', N'2023-11-14 12:33:31', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, N'负责人', N'1', N'crm_permission_level', 0, N'default', N'', N'', N'1', N'2023-11-30 09:53:12', N'1', N'2023-11-30 09:53:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, N'只读', N'2', N'crm_permission_level', 0, N'', N'', N'', N'1', N'2023-11-30 09:53:29', N'1', N'2023-11-30 09:53:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, N'读写', N'3', N'crm_permission_level', 0, N'', N'', N'', N'1', N'2023-11-30 09:53:36', N'1', N'2023-11-30 09:53:36', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, N'未提交', N'0', N'crm_audit_status', 0, N'', N'', N'', N'1', N'2023-11-30 18:56:59', N'1', N'2023-11-30 18:56:59', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, N'审批中', N'10', N'crm_audit_status', 0, N'', N'', N'', N'1', N'2023-11-30 18:57:10', N'1', N'2023-11-30 18:57:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, N'审核通过', N'20', N'crm_audit_status', 0, N'', N'', N'', N'1', N'2023-11-30 18:57:24', N'1', N'2023-11-30 18:57:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, N'审核不通过', N'30', N'crm_audit_status', 0, N'', N'', N'', N'1', N'2023-11-30 18:57:32', N'1', N'2023-11-30 18:57:32', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, N'已取消', N'40', N'crm_audit_status', 0, N'', N'', N'', N'1', N'2023-11-30 18:57:42', N'1', N'2023-11-30 18:57:42', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, N'支票', N'1', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:54:29', N'1', N'2023-10-18 21:54:29', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, N'现金', N'2', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:54:41', N'1', N'2023-10-18 21:54:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, N'邮政汇款', N'3', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:54:53', N'1', N'2023-10-18 21:54:53', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, N'电汇', N'4', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:55:07', N'1', N'2023-10-18 21:55:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1460, 5, N'网上转账', N'5', N'crm_receivable_return_type', 0, N'default', N'', N'', N'1', N'2023-10-18 21:55:24', N'1', N'2023-10-18 21:55:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, N'个', N'1', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:02:26', N'1', N'2023-12-05 23:02:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, N'块', N'2', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:02:34', N'1', N'2023-12-05 23:02:34', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, N'只', N'3', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:02:57', N'1', N'2023-12-05 23:02:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, N'把', N'4', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:05', N'1', N'2023-12-05 23:03:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, N'枚', N'5', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:14', N'1', N'2023-12-05 23:03:14', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, N'瓶', N'6', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:20', N'1', N'2023-12-05 23:03:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, N'盒', N'7', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:30', N'1', N'2023-12-05 23:03:30', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, N'台', N'8', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:41', N'1', N'2023-12-05 23:03:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, N'吨', N'9', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:03:48', N'1', N'2023-12-05 23:03:48', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, N'千克', N'10', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:04:03', N'1', N'2023-12-05 23:04:03', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, N'米', N'11', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:04:12', N'1', N'2023-12-05 23:04:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, N'箱', N'12', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:04:25', N'1', N'2023-12-05 23:04:25', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, N'套', N'13', N'crm_product_unit', 0, N'', N'', N'', N'1', N'2023-12-05 23:04:34', N'1', N'2023-12-05 23:04:34', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, N'打电话', N'1', N'crm_follow_up_type', 0, N'', N'', N'', N'1', N'2024-01-15 20:48:20', N'1', N'2024-01-15 20:48:20', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, N'发短信', N'2', N'crm_follow_up_type', 0, N'', N'', N'', N'1', N'2024-01-15 20:48:31', N'1', N'2024-01-15 20:48:31', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, N'上门拜访', N'3', N'crm_follow_up_type', 0, N'', N'', N'', N'1', N'2024-01-15 20:49:07', N'1', N'2024-01-15 20:49:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, N'微信沟通', N'4', N'crm_follow_up_type', 0, N'', N'', N'', N'1', N'2024-01-15 20:49:15', N'1', N'2024-01-15 20:49:15', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1478, 4, N'钱包余额', N'4', N'pay_transfer_type', 0, N'info', N'', N'', N'1', N'2023-10-28 16:28:37', N'1', N'2023-10-28 16:28:37', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1479, 3, N'银行卡', N'3', N'pay_transfer_type', 0, N'default', N'', N'', N'1', N'2023-10-28 16:28:21', N'1', N'2023-10-28 16:28:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1480, 2, N'微信余额', N'2', N'pay_transfer_type', 0, N'info', N'', N'', N'1', N'2023-10-28 16:28:07', N'1', N'2023-10-28 16:28:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1481, 1, N'支付宝余额', N'1', N'pay_transfer_type', 0, N'default', N'', N'', N'1', N'2023-10-28 16:27:44', N'1', N'2023-10-28 16:27:44', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, N'转账失败', N'30', N'pay_transfer_status', 0, N'warning', N'', N'', N'1', N'2023-10-28 16:24:16', N'1', N'2023-10-28 16:24:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, N'转账成功', N'20', N'pay_transfer_status', 0, N'success', N'', N'', N'1', N'2023-10-28 16:23:50', N'1', N'2023-10-28 16:23:50', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, N'转账进行中', N'10', N'pay_transfer_status', 0, N'info', N'', N'', N'1', N'2023-10-28 16:23:12', N'1', N'2023-10-28 16:23:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, N'等待转账', N'0', N'pay_transfer_status', 0, N'default', N'', N'', N'1', N'2023-10-28 16:21:43', N'1', N'2023-10-28 16:23:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, N'其它入库', N'10', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-05 18:07:25', N'1', N'2024-02-05 18:07:43', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, N'其它入库(作废)', N'11', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-05 18:08:07', N'1', N'2024-02-05 19:20:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, N'其它出库', N'20', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-05 18:08:51', N'1', N'2024-02-05 18:08:51', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, N'其它出库(作废)', N'21', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-05 18:09:00', N'1', N'2024-02-05 19:20:10', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, N'未审核', N'10', N'erp_audit_status', 0, N'default', N'', N'', N'1', N'2024-02-06 00:00:21', N'1', N'2024-02-06 00:00:21', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, N'已审核', N'20', N'erp_audit_status', 0, N'success', N'', N'', N'1', N'2024-02-06 00:00:35', N'1', N'2024-02-06 00:00:35', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, N'调拨入库', N'30', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-07 20:34:19', N'1', N'2024-02-07 12:36:31', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, N'调拨入库(作废)', N'31', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-07 20:34:29', N'1', N'2024-02-07 20:37:11', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, N'调拨出库', N'32', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-07 20:34:38', N'1', N'2024-02-07 12:36:33', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, N'调拨出库(作废)', N'33', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-07 20:34:49', N'1', N'2024-02-07 20:37:06', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, N'盘盈入库', N'40', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-08 08:53:00', N'1', N'2024-02-08 08:53:09', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, N'盘盈入库(作废)', N'41', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-08 08:53:39', N'1', N'2024-02-16 19:40:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, N'盘亏出库', N'42', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-08 08:54:16', N'1', N'2024-02-08 08:54:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, N'盘亏出库(作废)', N'43', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-08 08:54:31', N'1', N'2024-02-16 19:40:46', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, N'销售出库', N'50', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-11 21:47:25', N'1', N'2024-02-11 21:50:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, N'销售出库(作废)', N'51', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-11 21:47:37', N'1', N'2024-02-11 21:51:12', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, N'销售退货入库', N'60', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-12 06:51:05', N'1', N'2024-02-12 06:51:05', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, N'销售退货入库(作废)', N'61', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-12 06:51:18', N'1', N'2024-02-12 06:51:18', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, N'采购入库', N'70', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-16 13:10:02', N'1', N'2024-02-16 13:10:02', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, N'采购入库(作废)', N'71', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-16 13:10:10', N'1', N'2024-02-16 19:40:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, N'采购退货出库', N'80', N'erp_stock_record_biz_type', 0, N'', N'', N'', N'1', N'2024-02-16 13:10:17', N'1', N'2024-02-16 13:10:17', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, N'采购退货出库(作废)', N'81', N'erp_stock_record_biz_type', 0, N'danger', N'', N'', N'1', N'2024-02-16 13:10:26', N'1', N'2024-02-16 19:40:33', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, N'审批不通过', N'3', N'bpm_process_instance_status', 0, N'danger', N'', N'', N'1', N'2024-03-16 16:12:06', N'1', N'2024-03-16 16:12:06', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, N'已取消', N'4', N'bpm_process_instance_status', 0, N'warning', N'', N'', N'1', N'2024-03-16 16:12:22', N'1', N'2024-03-16 16:12:22', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, N'已退回', N'5', N'bpm_task_status', 0, N'warning', N'', N'', N'1', N'2024-03-16 19:10:46', N'1', N'2024-03-08 22:41:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, N'委派中', N'6', N'bpm_task_status', 0, N'primary', N'', N'', N'1', N'2024-03-17 10:06:22', N'1', N'2024-03-08 22:41:40', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, N'审批通过中', N'7', N'bpm_task_status', 0, N'success', N'', N'', N'1', N'2024-03-17 10:06:47', N'1', N'2024-03-08 22:41:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, N'待审批', N'0', N'bpm_task_status', 0, N'info', N'', N'', N'1', N'2024-03-17 10:07:11', N'1', N'2024-03-08 22:41:42', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, N'发起人自选', N'35', N'bpm_task_candidate_strategy', 0, N'', N'', N'', N'1', N'2024-03-22 19:45:16', N'1', N'2024-03-22 19:45:16', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, N'执行监听器', N'execution', N'bpm_process_listener_type', 0, N'primary', N'', N'', N'1', N'2024-03-23 12:54:03', N'1', N'2024-03-23 19:14:19', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, N'任务监听器', N'task', N'bpm_process_listener_type', 0, N'success', N'', N'', N'1', N'2024-03-23 12:54:13', N'1', N'2024-03-23 19:14:24', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, N'Java 类', N'class', N'bpm_process_listener_value_type', 0, N'primary', N'', N'', N'1', N'2024-03-23 15:08:45', N'1', N'2024-03-23 19:14:32', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, N'表达式', N'expression', N'bpm_process_listener_value_type', 0, N'success', N'', N'', N'1', N'2024-03-23 15:09:06', N'1', N'2024-03-23 19:14:38', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, N'代理表达式', N'delegateExpression', N'bpm_process_listener_value_type', 0, N'info', N'', N'', N'1', N'2024-03-23 15:11:23', N'1', N'2024-03-23 19:14:41', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, N'天', N'1', N'date_interval', 0, N'', N'', N'', N'1', N'2024-03-29 22:50:26', N'1', N'2024-03-29 22:50:26', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, N'周', N'2', N'date_interval', 0, N'', N'', N'', N'1', N'2024-03-29 22:50:36', N'1', N'2024-03-29 22:50:36', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, N'月', N'3', N'date_interval', 0, N'', N'', N'', N'1', N'2024-03-29 22:50:46', N'1', N'2024-03-29 22:50:54', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, N'季度', N'4', N'date_interval', 0, N'', N'', N'', N'1', N'2024-03-29 22:51:01', N'1', N'2024-03-29 22:51:01', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, N'年', N'5', N'date_interval', 0, N'', N'', N'', N'1', N'2024-03-29 22:51:07', N'1', N'2024-03-29 22:51:07', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, N'赢单', N'1', N'crm_business_end_status_type', 0, N'success', N'', N'', N'1', N'2024-04-13 23:26:57', N'1', N'2024-04-13 23:26:57', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, N'输单', N'2', N'crm_business_end_status_type', 0, N'primary', N'', N'', N'1', N'2024-04-13 23:27:31', N'1', N'2024-04-13 23:27:31', N'0') +GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, N'无效', N'3', N'crm_business_end_status_type', 0, N'info', N'', N'', N'1', N'2024-04-13 23:27:59', N'1', N'2024-04-13 23:27:59', N'0') +GO +SET IDENTITY_INSERT system_dict_data OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS system_dict_type +GO +CREATE TABLE system_dict_type +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(100) DEFAULT '' NOT NULL, + type nvarchar(100) DEFAULT '' NOT NULL, + status tinyint DEFAULT 0 NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + deleted_time datetime2 DEFAULT NULL NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典主键', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type', + 'COLUMN', N'deleted_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'字典类型表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_dict_type' +GO + +-- ---------------------------- +-- Records of system_dict_type +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_dict_type ON +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, N'用户性别', N'system_user_sex', 0, NULL, N'admin', N'2021-01-05 17:03:48', N'1', N'2022-05-16 20:29:32', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, N'参数类型', N'infra_config_type', 0, NULL, N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:36:54', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, N'通知类型', N'system_notice_type', 0, NULL, N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:35:26', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, N'操作类型', N'infra_operate_type', 0, NULL, N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-14 12:44:01', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, N'系统状态', N'common_status', 0, NULL, N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-01 16:21:28', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, N'Boolean 是否类型', N'infra_boolean_string', 0, N'boolean 转是否', N'', N'2021-01-19 03:20:08', N'', N'2022-02-01 16:37:10', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, N'登陆结果', N'system_login_result', 0, N'登陆结果', N'', N'2021-01-18 06:17:11', N'', N'2022-02-01 16:36:00', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, N'代码生成模板类型', N'infra_codegen_template_type', 0, NULL, N'', N'2021-02-05 07:08:06', N'1', N'2022-05-16 20:26:50', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, N'定时任务状态', N'infra_job_status', 0, NULL, N'', N'2021-02-07 07:44:16', N'', N'2022-02-01 16:51:11', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, N'定时任务日志状态', N'infra_job_log_status', 0, NULL, N'', N'2021-02-08 10:03:51', N'', N'2022-02-01 16:50:43', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, N'用户类型', N'user_type', 0, NULL, N'', N'2021-02-26 00:15:51', N'', N'2021-02-26 00:15:51', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, N'API 异常数据的处理状态', N'infra_api_error_log_process_status', 0, NULL, N'', N'2021-02-26 07:07:01', N'', N'2022-02-01 16:50:53', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, N'短信渠道编码', N'system_sms_channel_code', 0, NULL, N'1', N'2021-04-05 01:04:50', N'1', N'2022-02-16 02:09:08', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, N'短信模板的类型', N'system_sms_template_type', 0, NULL, N'1', N'2021-04-05 21:50:43', N'1', N'2022-02-01 16:35:06', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, N'短信发送状态', N'system_sms_send_status', 0, NULL, N'1', N'2021-04-11 20:18:03', N'1', N'2022-02-01 16:35:09', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, N'短信接收状态', N'system_sms_receive_status', 0, NULL, N'1', N'2021-04-11 20:27:14', N'1', N'2022-02-01 16:35:14', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, N'登陆日志的类型', N'system_login_type', 0, N'登陆日志的类型', N'1', N'2021-10-06 00:50:46', N'1', N'2022-02-01 16:35:56', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, N'OA 请假类型', N'bpm_oa_leave_type', 0, NULL, N'1', N'2021-09-21 22:34:33', N'1', N'2022-01-22 10:41:37', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, N'支付渠道编码类型', N'pay_channel_code', 0, N'支付渠道的编码', N'1', N'2021-12-03 10:35:08', N'1', N'2023-07-10 10:11:39', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, N'支付回调状态', N'pay_notify_status', 0, N'支付回调状态(包括退款回调)', N'1', N'2021-12-03 10:53:29', N'1', N'2023-07-19 18:09:43', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, N'支付订单状态', N'pay_order_status', 0, N'支付订单状态', N'1', N'2021-12-03 11:17:50', N'1', N'2021-12-03 11:17:50', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, N'退款订单状态', N'pay_refund_status', 0, N'退款订单状态', N'1', N'2021-12-10 16:42:50', N'1', N'2023-07-19 10:13:17', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, N'流程实例的状态', N'bpm_process_instance_status', 0, N'流程实例的状态', N'1', N'2022-01-07 23:46:42', N'1', N'2022-01-07 23:46:42', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, N'流程实例的结果', N'bpm_task_status', 0, N'流程实例的结果', N'1', N'2022-01-07 23:48:10', N'1', N'2024-03-08 22:42:03', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, N'流程的表单类型', N'bpm_model_form_type', 0, N'流程的表单类型', N'103', N'2022-01-11 23:50:45', N'103', N'2022-01-11 23:50:45', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, N'任务分配规则的类型', N'bpm_task_candidate_strategy', 0, N'BPM 任务的候选人的策略', N'103', N'2022-01-12 23:21:04', N'103', N'2024-03-06 02:53:59', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, N'代码生成的场景枚举', N'infra_codegen_scene', 0, N'代码生成的场景枚举', N'1', N'2022-02-02 13:14:45', N'1', N'2022-03-10 16:33:46', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, N'角色类型', N'system_role_type', 0, N'角色类型', N'1', N'2022-02-16 13:01:46', N'1', N'2022-02-16 13:01:46', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, N'文件存储器', N'infra_file_storage', 0, N'文件存储器', N'1', N'2022-03-15 00:24:38', N'1', N'2022-03-15 00:24:38', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, N'OAuth 2.0 授权类型', N'system_oauth2_grant_type', 0, N'OAuth 2.0 授权类型(模式)', N'1', N'2022-05-12 00:20:52', N'1', N'2022-05-11 16:25:49', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, N'商品 SPU 状态', N'product_spu_status', 0, N'商品 SPU 状态', N'1', N'2022-10-24 21:19:04', N'1', N'2022-10-24 21:19:08', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, N'优惠类型', N'promotion_discount_type', 0, N'优惠类型', N'1', N'2022-11-01 12:46:06', N'1', N'2022-11-01 12:46:06', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, N'优惠劵模板的有限期类型', N'promotion_coupon_template_validity_type', 0, N'优惠劵模板的有限期类型', N'1', N'2022-11-02 00:06:20', N'1', N'2022-11-04 00:08:26', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, N'营销的商品范围', N'promotion_product_scope', 0, N'营销的商品范围', N'1', N'2022-11-02 00:28:01', N'1', N'2022-11-02 00:28:01', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, N'优惠劵的状态', N'promotion_coupon_status', 0, N'优惠劵的状态', N'1', N'2022-11-04 00:14:49', N'1', N'2022-11-04 00:14:49', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, N'优惠劵的领取方式', N'promotion_coupon_take_type', 0, N'优惠劵的领取方式', N'1', N'2022-11-04 19:12:27', N'1', N'2022-11-04 19:12:27', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, N'促销活动的状态', N'promotion_activity_status', 0, N'促销活动的状态', N'1', N'2022-11-04 22:54:23', N'1', N'2022-11-04 22:54:23', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, N'营销的条件类型', N'promotion_condition_type', 0, N'营销的条件类型', N'1', N'2022-11-04 22:59:23', N'1', N'2022-11-04 22:59:23', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, N'交易售后状态', N'trade_after_sale_status', 0, N'交易售后状态', N'1', N'2022-11-19 20:52:56', N'1', N'2022-11-19 20:52:56', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, N'交易售后的类型', N'trade_after_sale_type', 0, N'交易售后的类型', N'1', N'2022-11-19 21:04:09', N'1', N'2022-11-19 21:04:09', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, N'交易售后的方式', N'trade_after_sale_way', 0, N'交易售后的方式', N'1', N'2022-11-19 21:39:04', N'1', N'2022-11-19 21:39:04', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, N'终端', N'terminal', 0, N'终端', N'1', N'2022-12-10 10:50:50', N'1', N'2022-12-10 10:53:11', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, N'交易订单的类型', N'trade_order_type', 0, N'交易订单的类型', N'1', N'2022-12-10 16:33:54', N'1', N'2022-12-10 16:33:54', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, N'交易订单的状态', N'trade_order_status', 0, N'交易订单的状态', N'1', N'2022-12-10 16:48:44', N'1', N'2022-12-10 16:48:44', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, N'交易订单项的售后状态', N'trade_order_item_after_sale_status', 0, N'交易订单项的售后状态', N'1', N'2022-12-10 20:58:08', N'1', N'2022-12-10 20:58:08', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, N'公众号自动回复的请求关键字匹配模式', N'mp_auto_reply_request_match', 0, N'公众号自动回复的请求关键字匹配模式', N'1', N'2023-01-16 23:29:56', N'1', N'2023-01-16 23:29:56', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, N'公众号的消息类型', N'mp_message_type', 0, N'公众号的消息类型', N'1', N'2023-01-17 22:17:09', N'1', N'2023-01-17 22:17:09', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, N'邮件发送状态', N'system_mail_send_status', 0, N'邮件发送状态', N'1', N'2023-01-26 09:53:13', N'1', N'2023-01-26 09:53:13', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, N'站内信模版的类型', N'system_notify_template_type', 0, N'站内信模版的类型', N'1', N'2023-01-28 10:35:10', N'1', N'2023-01-28 10:35:10', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, N'代码生成的前端类型', N'infra_codegen_front_type', 0, N'', N'1', N'2023-04-12 23:57:52', N'1', N'2023-04-12 23:57:52', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, N'快递计费方式', N'trade_delivery_express_charge_mode', 0, N'用于商城交易模块配送管理', N'1', N'2023-05-21 22:45:03', N'1', N'2023-05-21 22:45:03', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, N'积分业务类型', N'member_point_biz_type', 0, N'', N'1', N'2023-06-10 12:15:00', N'1', N'2023-06-28 13:48:20', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, N'支付通知类型', N'pay_notify_type', 0, NULL, N'1', N'2023-07-20 12:23:03', N'1', N'2023-07-20 12:23:03', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, N'会员经验业务类型', N'member_experience_biz_type', 0, NULL, N'', N'2023-08-22 12:41:01', N'', N'2023-08-22 12:41:01', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, N'交易配送类型', N'trade_delivery_type', 0, N'', N'1', N'2023-08-23 00:03:14', N'1', N'2023-08-23 00:03:14', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, N'分佣模式', N'brokerage_enabled_condition', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, N'分销关系绑定模式', N'brokerage_bind_mode', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, N'佣金提现类型', N'brokerage_withdraw_type', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, N'佣金记录业务类型', N'brokerage_record_biz_type', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, N'佣金记录状态', N'brokerage_record_status', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, N'佣金提现状态', N'brokerage_withdraw_status', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, N'佣金提现银行', N'brokerage_bank_name', 0, NULL, N'', N'2023-09-28 02:46:05', N'', N'2023-09-28 02:46:05', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, N'砍价记录的状态', N'promotion_bargain_record_status', 0, N'', N'1', N'2023-10-05 10:41:08', N'1', N'2023-10-05 10:41:08', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, N'拼团记录的状态', N'promotion_combination_record_status', 0, N'', N'1', N'2023-10-08 07:24:25', N'1', N'2023-10-08 07:24:25', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, N'回款-回款方式', N'crm_receivable_return_type', 0, N'回款-回款方式', N'1', N'2023-10-18 21:54:10', N'1', N'2023-10-18 21:54:10', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, N'CRM 客户行业', N'crm_customer_industry', 0, N'CRM 客户所属行业', N'1', N'2023-10-28 22:57:07', N'1', N'2024-02-18 23:30:22', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, N'客户等级', N'crm_customer_level', 0, N'CRM 客户等级', N'1', N'2023-10-28 22:59:12', N'1', N'2023-10-28 15:11:16', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, N'客户来源', N'crm_customer_source', 0, N'CRM 客户来源', N'1', N'2023-10-28 23:00:34', N'1', N'2023-10-28 15:11:16', N'0', NULL) +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, N'Banner 位置', N'promotion_banner_position', 0, N'', N'1', N'2023-10-08 07:24:25', N'1', N'2023-11-04 13:04:02', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, N'社交类型', N'system_social_type', 0, N'', N'1', N'2023-11-04 13:03:54', N'1', N'2023-11-04 13:03:54', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, N'产品状态', N'crm_product_status', 0, N'', N'1', N'2023-10-30 21:47:59', N'1', N'2023-10-30 21:48:45', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, N'CRM 数据权限的级别', N'crm_permission_level', 0, N'', N'1', N'2023-11-30 09:51:59', N'1', N'2023-11-30 09:51:59', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, N'CRM 审批状态', N'crm_audit_status', 0, N'', N'1', N'2023-11-30 18:56:23', N'1', N'2023-11-30 18:56:23', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, N'CRM 产品单位', N'crm_product_unit', 0, N'', N'1', N'2023-12-05 23:01:51', N'1', N'2023-12-05 23:01:51', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, N'CRM 跟进方式', N'crm_follow_up_type', 0, N'', N'1', N'2024-01-15 20:48:05', N'1', N'2024-01-15 20:48:05', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (609, N'支付转账类型', N'pay_transfer_type', 0, N'', N'1', N'2023-10-28 16:27:18', N'1', N'2023-10-28 16:27:18', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, N'转账订单状态', N'pay_transfer_status', 0, N'', N'1', N'2023-10-28 16:18:32', N'1', N'2023-10-28 16:18:32', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, N'ERP 库存明细的业务类型', N'erp_stock_record_biz_type', 0, N'ERP 库存明细的业务类型', N'1', N'2024-02-05 18:07:02', N'1', N'2024-02-05 18:07:02', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, N'ERP 审批状态', N'erp_audit_status', 0, N'', N'1', N'2024-02-06 00:00:07', N'1', N'2024-02-06 00:00:07', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, N'BPM 监听器类型', N'bpm_process_listener_type', 0, N'', N'1', N'2024-03-23 12:52:24', N'1', N'2024-03-09 15:54:28', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, N'BPM 监听器值类型', N'bpm_process_listener_value_type', 0, N'', N'1', N'2024-03-23 13:00:31', N'1', N'2024-03-23 13:00:31', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, N'时间间隔', N'date_interval', 0, N'', N'1', N'2024-03-29 22:50:09', N'1', N'2024-03-29 22:50:09', N'0', N'1970-01-01 00:00:00') +GO +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, N'CRM 商机结束状态类型', N'crm_business_end_status_type', 0, N'', N'1', N'2024-04-13 23:23:00', N'1', N'2024-04-13 23:23:00', N'0', N'1970-01-01 00:00:00') +GO +SET IDENTITY_INSERT system_dict_type OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_login_log +-- ---------------------------- +DROP TABLE IF EXISTS system_login_log +GO +CREATE TABLE system_login_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + log_type bigint NOT NULL, + trace_id nvarchar(64) DEFAULT '' NOT NULL, + user_id bigint DEFAULT 0 NOT NULL, + user_type tinyint DEFAULT 0 NOT NULL, + username nvarchar(50) DEFAULT '' NOT NULL, + result tinyint NOT NULL, + user_ip nvarchar(50) NOT NULL, + user_agent nvarchar(512) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'访问ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'log_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'链路追踪编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'trace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户账号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'登陆结果', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'result' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'user_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'浏览器 UA', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'user_agent' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统访问记录', + 'SCHEMA', N'dbo', + 'TABLE', N'system_login_log' +GO + +-- ---------------------------- +-- Table structure for system_mail_account +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_account +GO +CREATE TABLE system_mail_account +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + mail nvarchar(255) NOT NULL, + username nvarchar(255) NOT NULL, + password nvarchar(255) NOT NULL, + host nvarchar(255) NOT NULL, + port int NOT NULL, + ssl_enable varchar(1) DEFAULT '0' NOT NULL, + starttls_enable varchar(1) DEFAULT '0' NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮箱', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'mail' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'SMTP 服务器域名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'host' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'SMTP 服务器端口', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'port' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否开启 SSL', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'ssl_enable' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否开启 STARTTLS', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'starttls_enable' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮箱账号表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_account' +GO + +-- ---------------------------- +-- Records of system_mail_account +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_mail_account ON +GO +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, N'7684413@qq.com', N'7684413@qq.com', N'1234576', N'127.0.0.1', 8080, N'0', N'0', N'1', N'2023-01-25 17:39:52', N'1', N'2024-04-24 09:13:56', N'0') +GO +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, N'ydym_test@163.com', N'ydym_test@163.com', N'WBZTEINMIFVRYSOE', N'smtp.163.com', 465, N'1', N'0', N'1', N'2023-01-26 01:26:03', N'1', N'2023-04-12 22:39:38', N'0') +GO +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, N'76854114@qq.com', N'3335', N'11234', N'yunai1.cn', 466, N'0', N'0', N'1', N'2023-01-27 15:06:38', N'1', N'2023-01-27 07:08:36', N'1') +GO +INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, N'7685413x@qq.com', N'2', N'3', N'4', 5, N'1', N'0', N'1', N'2023-04-12 23:05:06', N'1', N'2023-04-12 15:05:11', N'1') +GO +SET IDENTITY_INSERT system_mail_account OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_mail_log +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_log +GO +CREATE TABLE system_mail_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint DEFAULT NULL NULL, + user_type tinyint DEFAULT NULL NULL, + to_mail nvarchar(255) NOT NULL, + account_id bigint NOT NULL, + from_mail nvarchar(255) NOT NULL, + template_id bigint NOT NULL, + template_code nvarchar(63) NOT NULL, + template_nickname nvarchar(255) DEFAULT NULL NULL, + template_title nvarchar(255) NOT NULL, + template_content nvarchar(4000) NOT NULL, + template_params nvarchar(255) NOT NULL, + send_status tinyint DEFAULT 0 NOT NULL, + send_time datetime2 DEFAULT NULL NULL, + send_message_id nvarchar(255) DEFAULT NULL NULL, + send_exception nvarchar(4000) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收邮箱地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'to_mail' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮箱账号编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'account_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送邮箱地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'from_mail' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版发送人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮件标题', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_title' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮件内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮件参数', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'template_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'send_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'send_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送返回的消息 ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'send_message_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送异常', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'send_exception' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮件日志表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_log' +GO + +-- ---------------------------- +-- Table structure for system_mail_template +-- ---------------------------- +DROP TABLE IF EXISTS system_mail_template +GO +CREATE TABLE system_mail_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(63) NOT NULL, + code nvarchar(63) NOT NULL, + account_id bigint NOT NULL, + nickname nvarchar(255) DEFAULT NULL NULL, + title nvarchar(255) NOT NULL, + content nvarchar(4000) NOT NULL, + params nvarchar(255) NOT NULL, + status tinyint NOT NULL, + remark nvarchar(255) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送的邮箱账号编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'account_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板标题', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'title' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数数组', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'开启状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'邮件模版表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_mail_template' +GO + +-- ---------------------------- +-- Records of system_mail_template +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_mail_template ON +GO +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, N'后台用户短信登录', N'admin-sms-login', 1, N'奥特曼', N'你猜我猜', N'

您的验证码是{code},名字是{name}

', N'["code","name"]', 0, N'3', N'1', N'2021-10-11 08:10:00', N'1', N'2023-12-02 19:51:14', N'0') +GO +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, N'测试模版', N'test_01', 2, N'芋艿', N'一个标题', N'

你是 {key01} 吗?


是的话,赶紧 {key02} 一下!

', N'["key01","key02"]', 0, NULL, N'1', N'2023-01-26 01:27:40', N'1', N'2023-01-27 10:32:16', N'0') +GO +INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, N'3', N'2', 2, N'7', N'4', N'

45

', N'[]', 1, N'80', N'1', N'2023-01-27 15:50:35', N'1', N'2023-01-27 16:34:49', N'0') +GO +SET IDENTITY_INSERT system_mail_template OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_menu +GO +CREATE TABLE system_menu +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(50) NOT NULL, + permission nvarchar(100) DEFAULT '' NOT NULL, + type tinyint NOT NULL, + sort int DEFAULT 0 NOT NULL, + parent_id bigint DEFAULT 0 NOT NULL, + path nvarchar(200) DEFAULT '' NULL, + icon nvarchar(100) DEFAULT '#' NULL, + component nvarchar(255) DEFAULT NULL NULL, + component_name nvarchar(255) DEFAULT NULL NULL, + status tinyint DEFAULT 0 NOT NULL, + visible varchar(1) DEFAULT '1' NOT NULL, + keep_alive varchar(1) DEFAULT '1' NOT NULL, + always_show varchar(1) DEFAULT '1' NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'权限标识', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'permission' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'显示顺序', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父菜单ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'path' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单图标', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'icon' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组件路径', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'component' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组件名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'component_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否可见', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'visible' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否缓存', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'keep_alive' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否总是显示', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'always_show' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单权限表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_menu' +GO + +-- ---------------------------- +-- Records of system_menu +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_menu ON +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, N'系统管理', N'', 1, 10, 0, N'/system', N'ep:tools', NULL, NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:04:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, N'基础设施', N'', 1, 20, 0, N'/infra', N'ep:monitor', NULL, NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-03-01 08:28:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, N'OA 示例', N'', 1, 40, 1185, N'oa', N'fa:road', NULL, NULL, 0, N'1', N'1', N'1', N'admin', N'2021-09-20 16:26:19', N'1', N'2024-02-29 12:38:13', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, N'用户管理', N'system:user:list', 2, 1, 1, N'user', N'ep:avatar', N'system/user/index', N'SystemUser', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:02:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, N'角色管理', N'', 2, 2, 1, N'role', N'ep:user', N'system/role/index', N'SystemRole', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:03:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, N'菜单管理', N'', 2, 3, 1, N'menu', N'ep:menu', N'system/menu/index', N'SystemMenu', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:03:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, N'部门管理', N'', 2, 4, 1, N'dept', N'fa:address-card', N'system/dept/index', N'SystemDept', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:06:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, N'岗位管理', N'', 2, 5, 1, N'post', N'fa:address-book-o', N'system/post/index', N'SystemPost', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:06:39', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, N'字典管理', N'', 2, 6, 1, N'dict', N'ep:collection', N'system/dict/index', N'SystemDictType', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:07:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, N'配置管理', N'', 2, 8, 2, N'config', N'fa:connectdevelop', N'infra/config/index', N'InfraConfig', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-23 00:02:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, N'通知公告', N'', 2, 4, 2739, N'notice', N'ep:takeaway-box', N'system/notice/index', N'SystemNotice', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-22 23:56:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, N'审计日志', N'', 1, 9, 1, N'log', N'ep:document-copy', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:08:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, N'令牌管理', N'', 2, 2, 1261, N'token', N'fa:key', N'system/oauth2/token/index', N'SystemTokenClient', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:13:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, N'定时任务', N'', 2, 7, 2, N'job', N'fa-solid:tasks', N'infra/job/index', N'InfraJob', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 08:57:36', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, N'MySQL 监控', N'', 2, 1, 2740, N'druid', N'fa-solid:box', N'infra/druid/index', N'InfraDruid', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-23 00:05:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, N'Java 监控', N'', 2, 3, 2740, N'admin-server', N'ep:coffee-cup', N'infra/server/index', N'InfraAdminServer', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-23 00:06:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, N'Redis 监控', N'', 2, 2, 2740, N'redis', N'fa:reddit-square', N'infra/redis/index', N'InfraRedis', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-23 00:06:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, N'表单构建', N'infra:build:list', 2, 2, 2, N'build', N'fa:wpforms', N'infra/build/index', N'InfraBuild', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 08:51:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, N'代码生成', N'infra:codegen:query', 2, 1, 2, N'codegen', N'ep:document-copy', N'infra/codegen/index', N'InfraCodegen', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 08:51:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, N'API 接口', N'infra:swagger:list', 2, 3, 2, N'swagger', N'fa:fighter-jet', N'infra/swagger/index', N'InfraSwagger', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-04-23 00:01:24', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, N'操作日志', N'', 2, 1, 108, N'operate-log', N'ep:position', N'system/operatelog/index', N'SystemOperateLog', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:09:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, N'登录日志', N'', 2, 2, 108, N'login-log', N'ep:promotion', N'system/loginlog/index', N'SystemLoginLog', 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2024-02-29 01:10:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, N'用户查询', N'system:user:query', 3, 1, 100, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, N'用户新增', N'system:user:create', 3, 2, 100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, N'用户修改', N'system:user:update', 3, 3, 100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, N'用户删除', N'system:user:delete', 3, 4, 100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, N'用户导出', N'system:user:export', 3, 5, 100, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, N'用户导入', N'system:user:import', 3, 6, 100, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, N'重置密码', N'system:user:update-password', 3, 7, 100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, N'角色查询', N'system:role:query', 3, 1, 101, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, N'角色新增', N'system:role:create', 3, 2, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, N'角色修改', N'system:role:update', 3, 3, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, N'角色删除', N'system:role:delete', 3, 4, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, N'角色导出', N'system:role:export', 3, 5, 101, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, N'菜单查询', N'system:menu:query', 3, 1, 102, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, N'菜单新增', N'system:menu:create', 3, 2, 102, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, N'菜单修改', N'system:menu:update', 3, 3, 102, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, N'菜单删除', N'system:menu:delete', 3, 4, 102, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, N'部门查询', N'system:dept:query', 3, 1, 103, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, N'部门新增', N'system:dept:create', 3, 2, 103, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, N'部门修改', N'system:dept:update', 3, 3, 103, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, N'部门删除', N'system:dept:delete', 3, 4, 103, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, N'岗位查询', N'system:post:query', 3, 1, 104, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, N'岗位新增', N'system:post:create', 3, 2, 104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, N'岗位修改', N'system:post:update', 3, 3, 104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, N'岗位删除', N'system:post:delete', 3, 4, 104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, N'岗位导出', N'system:post:export', 3, 5, 104, N'', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, N'字典查询', N'system:dict:query', 3, 1, 105, N'#', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, N'字典新增', N'system:dict:create', 3, 2, 105, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, N'字典修改', N'system:dict:update', 3, 3, 105, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, N'字典删除', N'system:dict:delete', 3, 4, 105, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, N'字典导出', N'system:dict:export', 3, 5, 105, N'#', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, N'配置查询', N'infra:config:query', 3, 1, 106, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, N'配置新增', N'infra:config:create', 3, 2, 106, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, N'配置修改', N'infra:config:update', 3, 3, 106, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, N'配置删除', N'infra:config:delete', 3, 4, 106, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, N'配置导出', N'infra:config:export', 3, 5, 106, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, N'公告查询', N'system:notice:query', 3, 1, 107, N'#', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, N'公告新增', N'system:notice:create', 3, 2, 107, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, N'公告修改', N'system:notice:update', 3, 3, 107, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, N'公告删除', N'system:notice:delete', 3, 4, 107, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, N'操作查询', N'system:operate-log:query', 3, 1, 500, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, N'日志导出', N'system:operate-log:export', 3, 2, 500, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, N'登录查询', N'system:login-log:query', 3, 1, 501, N'#', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, N'日志导出', N'system:login-log:export', 3, 3, 501, N'#', N'#', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, N'令牌列表', N'system:oauth2-token:page', 3, 1, 109, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-05-09 23:54:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, N'令牌删除', N'system:oauth2-token:delete', 3, 2, 109, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-05-09 23:54:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, N'任务新增', N'infra:job:create', 3, 2, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, N'任务修改', N'infra:job:update', 3, 3, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, N'任务删除', N'infra:job:delete', 3, 4, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, N'状态修改', N'infra:job:update', 3, 5, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, N'任务导出', N'infra:job:export', 3, 7, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, N'生成修改', N'infra:codegen:update', 3, 2, 115, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, N'生成删除', N'infra:codegen:delete', 3, 3, 115, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, N'导入代码', N'infra:codegen:create', 3, 2, 115, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, N'预览代码', N'infra:codegen:preview', 3, 4, 115, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, N'生成代码', N'infra:codegen:download', 3, 5, 115, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'admin', N'2021-01-05 17:03:48', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, N'设置角色菜单权限', N'system:permission:assign-role-menu', 3, 6, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-01-06 17:53:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, N'设置角色数据权限', N'system:permission:assign-role-data-scope', 3, 7, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-01-06 17:56:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, N'设置用户角色', N'system:permission:assign-user-role', 3, 8, 101, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-01-07 10:23:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, N'获得 Redis 监控信息', N'infra:redis:get-monitor-info', 3, 1, 113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-01-26 01:02:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, N'获得 Redis Key 列表', N'infra:redis:get-key-list', 3, 2, 113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-01-26 01:02:52', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, N'代码生成案例', N'', 1, 1, 2, N'demo', N'ep:aim', N'infra/testDemo/index', NULL, 0, N'1', N'1', N'1', N'', N'2021-02-06 12:42:49', N'1', N'2023-11-15 23:45:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, N'任务触发', N'infra:job:trigger', 3, 8, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-02-07 13:03:10', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, N'链路追踪', N'', 2, 4, 2740, N'skywalking', N'fa:eye', N'infra/skywalking/index', N'InfraSkyWalking', 0, N'1', N'1', N'1', N'', N'2021-02-08 20:41:31', N'1', N'2024-04-23 00:07:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, N'访问日志', N'', 2, 1, 1083, N'api-access-log', N'ep:place', N'infra/apiAccessLog/index', N'InfraApiAccessLog', 0, N'1', N'1', N'1', N'', N'2021-02-26 01:32:59', N'1', N'2024-02-29 08:54:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, N'日志导出', N'infra:api-access-log:export', 3, 2, 1078, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-02-26 01:32:59', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, N'API 日志', N'', 2, 4, 2, N'log', N'fa:tasks', NULL, NULL, 0, N'1', N'1', N'1', N'', N'2021-02-26 02:18:24', N'1', N'2024-04-22 23:58:36', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, N'错误日志', N'infra:api-error-log:query', 2, 2, 1083, N'api-error-log', N'ep:warning-filled', N'infra/apiErrorLog/index', N'InfraApiErrorLog', 0, N'1', N'1', N'1', N'', N'2021-02-26 07:53:20', N'1', N'2024-02-29 08:55:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, N'日志处理', N'infra:api-error-log:update-status', 3, 2, 1084, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-02-26 07:53:20', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, N'日志导出', N'infra:api-error-log:export', 3, 3, 1084, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-02-26 07:53:20', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, N'任务查询', N'infra:job:query', 3, 1, 110, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-03-10 01:26:19', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, N'日志查询', N'infra:api-access-log:query', 3, 1, 1078, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-03-10 01:28:04', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, N'日志查询', N'infra:api-error-log:query', 3, 1, 1084, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-03-10 01:29:09', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, N'文件列表', N'', 2, 5, 1243, N'file', N'ep:upload-filled', N'infra/file/index', N'InfraFile', 0, N'1', N'1', N'1', N'', N'2021-03-12 20:16:20', N'1', N'2024-02-29 08:53:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, N'文件查询', N'infra:file:query', 3, 1, 1090, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-03-12 20:16:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, N'文件删除', N'infra:file:delete', 3, 4, 1090, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-03-12 20:16:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, N'短信管理', N'', 1, 1, 2739, N'sms', N'ep:message', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2021-04-05 01:10:16', N'1', N'2024-04-22 23:56:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, N'短信渠道', N'', 2, 0, 1093, N'sms-channel', N'fa:stack-exchange', N'system/sms/channel/index', N'SystemSmsChannel', 0, N'1', N'1', N'1', N'', N'2021-04-01 11:07:15', N'1', N'2024-02-29 01:15:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, N'短信渠道查询', N'system:sms-channel:query', 3, 1, 1094, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 11:07:15', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, N'短信渠道创建', N'system:sms-channel:create', 3, 2, 1094, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 11:07:15', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, N'短信渠道更新', N'system:sms-channel:update', 3, 3, 1094, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 11:07:15', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, N'短信渠道删除', N'system:sms-channel:delete', 3, 4, 1094, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 11:07:15', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, N'短信模板', N'', 2, 1, 1093, N'sms-template', N'ep:connection', N'system/sms/template/index', N'SystemSmsTemplate', 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'1', N'2024-02-29 01:16:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, N'短信模板查询', N'system:sms-template:query', 3, 1, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, N'短信模板创建', N'system:sms-template:create', 3, 2, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, N'短信模板更新', N'system:sms-template:update', 3, 3, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, N'短信模板删除', N'system:sms-template:delete', 3, 4, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, N'短信模板导出', N'system:sms-template:export', 3, 5, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-01 17:35:17', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, N'发送测试短信', N'system:sms-template:send-sms', 3, 6, 1100, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-04-11 00:26:40', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, N'短信日志', N'', 2, 2, 1093, N'sms-log', N'fa:edit', N'system/sms/log/index', N'SystemSmsLog', 0, N'1', N'1', N'1', N'', N'2021-04-11 08:37:05', N'1', N'2024-02-29 08:49:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, N'短信日志查询', N'system:sms-log:query', 3, 1, 1107, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-11 08:37:05', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, N'短信日志导出', N'system:sms-log:export', 3, 5, 1107, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-04-11 08:37:05', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, N'支付管理', N'', 1, 30, 0, N'/pay', N'ep:money', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2021-12-25 16:43:41', N'1', N'2024-02-29 08:58:38', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, N'请假查询', N'', 2, 0, 5, N'leave', N'fa:leanpub', N'bpm/oa/leave/index', N'BpmOALeave', 0, N'1', N'1', N'1', N'', N'2021-09-20 08:51:03', N'1', N'2024-02-29 12:38:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, N'请假申请查询', N'bpm:oa-leave:query', 3, 1, 1118, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-09-20 08:51:03', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, N'请假申请创建', N'bpm:oa-leave:create', 3, 2, 1118, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-09-20 08:51:03', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, N'应用信息', N'', 2, 1, 1117, N'app', N'fa:apple', N'pay/app/index', N'PayApp', 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:30', N'1', N'2024-02-29 08:59:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, N'支付应用信息查询', N'pay:app:query', 3, 1, 1126, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, N'支付应用信息创建', N'pay:app:create', 3, 2, 1126, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, N'支付应用信息更新', N'pay:app:update', 3, 3, 1126, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, N'支付应用信息删除', N'pay:app:delete', 3, 4, 1126, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:31', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, N'秘钥解析', N'pay:channel:parsing', 3, 6, 1129, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-11-08 15:15:47', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, N'支付商户信息查询', N'pay:merchant:query', 3, 1, 1132, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:41', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, N'支付商户信息创建', N'pay:merchant:create', 3, 2, 1132, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:41', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, N'支付商户信息更新', N'pay:merchant:update', 3, 3, 1132, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:41', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, N'支付商户信息删除', N'pay:merchant:delete', 3, 4, 1132, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:41', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, N'支付商户信息导出', N'pay:merchant:export', 3, 5, 1132, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-11-10 01:13:41', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, N'租户列表', N'', 2, 0, 1224, N'list', N'ep:house', N'system/tenant/index', N'SystemTenant', 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:43', N'1', N'2024-02-29 01:01:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, N'租户查询', N'system:tenant:query', 3, 1, 1138, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, N'租户创建', N'system:tenant:create', 3, 2, 1138, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, N'租户更新', N'system:tenant:update', 3, 3, 1138, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, N'租户删除', N'system:tenant:delete', 3, 4, 1138, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, N'租户导出', N'system:tenant:export', 3, 5, 1138, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-14 12:31:44', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, N'秘钥解析', N'', 3, 6, 1129, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2021-11-08 15:15:47', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, N'退款订单', N'', 2, 3, 1117, N'refund', N'fa:registered', N'pay/refund/index', N'PayRefund', 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'1', N'2024-02-29 08:59:20', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, N'退款订单查询', N'pay:refund:query', 3, 1, 1161, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1163, N'退款订单创建', N'pay:refund:create', 3, 2, 1161, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1164, N'退款订单更新', N'pay:refund:update', 3, 3, 1161, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1165, N'退款订单删除', N'pay:refund:delete', 3, 4, 1161, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, N'退款订单导出', N'pay:refund:export', 3, 5, 1161, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:29:07', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, N'支付订单', N'', 2, 2, 1117, N'order', N'fa:cc-paypal', N'pay/order/index', N'PayOrder', 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'1', N'2024-02-29 08:59:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, N'支付订单查询', N'pay:order:query', 3, 1, 1173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1175, N'支付订单创建', N'pay:order:create', 3, 2, 1173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1176, N'支付订单更新', N'pay:order:update', 3, 3, 1173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1177, N'支付订单删除', N'pay:order:delete', 3, 4, 1173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, N'支付订单导出', N'pay:order:export', 3, 5, 1173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-25 08:49:43', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, N'工作流程', N'', 1, 50, 0, N'/bpm', N'fa:medium', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2021-12-30 20:26:36', N'1', N'2024-02-29 12:43:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, N'流程管理', N'', 1, 10, 1185, N'manager', N'fa:dedent', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2021-12-30 20:28:30', N'1', N'2024-02-29 12:36:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, N'流程表单', N'', 2, 2, 1186, N'form', N'fa:hdd-o', N'bpm/form/index', N'BpmForm', 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2024-03-19 12:25:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, N'表单查询', N'bpm:form:query', 3, 1, 1187, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, N'表单创建', N'bpm:form:create', 3, 2, 1187, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, N'表单更新', N'bpm:form:update', 3, 3, 1187, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, N'表单删除', N'bpm:form:delete', 3, 4, 1187, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, N'表单导出', N'bpm:form:export', 3, 5, 1187, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2021-12-30 12:38:22', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, N'流程模型', N'', 2, 1, 1186, N'model', N'fa-solid:project-diagram', N'bpm/model/index', N'BpmModel', 0, N'1', N'1', N'1', N'1', N'2021-12-31 23:24:58', N'1', N'2024-03-19 12:25:19', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, N'模型查询', N'bpm:model:query', 3, 1, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:01:10', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, N'模型创建', N'bpm:model:create', 3, 2, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:01:24', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1196, N'模型导入', N'bpm:model:import', 3, 3, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:01:35', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, N'模型更新', N'bpm:model:update', 3, 4, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:02:28', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, N'模型删除', N'bpm:model:delete', 3, 5, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:02:43', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, N'模型发布', N'bpm:model:deploy', 3, 6, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-03 19:03:24', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, N'审批中心', N'', 2, 20, 1185, N'task', N'fa:tasks', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-07 23:51:48', N'1', N'2024-03-21 00:33:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, N'我的流程', N'', 2, 1, 1200, N'my', N'fa-solid:book', N'bpm/processInstance/index', N'BpmProcessInstanceMy', 0, N'1', N'1', N'1', N'', N'2022-01-07 15:53:44', N'1', N'2024-03-21 23:52:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, N'流程实例的查询', N'bpm:process-instance:query', 3, 1, 1201, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-01-07 15:53:44', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, N'待办任务', N'', 2, 10, 1200, N'todo', N'fa:slack', N'bpm/task/todo/index', N'BpmTodoTask', 0, N'1', N'1', N'1', N'1', N'2022-01-08 10:33:37', N'1', N'2024-02-29 12:37:39', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, N'已办任务', N'', 2, 20, 1200, N'done', N'fa:delicious', N'bpm/task/done/index', N'BpmDoneTask', 0, N'1', N'1', N'1', N'1', N'2022-01-08 10:34:13', N'1', N'2024-02-29 12:37:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, N'用户分组', N'', 2, 4, 1186, N'user-group', N'fa:user-secret', N'bpm/group/index', N'BpmUserGroup', 0, N'1', N'1', N'1', N'', N'2022-01-14 02:14:20', N'1', N'2024-03-21 23:55:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, N'用户组查询', N'bpm:user-group:query', 3, 1, 1209, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-01-14 02:14:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, N'用户组创建', N'bpm:user-group:create', 3, 2, 1209, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-01-14 02:14:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, N'用户组更新', N'bpm:user-group:update', 3, 3, 1209, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-01-14 02:14:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, N'用户组删除', N'bpm:user-group:delete', 3, 4, 1209, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-01-14 02:14:20', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, N'流程定义查询', N'bpm:process-definition:query', 3, 10, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:21:43', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, N'流程任务分配规则查询', N'bpm:task-assign-rule:query', 3, 20, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:26:53', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, N'流程任务分配规则创建', N'bpm:task-assign-rule:create', 3, 21, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:28:15', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, N'流程任务分配规则更新', N'bpm:task-assign-rule:update', 3, 22, 1193, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:28:41', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, N'流程实例的创建', N'bpm:process-instance:create', 3, 2, 1201, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:36:15', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, N'流程实例的取消', N'bpm:process-instance:cancel', 3, 3, 1201, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:36:33', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, N'流程任务的查询', N'bpm:task:query', 3, 1, 1207, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:38:52', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, N'流程任务的更新', N'bpm:task:update', 3, 2, 1207, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-01-23 00:39:24', N'1', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, N'租户管理', N'', 2, 0, 1, N'tenant', N'fa-solid:house-user', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-02-20 01:41:13', N'1', N'2024-02-29 00:59:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, N'租户套餐', N'', 2, 0, 1224, N'package', N'fa:bars', N'system/tenantPackage/index', N'SystemTenantPackage', 0, N'1', N'1', N'1', N'', N'2022-02-19 17:44:06', N'1', N'2024-02-29 01:01:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, N'租户套餐查询', N'system:tenant-package:query', 3, 1, 1225, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-02-19 17:44:06', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, N'租户套餐创建', N'system:tenant-package:create', 3, 2, 1225, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-02-19 17:44:06', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, N'租户套餐更新', N'system:tenant-package:update', 3, 3, 1225, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-02-19 17:44:06', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, N'租户套餐删除', N'system:tenant-package:delete', 3, 4, 1225, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-02-19 17:44:06', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, N'文件配置', N'', 2, 0, 1243, N'file-config', N'fa-solid:file-signature', N'infra/fileConfig/index', N'InfraFileConfig', 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'1', N'2024-02-29 08:52:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, N'文件配置查询', N'infra:file-config:query', 3, 1, 1237, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, N'文件配置创建', N'infra:file-config:create', 3, 2, 1237, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, N'文件配置更新', N'infra:file-config:update', 3, 3, 1237, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, N'文件配置删除', N'infra:file-config:delete', 3, 4, 1237, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, N'文件配置导出', N'infra:file-config:export', 3, 5, 1237, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-03-15 14:35:28', N'', N'2022-04-20 17:03:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, N'文件管理', N'', 2, 6, 2, N'file', N'ep:files', NULL, N'', 0, N'1', N'1', N'1', N'1', N'2022-03-16 23:47:40', N'1', N'2024-04-23 00:02:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, N'作者动态', N'', 1, 0, 0, N'https://www.iocoder.cn', N'ep:avatar', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-04-23 01:03:15', N'1', N'2023-12-08 23:40:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, N'数据源配置', N'', 2, 1, 2, N'data-source-config', N'ep:data-analysis', N'infra/dataSourceConfig/index', N'InfraDataSourceConfig', 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'1', N'2024-02-29 08:51:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, N'数据源配置查询', N'infra:data-source-config:query', 3, 1, 1255, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'', N'2022-04-27 14:37:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, N'数据源配置创建', N'infra:data-source-config:create', 3, 2, 1255, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'', N'2022-04-27 14:37:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, N'数据源配置更新', N'infra:data-source-config:update', 3, 3, 1255, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'', N'2022-04-27 14:37:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, N'数据源配置删除', N'infra:data-source-config:delete', 3, 4, 1255, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'', N'2022-04-27 14:37:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, N'数据源配置导出', N'infra:data-source-config:export', 3, 5, 1255, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-04-27 14:37:32', N'', N'2022-04-27 14:37:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, N'OAuth 2.0', N'', 2, 10, 1, N'oauth2', N'fa:dashcube', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-05-09 23:38:17', N'1', N'2024-02-29 01:12:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, N'应用管理', N'', 2, 0, 1261, N'oauth2/application', N'fa:hdd-o', N'system/oauth2/client/index', N'SystemOAuth2Client', 0, N'1', N'1', N'1', N'', N'2022-05-10 16:26:33', N'1', N'2024-02-29 01:13:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, N'客户端查询', N'system:oauth2-client:query', 3, 1, 1263, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-05-10 16:26:33', N'1', N'2022-05-11 00:31:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, N'客户端创建', N'system:oauth2-client:create', 3, 2, 1263, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-05-10 16:26:33', N'1', N'2022-05-11 00:31:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, N'客户端更新', N'system:oauth2-client:update', 3, 3, 1263, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-05-10 16:26:33', N'1', N'2022-05-11 00:31:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, N'客户端删除', N'system:oauth2-client:delete', 3, 4, 1263, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-05-10 16:26:33', N'1', N'2022-05-11 00:31:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, N'报表管理', N'', 2, 40, 0, N'/report', N'ep:pie-chart', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-07-10 20:22:15', N'1', N'2024-02-29 12:33:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, N'报表设计器', N'', 2, 1, 1281, N'jimu-report', N'ep:trend-charts', N'report/jmreport/index', N'GoView', 0, N'1', N'1', N'1', N'1', N'2022-07-10 20:26:36', N'1', N'2024-02-29 12:33:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, N'商品中心', N'', 1, 60, 2362, N'product', N'fa:product-hunt', NULL, NULL, 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'1', N'2023-09-30 11:52:36', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, N'商品分类', N'', 2, 2, 2000, N'category', N'ep:cellphone', N'mall/product/category/index', N'ProductCategory', 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'1', N'2023-08-21 10:27:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, N'分类查询', N'product:category:query', 3, 1, 2002, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'', N'2022-07-29 15:53:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, N'分类创建', N'product:category:create', 3, 2, 2002, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'', N'2022-07-29 15:53:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, N'分类更新', N'product:category:update', 3, 3, 2002, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'', N'2022-07-29 15:53:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, N'分类删除', N'product:category:delete', 3, 4, 2002, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-29 15:53:53', N'', N'2022-07-29 15:53:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, N'商品品牌', N'', 2, 3, 2000, N'brand', N'ep:chicken', N'mall/product/brand/index', N'ProductBrand', 0, N'1', N'1', N'1', N'', N'2022-07-30 13:52:44', N'1', N'2023-08-21 10:27:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, N'品牌查询', N'product:brand:query', 3, 1, 2008, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 13:52:44', N'', N'2022-07-30 13:52:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, N'品牌创建', N'product:brand:create', 3, 2, 2008, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 13:52:44', N'', N'2022-07-30 13:52:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, N'品牌更新', N'product:brand:update', 3, 3, 2008, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 13:52:44', N'', N'2022-07-30 13:52:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, N'品牌删除', N'product:brand:delete', 3, 4, 2008, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 13:52:44', N'', N'2022-07-30 13:52:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, N'商品列表', N'', 2, 1, 2000, N'spu', N'ep:apple', N'mall/product/spu/index', N'ProductSpu', 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'1', N'2023-08-21 10:27:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, N'商品查询', N'product:spu:query', 3, 1, 2014, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'', N'2022-07-30 14:22:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, N'商品创建', N'product:spu:create', 3, 2, 2014, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'', N'2022-07-30 14:22:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, N'商品更新', N'product:spu:update', 3, 3, 2014, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'', N'2022-07-30 14:22:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, N'商品删除', N'product:spu:delete', 3, 4, 2014, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'', N'2022-07-30 14:22:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, N'商品属性', N'', 2, 4, 2000, N'property', N'ep:cold-drink', N'mall/product/property/index', N'ProductProperty', 0, N'1', N'1', N'1', N'', N'2022-08-01 14:55:35', N'1', N'2023-08-26 11:01:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, N'规格查询', N'product:property:query', 3, 1, 2019, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-08-01 14:55:35', N'', N'2022-12-12 20:26:24', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, N'规格创建', N'product:property:create', 3, 2, 2019, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-08-01 14:55:35', N'', N'2022-12-12 20:26:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, N'规格更新', N'product:property:update', 3, 3, 2019, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-08-01 14:55:35', N'', N'2022-12-12 20:26:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, N'规格删除', N'product:property:delete', 3, 4, 2019, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-08-01 14:55:35', N'', N'2022-12-12 20:26:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, N'Banner', N'', 2, 100, 2387, N'banner', N'fa:bandcamp', N'mall/promotion/banner/index', NULL, 0, N'1', N'1', N'1', N'', N'2022-08-01 14:56:14', N'1', N'2023-10-24 20:20:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, N'Banner查询', N'promotion:banner:query', 3, 1, 2025, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-08-01 14:56:14', N'1', N'2023-10-24 20:20:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, N'Banner创建', N'promotion:banner:create', 3, 2, 2025, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-08-01 14:56:14', N'1', N'2023-10-24 20:20:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, N'Banner更新', N'promotion:banner:update', 3, 3, 2025, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-08-01 14:56:14', N'1', N'2023-10-24 20:20:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, N'Banner删除', N'promotion:banner:delete', 3, 4, 2025, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-08-01 14:56:14', N'1', N'2023-10-24 20:20:36', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, N'营销中心', N'', 1, 70, 2362, N'promotion', N'ep:present', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-10-31 21:25:09', N'1', N'2023-09-30 11:54:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, N'优惠劵列表', N'', 2, 1, 2365, N'template', N'ep:discount', N'mall/promotion/coupon/template/index', N'PromotionCouponTemplate', 0, N'1', N'1', N'1', N'', N'2022-10-31 22:27:14', N'1', N'2023-10-03 12:40:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, N'优惠劵模板查询', N'promotion:coupon-template:query', 3, 1, 2032, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-10-31 22:27:14', N'', N'2022-10-31 22:27:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, N'优惠劵模板创建', N'promotion:coupon-template:create', 3, 2, 2032, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-10-31 22:27:14', N'', N'2022-10-31 22:27:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, N'优惠劵模板更新', N'promotion:coupon-template:update', 3, 3, 2032, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-10-31 22:27:14', N'', N'2022-10-31 22:27:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, N'优惠劵模板删除', N'promotion:coupon-template:delete', 3, 4, 2032, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-10-31 22:27:14', N'', N'2022-10-31 22:27:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, N'领取记录', N'', 2, 2, 2365, N'list', N'ep:collection-tag', N'mall/promotion/coupon/index', N'PromotionCoupon', 0, N'1', N'1', N'1', N'', N'2022-11-03 23:21:31', N'1', N'2023-10-03 12:55:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, N'优惠劵查询', N'promotion:coupon:query', 3, 1, 2038, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-03 23:21:31', N'', N'2022-11-03 23:21:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, N'优惠劵删除', N'promotion:coupon:delete', 3, 4, 2038, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-03 23:21:31', N'', N'2022-11-03 23:21:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, N'满减送', N'', 2, 10, 2390, N'reward-activity', N'ep:goblet-square-full', N'mall/promotion/rewardActivity/index', N'PromotionRewardActivity', 0, N'1', N'1', N'1', N'', N'2022-11-04 23:47:49', N'1', N'2023-10-21 19:24:46', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, N'满减送活动查询', N'promotion:reward-activity:query', 3, 1, 2041, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-04 23:47:49', N'', N'2022-11-04 23:47:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, N'满减送活动创建', N'promotion:reward-activity:create', 3, 2, 2041, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-04 23:47:49', N'', N'2022-11-04 23:47:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, N'满减送活动更新', N'promotion:reward-activity:update', 3, 3, 2041, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-04 23:47:50', N'', N'2022-11-04 23:47:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, N'满减送活动删除', N'promotion:reward-activity:delete', 3, 4, 2041, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-04 23:47:50', N'', N'2022-11-04 23:47:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, N'满减送活动关闭', N'promotion:reward-activity:close', 3, 5, 2041, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2022-11-05 10:42:53', N'1', N'2022-11-05 10:42:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, N'限时折扣', N'', 2, 7, 2390, N'discount-activity', N'ep:timer', N'mall/promotion/discountActivity/index', N'PromotionDiscountActivity', 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:15', N'1', N'2023-10-21 19:24:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, N'限时折扣活动查询', N'promotion:discount-activity:query', 3, 1, 2047, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:15', N'', N'2022-11-05 17:12:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, N'限时折扣活动创建', N'promotion:discount-activity:create', 3, 2, 2047, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:15', N'', N'2022-11-05 17:12:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, N'限时折扣活动更新', N'promotion:discount-activity:update', 3, 3, 2047, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:16', N'', N'2022-11-05 17:12:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, N'限时折扣活动删除', N'promotion:discount-activity:delete', 3, 4, 2047, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:16', N'', N'2022-11-05 17:12:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, N'限时折扣活动关闭', N'promotion:discount-activity:close', 3, 5, 2047, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-05 17:12:16', N'', N'2022-11-05 17:12:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, N'秒杀商品', N'', 2, 2, 2209, N'activity', N'ep:basketball', N'mall/promotion/seckill/activity/index', N'PromotionSeckillActivity', 0, N'1', N'1', N'1', N'', N'2022-11-06 22:24:49', N'1', N'2023-06-24 18:57:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, N'秒杀活动查询', N'promotion:seckill-activity:query', 3, 1, 2059, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-06 22:24:49', N'', N'2022-11-06 22:24:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, N'秒杀活动创建', N'promotion:seckill-activity:create', 3, 2, 2059, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-06 22:24:49', N'', N'2022-11-06 22:24:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, N'秒杀活动更新', N'promotion:seckill-activity:update', 3, 3, 2059, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-06 22:24:49', N'', N'2022-11-06 22:24:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, N'秒杀活动删除', N'promotion:seckill-activity:delete', 3, 4, 2059, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-06 22:24:49', N'', N'2022-11-06 22:24:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, N'秒杀时段', N'', 2, 1, 2209, N'config', N'ep:baseball', N'mall/promotion/seckill/config/index', N'PromotionSeckillConfig', 0, N'1', N'1', N'1', N'', N'2022-11-15 19:46:50', N'1', N'2023-06-24 18:57:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, N'秒杀时段查询', N'promotion:seckill-config:query', 3, 1, 2066, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-11-15 19:46:51', N'1', N'2023-06-24 17:50:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, N'秒杀时段创建', N'promotion:seckill-config:create', 3, 2, 2066, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-11-15 19:46:51', N'1', N'2023-06-24 17:48:39', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, N'秒杀时段更新', N'promotion:seckill-config:update', 3, 3, 2066, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-11-15 19:46:51', N'1', N'2023-06-24 17:50:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, N'秒杀时段删除', N'promotion:seckill-config:delete', 3, 4, 2066, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2022-11-15 19:46:51', N'1', N'2023-06-24 17:50:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, N'订单中心', N'', 1, 65, 2362, N'trade', N'ep:eleme', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2022-11-19 18:57:19', N'1', N'2023-09-30 11:54:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, N'售后退款', N'', 2, 2, 2072, N'after-sale', N'ep:refrigerator', N'mall/trade/afterSale/index', N'TradeAfterSale', 0, N'1', N'1', N'1', N'', N'2022-11-19 20:15:32', N'1', N'2023-10-01 21:42:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, N'售后查询', N'trade:after-sale:query', 3, 1, 2073, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-11-19 20:15:33', N'1', N'2022-12-10 21:04:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, N'秒杀活动关闭', N'promotion:seckill-activity:close', 3, 5, 2059, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2022-11-28 20:20:15', N'1', N'2023-10-03 18:34:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, N'订单列表', N'', 2, 1, 2072, N'order', N'ep:list', N'mall/trade/order/index', N'TradeOrder', 0, N'1', N'1', N'1', N'1', N'2022-12-10 21:05:44', N'1', N'2023-10-01 21:42:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, N'地区管理', N'', 2, 14, 1, N'area', N'fa:map-marker', N'system/area/index', N'SystemArea', 0, N'1', N'1', N'1', N'1', N'2022-12-23 17:35:05', N'1', N'2024-02-29 08:50:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, N'公众号管理', N'', 1, 100, 0, N'/mp', N'ep:compass', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-01 20:11:04', N'1', N'2024-02-29 12:39:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, N'账号管理', N'', 2, 1, 2084, N'account', N'fa:user', N'mp/account/index', N'MpAccount', 0, N'1', N'1', N'1', N'1', N'2023-01-01 20:13:31', N'1', N'2024-02-29 12:42:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, N'新增账号', N'mp:account:create', 3, 1, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-01 20:21:40', N'1', N'2023-01-07 17:32:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, N'修改账号', N'mp:account:update', 3, 2, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-07 17:32:46', N'1', N'2023-01-07 17:32:46', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, N'查询账号', N'mp:account:query', 3, 0, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-07 17:33:07', N'1', N'2023-01-07 17:33:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, N'删除账号', N'mp:account:delete', 3, 3, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-07 17:33:21', N'1', N'2023-01-07 17:33:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, N'生成二维码', N'mp:account:qr-code', 3, 4, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-07 17:33:58', N'1', N'2023-01-07 17:33:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, N'清空 API 配额', N'mp:account:clear-quota', 3, 5, 2085, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-07 18:20:32', N'1', N'2023-01-07 18:20:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, N'数据统计', N'mp:statistics:query', 2, 2, 2084, N'statistics', N'ep:trend-charts', N'mp/statistics/index', N'MpStatistics', 0, N'1', N'1', N'1', N'1', N'2023-01-07 20:17:36', N'1', N'2024-02-29 12:42:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, N'标签管理', N'', 2, 3, 2084, N'tag', N'ep:collection-tag', N'mp/tag/index', N'MpTag', 0, N'1', N'1', N'1', N'1', N'2023-01-08 11:37:32', N'1', N'2024-02-29 12:42:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, N'查询标签', N'mp:tag:query', 3, 0, 2093, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 11:59:03', N'1', N'2023-01-08 11:59:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, N'新增标签', N'mp:tag:create', 3, 1, 2093, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 11:59:23', N'1', N'2023-01-08 11:59:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, N'修改标签', N'mp:tag:update', 3, 2, 2093, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 11:59:41', N'1', N'2023-01-08 11:59:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, N'删除标签', N'mp:tag:delete', 3, 3, 2093, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 12:00:04', N'1', N'2023-01-08 12:00:13', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, N'同步标签', N'mp:tag:sync', 3, 4, 2093, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 12:00:29', N'1', N'2023-01-08 12:00:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, N'粉丝管理', N'', 2, 4, 2084, N'user', N'fa:user-secret', N'mp/user/index', N'MpUser', 0, N'1', N'1', N'1', N'1', N'2023-01-08 16:51:20', N'1', N'2024-02-29 12:42:39', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, N'查询粉丝', N'mp:user:query', 3, 0, 2099, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 17:16:59', N'1', N'2023-01-08 17:17:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, N'修改粉丝', N'mp:user:update', 3, 1, 2099, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 17:17:11', N'1', N'2023-01-08 17:17:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, N'同步粉丝', N'mp:user:sync', 3, 2, 2099, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-08 17:17:40', N'1', N'2023-01-08 17:17:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, N'消息管理', N'', 2, 5, 2084, N'message', N'ep:message', N'mp/message/index', N'MpMessage', 0, N'1', N'1', N'1', N'1', N'2023-01-08 18:44:19', N'1', N'2024-02-29 12:42:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, N'图文发表记录', N'', 2, 10, 2084, N'free-publish', N'ep:edit-pen', N'mp/freePublish/index', N'MpFreePublish', 0, N'1', N'1', N'1', N'1', N'2023-01-13 00:30:50', N'1', N'2024-02-29 12:43:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, N'查询发布列表', N'mp:free-publish:query', 3, 1, 2104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-13 07:19:17', N'1', N'2023-01-13 07:19:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, N'发布草稿', N'mp:free-publish:submit', 3, 2, 2104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-13 07:19:46', N'1', N'2023-01-13 07:19:46', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, N'删除发布记录', N'mp:free-publish:delete', 3, 3, 2104, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-13 07:20:01', N'1', N'2023-01-13 07:20:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, N'图文草稿箱', N'', 2, 9, 2084, N'draft', N'ep:edit', N'mp/draft/index', N'MpDraft', 0, N'1', N'1', N'1', N'1', N'2023-01-13 07:40:21', N'1', N'2024-02-29 12:43:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, N'新建草稿', N'mp:draft:create', 3, 1, 2108, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-13 23:15:30', N'1', N'2023-01-13 23:15:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, N'修改草稿', N'mp:draft:update', 3, 2, 2108, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 10:08:47', N'1', N'2023-01-14 10:08:47', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, N'查询草稿', N'mp:draft:query', 3, 0, 2108, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 10:09:01', N'1', N'2023-01-14 10:09:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, N'删除草稿', N'mp:draft:delete', 3, 3, 2108, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 10:09:19', N'1', N'2023-01-14 10:09:19', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, N'素材管理', N'', 2, 8, 2084, N'material', N'ep:basketball', N'mp/material/index', N'MpMaterial', 0, N'1', N'1', N'1', N'1', N'2023-01-14 14:12:07', N'1', N'2024-02-29 12:43:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, N'上传临时素材', N'mp:material:upload-temporary', 3, 1, 2113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 15:33:55', N'1', N'2023-01-14 15:33:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, N'上传永久素材', N'mp:material:upload-permanent', 3, 2, 2113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 15:34:14', N'1', N'2023-01-14 15:34:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, N'删除素材', N'mp:material:delete', 3, 3, 2113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 15:35:37', N'1', N'2023-01-14 15:35:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, N'上传图文图片', N'mp:material:upload-news-image', 3, 4, 2113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 15:36:31', N'1', N'2023-01-14 15:36:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, N'查询素材', N'mp:material:query', 3, 5, 2113, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-14 15:39:22', N'1', N'2023-01-14 15:39:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, N'菜单管理', N'', 2, 6, 2084, N'menu', N'ep:menu', N'mp/menu/index', N'MpMenu', 0, N'1', N'1', N'1', N'1', N'2023-01-14 17:43:54', N'1', N'2024-02-29 12:42:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, N'自动回复', N'', 2, 7, 2084, N'auto-reply', N'fa-solid:republican', N'mp/autoReply/index', N'MpAutoReply', 0, N'1', N'1', N'1', N'1', N'2023-01-15 22:13:09', N'1', N'2024-02-29 12:43:10', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, N'查询回复', N'mp:auto-reply:query', 3, 0, 2120, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-16 22:28:41', N'1', N'2023-01-16 22:28:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, N'新增回复', N'mp:auto-reply:create', 3, 1, 2120, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-16 22:28:54', N'1', N'2023-01-16 22:28:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, N'修改回复', N'mp:auto-reply:update', 3, 2, 2120, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-16 22:29:05', N'1', N'2023-01-16 22:29:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, N'删除回复', N'mp:auto-reply:delete', 3, 3, 2120, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-16 22:29:34', N'1', N'2023-01-16 22:29:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, N'查询菜单', N'mp:menu:query', 3, 0, 2119, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-17 23:05:41', N'1', N'2023-01-17 23:05:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, N'保存菜单', N'mp:menu:save', 3, 1, 2119, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-17 23:06:01', N'1', N'2023-01-17 23:06:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, N'删除菜单', N'mp:menu:delete', 3, 2, 2119, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-17 23:06:16', N'1', N'2023-01-17 23:06:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, N'查询消息', N'mp:message:query', 3, 0, 2103, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-17 23:07:14', N'1', N'2023-01-17 23:07:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, N'发送消息', N'mp:message:send', 3, 1, 2103, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-17 23:07:26', N'1', N'2023-01-17 23:07:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, N'邮箱管理', N'', 2, 2, 2739, N'mail', N'fa-solid:mail-bulk', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-25 17:27:44', N'1', N'2024-04-22 23:56:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, N'邮箱账号', N'', 2, 0, 2130, N'mail-account', N'fa:universal-access', N'system/mail/account/index', N'SystemMailAccount', 0, N'1', N'1', N'1', N'', N'2023-01-25 09:33:48', N'1', N'2024-02-29 08:48:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, N'账号查询', N'system:mail-account:query', 3, 1, 2131, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 09:33:48', N'', N'2023-01-25 09:33:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, N'账号创建', N'system:mail-account:create', 3, 2, 2131, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 09:33:48', N'', N'2023-01-25 09:33:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, N'账号更新', N'system:mail-account:update', 3, 3, 2131, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 09:33:48', N'', N'2023-01-25 09:33:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, N'账号删除', N'system:mail-account:delete', 3, 4, 2131, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 09:33:48', N'', N'2023-01-25 09:33:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, N'邮件模版', N'', 2, 0, 2130, N'mail-template', N'fa:tag', N'system/mail/template/index', N'SystemMailTemplate', 0, N'1', N'1', N'1', N'', N'2023-01-25 12:05:31', N'1', N'2024-02-29 08:48:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, N'模版查询', N'system:mail-template:query', 3, 1, 2136, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 12:05:31', N'', N'2023-01-25 12:05:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, N'模版创建', N'system:mail-template:create', 3, 2, 2136, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 12:05:31', N'', N'2023-01-25 12:05:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, N'模版更新', N'system:mail-template:update', 3, 3, 2136, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 12:05:31', N'', N'2023-01-25 12:05:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, N'模版删除', N'system:mail-template:delete', 3, 4, 2136, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-25 12:05:31', N'', N'2023-01-25 12:05:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, N'邮件记录', N'', 2, 0, 2130, N'mail-log', N'fa:edit', N'system/mail/log/index', N'SystemMailLog', 0, N'1', N'1', N'1', N'', N'2023-01-26 02:16:50', N'1', N'2024-02-29 08:48:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, N'日志查询', N'system:mail-log:query', 3, 1, 2141, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-26 02:16:50', N'', N'2023-01-26 02:16:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, N'发送测试邮件', N'system:mail-template:send-mail', 3, 5, 2136, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-26 23:29:15', N'1', N'2023-01-26 23:29:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, N'站内信管理', N'', 1, 3, 2739, N'notify', N'ep:message-box', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-28 10:25:18', N'1', N'2024-04-22 23:56:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, N'模板管理', N'', 2, 0, 2144, N'notify-template', N'fa:archive', N'system/notify/template/index', N'SystemNotifyTemplate', 0, N'1', N'1', N'1', N'', N'2023-01-28 02:26:42', N'1', N'2024-02-29 08:49:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, N'站内信模板查询', N'system:notify-template:query', 3, 1, 2145, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-28 02:26:42', N'', N'2023-01-28 02:26:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, N'站内信模板创建', N'system:notify-template:create', 3, 2, 2145, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-28 02:26:42', N'', N'2023-01-28 02:26:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, N'站内信模板更新', N'system:notify-template:update', 3, 3, 2145, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-28 02:26:42', N'', N'2023-01-28 02:26:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, N'站内信模板删除', N'system:notify-template:delete', 3, 4, 2145, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-28 02:26:42', N'', N'2023-01-28 02:26:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, N'发送测试站内信', N'system:notify-template:send-notify', 3, 5, 2145, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-01-28 10:54:43', N'1', N'2023-01-28 10:54:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, N'消息记录', N'', 2, 0, 2144, N'notify-message', N'fa:edit', N'system/notify/message/index', N'SystemNotifyMessage', 0, N'1', N'1', N'1', N'', N'2023-01-28 04:28:22', N'1', N'2024-02-29 08:49:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, N'站内信消息查询', N'system:notify-message:query', 3, 1, 2151, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-01-28 04:28:22', N'', N'2023-01-28 04:28:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, N'大屏设计器', N'', 2, 2, 1281, N'go-view', N'fa:area-chart', N'report/goview/index', N'JimuReport', 0, N'1', N'1', N'1', N'1', N'2023-02-07 00:03:19', N'1', N'2024-02-29 12:34:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, N'创建项目', N'report:go-view-project:create', 3, 1, 2153, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-07 19:25:14', N'1', N'2023-02-07 19:25:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, N'更新项目', N'report:go-view-project:update', 3, 2, 2153, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-02-07 19:25:34', N'1', N'2024-04-24 20:01:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, N'查询项目', N'report:go-view-project:query', 3, 0, 2153, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-07 19:25:53', N'1', N'2023-02-07 19:25:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, N'使用 SQL 查询数据', N'report:go-view-data:get-by-sql', 3, 3, 2153, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-07 19:26:15', N'1', N'2023-02-07 19:26:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, N'使用 HTTP 查询数据', N'report:go-view-data:get-by-http', 3, 4, 2153, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-07 19:26:35', N'1', N'2023-02-07 19:26:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, N'Boot 开发文档', N'', 1, 1, 0, N'https://doc.iocoder.cn/', N'ep:document', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-10 22:46:28', N'1', N'2023-12-02 21:32:20', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, N'Cloud 开发文档', N'', 1, 2, 0, N'https://cloud.iocoder.cn', N'ep:document-copy', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-02-10 22:47:07', N'1', N'2023-12-02 21:32:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, N'接入示例', N'', 1, 99, 1117, N'demo', N'fa-solid:dragon', N'pay/demo/index', NULL, 0, N'1', N'1', N'1', N'', N'2023-02-11 14:21:42', N'1', N'2024-01-18 23:50:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, N'商品导出', N'product:spu:export', 3, 5, 2014, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2022-07-30 14:22:58', N'', N'2022-07-30 14:22:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, N'配送管理', N'', 1, 3, 2072, N'delivery', N'ep:shopping-cart', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-05-18 09:18:02', N'1', N'2023-09-28 10:58:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, N'快递发货', N'', 1, 0, 2164, N'express', N'ep:bicycle', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-05-18 09:22:06', N'1', N'2023-08-30 21:02:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, N'门店自提', N'', 1, 1, 2164, N'pick-up-store', N'ep:add-location', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-05-18 09:23:14', N'1', N'2023-08-30 21:03:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, N'快递公司', N'', 2, 0, 2165, N'express', N'ep:compass', N'mall/trade/delivery/express/index', N'Express', 0, N'1', N'1', N'1', N'1', N'2023-05-18 09:27:21', N'1', N'2023-08-30 21:02:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, N'快递公司查询', N'trade:delivery:express:query', 3, 1, 2167, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-18 09:37:53', N'', N'2023-05-18 09:37:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, N'快递公司创建', N'trade:delivery:express:create', 3, 2, 2167, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-18 09:37:53', N'', N'2023-05-18 09:37:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, N'快递公司更新', N'trade:delivery:express:update', 3, 3, 2167, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-18 09:37:53', N'', N'2023-05-18 09:37:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, N'快递公司删除', N'trade:delivery:express:delete', 3, 4, 2167, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-18 09:37:53', N'', N'2023-05-18 09:37:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, N'快递公司导出', N'trade:delivery:express:export', 3, 5, 2167, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-18 09:37:53', N'', N'2023-05-18 09:37:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, N'运费模版', N'trade:delivery:express-template:query', 2, 1, 2165, N'express-template', N'ep:coordinate', N'mall/trade/delivery/expressTemplate/index', N'ExpressTemplate', 0, N'1', N'1', N'1', N'1', N'2023-05-20 06:48:10', N'1', N'2023-08-30 21:03:13', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, N'快递运费模板查询', N'trade:delivery:express-template:query', 3, 1, 2173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-20 06:49:53', N'', N'2023-05-20 06:49:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, N'快递运费模板创建', N'trade:delivery:express-template:create', 3, 2, 2173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-20 06:49:53', N'', N'2023-05-20 06:49:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, N'快递运费模板更新', N'trade:delivery:express-template:update', 3, 3, 2173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-20 06:49:53', N'', N'2023-05-20 06:49:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, N'快递运费模板删除', N'trade:delivery:express-template:delete', 3, 4, 2173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-20 06:49:53', N'', N'2023-05-20 06:49:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, N'快递运费模板导出', N'trade:delivery:express-template:export', 3, 5, 2173, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-20 06:49:53', N'', N'2023-05-20 06:49:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, N'门店管理', N'', 2, 1, 2166, N'pick-up-store', N'ep:basketball', N'mall/trade/delivery/pickUpStore/index', N'PickUpStore', 0, N'1', N'1', N'1', N'1', N'2023-05-25 10:50:00', N'1', N'2023-08-30 21:03:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, N'自提门店查询', N'trade:delivery:pick-up-store:query', 3, 1, 2179, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-25 10:53:29', N'', N'2023-05-25 10:53:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, N'自提门店创建', N'trade:delivery:pick-up-store:create', 3, 2, 2179, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-25 10:53:29', N'', N'2023-05-25 10:53:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, N'自提门店更新', N'trade:delivery:pick-up-store:update', 3, 3, 2179, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-25 10:53:29', N'', N'2023-05-25 10:53:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, N'自提门店删除', N'trade:delivery:pick-up-store:delete', 3, 4, 2179, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-25 10:53:29', N'', N'2023-05-25 10:53:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, N'自提门店导出', N'trade:delivery:pick-up-store:export', 3, 5, 2179, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-05-25 10:53:29', N'', N'2023-05-25 10:53:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, N'秒杀活动', N'', 2, 3, 2030, N'seckill', N'ep:place', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-06-24 17:39:13', N'1', N'2023-06-24 18:55:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, N'会员中心', N'', 1, 55, 0, N'/member', N'ep:bicycle', NULL, NULL, 0, N'1', N'1', N'1', N'1', N'2023-06-10 00:42:03', N'1', N'2023-08-20 09:23:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, N'会员配置', N'', 2, 0, 2262, N'config', N'fa:archive', N'member/config/index', N'MemberConfig', 0, N'1', N'1', N'1', N'', N'2023-06-10 02:07:44', N'1', N'2023-10-01 23:41:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, N'会员配置查询', N'member:config:query', 3, 1, 2275, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-06-10 02:07:44', N'1', N'2024-04-24 19:48:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, N'会员配置保存', N'member:config:save', 3, 2, 2275, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-06-10 02:07:44', N'1', N'2024-04-24 19:49:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, N'签到配置', N'', 2, 2, 2300, N'config', N'ep:calendar', N'member/signin/config/index', N'SignInConfig', 0, N'1', N'1', N'1', N'', N'2023-06-10 03:26:12', N'1', N'2023-08-20 19:25:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, N'积分签到规则查询', N'point:sign-in-config:query', 3, 1, 2281, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 03:26:12', N'', N'2023-06-10 03:26:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, N'积分签到规则创建', N'point:sign-in-config:create', 3, 2, 2281, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 03:26:12', N'', N'2023-06-10 03:26:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, N'积分签到规则更新', N'point:sign-in-config:update', 3, 3, 2281, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 03:26:12', N'', N'2023-06-10 03:26:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, N'积分签到规则删除', N'point:sign-in-config:delete', 3, 4, 2281, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 03:26:12', N'', N'2023-06-10 03:26:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, N'会员积分', N'', 2, 10, 2262, N'record', N'fa:asterisk', N'member/point/record/index', N'PointRecord', 0, N'1', N'1', N'1', N'', N'2023-06-10 04:18:50', N'1', N'2023-10-01 23:42:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, N'用户积分记录查询', N'point:record:query', 3, 1, 2287, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 04:18:50', N'', N'2023-06-10 04:18:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, N'签到记录', N'', 2, 3, 2300, N'record', N'ep:chicken', N'member/signin/record/index', N'SignInRecord', 0, N'1', N'1', N'1', N'', N'2023-06-10 04:48:22', N'1', N'2023-08-20 19:26:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, N'用户签到积分查询', N'point:sign-in-record:query', 3, 1, 2293, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 04:48:22', N'', N'2023-06-10 04:48:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, N'用户签到积分删除', N'point:sign-in-record:delete', 3, 4, 2293, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-06-10 04:48:22', N'', N'2023-06-10 04:48:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, N'会员签到', N'', 1, 11, 2262, N'signin', N'ep:alarm-clock', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-06-27 22:49:53', N'1', N'2023-08-20 09:23:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, N'回调通知', N'', 2, 5, 1117, N'notify', N'ep:mute-notification', N'pay/notify/index', N'PayNotify', 0, N'1', N'1', N'1', N'', N'2023-07-20 04:41:32', N'1', N'2024-01-18 23:56:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, N'支付通知查询', N'pay:notify:query', 3, 1, 2301, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-07-20 04:41:32', N'', N'2023-07-20 04:41:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, N'拼团活动', N'', 2, 3, 2030, N'combination', N'fa:group', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:19:54', N'1', N'2023-08-12 17:20:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, N'拼团商品', N'', 2, 1, 2303, N'acitivity', N'ep:apple', N'mall/promotion/combination/activity/index', N'PromotionCombinationActivity', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:22:03', N'1', N'2023-08-12 17:22:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, N'拼团活动查询', N'promotion:combination-activity:query', 3, 1, 2304, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:54:32', N'1', N'2023-11-24 11:57:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, N'拼团活动创建', N'promotion:combination-activity:create', 3, 2, 2304, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:54:49', N'1', N'2023-08-12 17:54:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, N'拼团活动更新', N'promotion:combination-activity:update', 3, 3, 2304, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:55:04', N'1', N'2023-08-12 17:55:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, N'拼团活动删除', N'promotion:combination-activity:delete', 3, 4, 2304, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:55:23', N'1', N'2023-08-12 17:55:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, N'拼团活动关闭', N'promotion:combination-activity:close', 3, 5, 2304, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-12 17:55:37', N'1', N'2023-10-06 10:51:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, N'砍价活动', N'', 2, 4, 2030, N'bargain', N'ep:box', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:27:25', N'1', N'2023-08-13 00:27:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, N'砍价商品', N'', 2, 1, 2310, N'activity', N'ep:burger', N'mall/promotion/bargain/activity/index', N'PromotionBargainActivity', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:28:49', N'1', N'2023-10-05 01:16:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, N'砍价活动查询', N'promotion:bargain-activity:query', 3, 1, 2311, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:32:30', N'1', N'2023-08-13 00:32:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, N'砍价活动创建', N'promotion:bargain-activity:create', 3, 2, 2311, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:32:44', N'1', N'2023-08-13 00:32:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, N'砍价活动更新', N'promotion:bargain-activity:update', 3, 3, 2311, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:32:55', N'1', N'2023-08-13 00:32:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, N'砍价活动删除', N'promotion:bargain-activity:delete', 3, 4, 2311, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:34:50', N'1', N'2023-08-13 00:34:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, N'砍价活动关闭', N'promotion:bargain-activity:close', 3, 5, 2311, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-13 00:35:02', N'1', N'2023-08-13 00:35:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, N'会员管理', N'', 2, 0, 2262, N'user', N'ep:avatar', N'member/user/index', N'MemberUser', 0, N'1', N'1', N'1', N'', N'2023-08-19 04:12:15', N'1', N'2023-08-24 00:50:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, N'会员用户查询', N'member:user:query', 3, 1, 2317, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-19 04:12:15', N'', N'2023-08-19 04:12:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, N'会员用户更新', N'member:user:update', 3, 3, 2317, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-19 04:12:15', N'', N'2023-08-19 04:12:15', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, N'会员标签', N'', 2, 1, 2262, N'tag', N'ep:collection-tag', N'member/tag/index', N'MemberTag', 0, N'1', N'1', N'1', N'', N'2023-08-20 01:03:08', N'1', N'2023-08-20 09:23:19', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, N'会员标签查询', N'member:tag:query', 3, 1, 2320, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-20 01:03:08', N'', N'2023-08-20 01:03:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, N'会员标签创建', N'member:tag:create', 3, 2, 2320, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-20 01:03:08', N'', N'2023-08-20 01:03:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, N'会员标签更新', N'member:tag:update', 3, 3, 2320, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-20 01:03:08', N'', N'2023-08-20 01:03:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, N'会员标签删除', N'member:tag:delete', 3, 4, 2320, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-20 01:03:08', N'', N'2023-08-20 01:03:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, N'会员等级', N'', 2, 2, 2262, N'level', N'fa:level-up', N'member/level/index', N'MemberLevel', 0, N'1', N'1', N'1', N'', N'2023-08-22 12:41:01', N'1', N'2023-08-22 21:47:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, N'会员等级查询', N'member:level:query', 3, 1, 2325, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 12:41:02', N'', N'2023-08-22 12:41:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, N'会员等级创建', N'member:level:create', 3, 2, 2325, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 12:41:02', N'', N'2023-08-22 12:41:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, N'会员等级更新', N'member:level:update', 3, 3, 2325, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 12:41:02', N'', N'2023-08-22 12:41:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, N'会员等级删除', N'member:level:delete', 3, 4, 2325, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 12:41:02', N'', N'2023-08-22 12:41:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, N'会员分组', N'', 2, 3, 2262, N'group', N'fa:group', N'member/group/index', N'MemberGroup', 0, N'1', N'1', N'1', N'', N'2023-08-22 13:50:06', N'1', N'2023-10-01 23:42:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, N'用户分组查询', N'member:group:query', 3, 1, 2330, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 13:50:06', N'', N'2023-08-22 13:50:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, N'用户分组创建', N'member:group:create', 3, 2, 2330, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 13:50:06', N'', N'2023-08-22 13:50:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, N'用户分组更新', N'member:group:update', 3, 3, 2330, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 13:50:06', N'', N'2023-08-22 13:50:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, N'用户分组删除', N'member:group:delete', 3, 4, 2330, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-22 13:50:06', N'', N'2023-08-22 13:50:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, N'用户等级修改', N'member:user:update-level', 3, 5, 2317, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-08-23 16:49:05', N'', N'2023-08-23 16:50:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, N'商品评论', N'', 2, 5, 2000, N'comment', N'ep:comment', N'mall/product/comment/index', N'ProductComment', 0, N'1', N'1', N'1', N'1', N'2023-08-26 11:03:00', N'1', N'2023-08-26 11:03:38', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, N'评论查询', N'product:comment:query', 3, 1, 2336, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-26 11:04:01', N'1', N'2023-08-26 11:04:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, N'添加自评', N'product:comment:create', 3, 2, 2336, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-26 11:04:23', N'1', N'2023-08-26 11:08:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, N'商家回复', N'product:comment:update', 3, 3, 2336, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-26 11:04:37', N'1', N'2023-08-26 11:04:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, N'显隐评论', N'product:comment:update', 3, 4, 2336, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-08-26 11:04:55', N'1', N'2023-08-26 11:04:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, N'优惠劵发送', N'promotion:coupon:send', 3, 2, 2038, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-09-02 00:03:14', N'1', N'2023-09-02 00:03:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, N'交易配置', N'', 2, 0, 2072, N'config', N'ep:setting', N'mall/trade/config/index', N'TradeConfig', 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'1', N'2024-02-26 20:30:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, N'交易中心配置查询', N'trade:config:query', 3, 1, 2342, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, N'交易中心配置保存', N'trade:config:save', 3, 2, 2342, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, N'分销管理', N'', 1, 4, 2072, N'brokerage', N'fa-solid:project-diagram', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'1', N'2023-09-28 10:58:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, N'分销用户', N'', 2, 0, 2345, N'brokerage-user', N'fa-solid:user-tie', N'mall/trade/brokerage/user/index', N'TradeBrokerageUser', 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'1', N'2024-02-26 20:33:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, N'分销用户查询', N'trade:brokerage-user:query', 3, 1, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, N'分销用户推广人查询', N'trade:brokerage-user:user-query', 3, 2, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, N'分销用户推广订单查询', N'trade:brokerage-user:order-query', 3, 3, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, N'分销用户修改推广资格', N'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, N'分销用户修改推广员', N'trade:brokerage-user:update-bind-user', 3, 5, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, N'分销用户清除推广员', N'trade:brokerage-user:clear-bind-user', 3, 6, 2346, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, N'佣金记录', N'', 2, 1, 2345, N'brokerage-record', N'fa:money', N'mall/trade/brokerage/record/index', N'TradeBrokerageRecord', 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'1', N'2024-02-26 20:33:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, N'佣金记录查询', N'trade:brokerage-record:query', 3, 1, 2353, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, N'佣金提现', N'', 2, 2, 2345, N'brokerage-withdraw', N'fa:credit-card', N'mall/trade/brokerage/withdraw/index', N'TradeBrokerageWithdraw', 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'1', N'2024-02-26 20:33:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, N'佣金提现查询', N'trade:brokerage-withdraw:query', 3, 1, 2355, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, N'佣金提现审核', N'trade:brokerage-withdraw:audit', 3, 2, 2355, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-28 02:46:22', N'', N'2023-09-28 02:46:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, N'统计中心', N'', 1, 75, 2362, N'statistics', N'ep:data-line', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-09-30 03:22:40', N'1', N'2023-09-30 11:54:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, N'交易统计', N'', 2, 4, 2358, N'trade', N'fa-solid:credit-card', N'mall/statistics/trade/index', N'TradeStatistics', 0, N'1', N'1', N'1', N'', N'2023-09-30 03:22:40', N'1', N'2024-02-26 20:42:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, N'交易统计查询', N'statistics:trade:query', 3, 1, 2359, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-30 03:22:40', N'', N'2023-09-30 03:22:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, N'交易统计导出', N'statistics:trade:export', 3, 2, 2359, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-09-30 03:22:40', N'', N'2023-09-30 03:22:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, N'商城系统', N'', 1, 59, 0, N'/mall', N'ep:shop', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-09-30 11:52:02', N'1', N'2023-09-30 11:52:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, N'用户积分修改', N'member:user:update-point', 3, 6, 2317, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-01 14:39:43', N'', N'2023-10-01 14:39:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, N'用户余额修改', N'member:user:update-balance', 3, 7, 2317, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-10-01 14:39:43', N'1', N'2023-10-01 22:42:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, N'优惠劵', N'', 1, 2, 2030, N'coupon', N'fa-solid:disease', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-03 12:39:15', N'1', N'2023-10-05 00:16:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, N'砍价记录', N'', 2, 2, 2310, N'record', N'ep:list', N'mall/promotion/bargain/record/index', N'PromotionBargainRecord', 0, N'1', N'1', N'1', N'', N'2023-10-05 02:49:06', N'1', N'2023-10-05 10:50:38', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, N'砍价记录查询', N'promotion:bargain-record:query', 3, 1, 2366, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-05 02:49:06', N'', N'2023-10-05 02:49:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, N'助力记录查询', N'promotion:bargain-help:query', 3, 2, 2366, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-05 12:27:49', N'1', N'2023-10-05 12:27:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, N'拼团记录', N'promotion:combination-record:query', 2, 2, 2303, N'record', N'ep:avatar', N'mall/promotion/combination/record/index.vue', N'PromotionCombinationRecord', 0, N'1', N'1', N'1', N'1', N'2023-10-08 07:10:22', N'1', N'2023-10-08 07:34:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, N'会员统计', N'', 2, 2, 2358, N'member', N'ep:avatar', N'mall/statistics/member/index', N'MemberStatistics', 0, N'1', N'1', N'1', N'', N'2023-10-11 04:39:24', N'1', N'2024-02-26 20:41:46', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, N'会员统计查询', N'statistics:member:query', 3, 1, 2374, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-11 04:39:24', N'', N'2023-10-11 04:39:24', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, N'订单核销', N'trade:order:pick-up', 3, 10, 2076, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-14 17:11:58', N'1', N'2023-10-14 17:11:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, N'文章分类', N'', 2, 0, 2387, N'article/category', N'fa:certificate', N'mall/promotion/article/category/index', N'ArticleCategory', 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'1', N'2023-10-16 09:38:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, N'分类查询', N'promotion:article-category:query', 3, 1, 2377, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, N'分类创建', N'promotion:article-category:create', 3, 2, 2377, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, N'分类更新', N'promotion:article-category:update', 3, 3, 2377, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, N'分类删除', N'promotion:article-category:delete', 3, 4, 2377, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, N'文章列表', N'', 2, 2, 2387, N'article', N'ep:connection', N'mall/promotion/article/index', N'Article', 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'1', N'2023-10-16 09:41:19', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, N'文章管理查询', N'promotion:article:query', 3, 1, 2382, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, N'文章管理创建', N'promotion:article:create', 3, 2, 2382, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, N'文章管理更新', N'promotion:article:update', 3, 3, 2382, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, N'文章管理删除', N'promotion:article:delete', 3, 4, 2382, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-16 01:26:18', N'', N'2023-10-16 01:26:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, N'内容管理', N'', 1, 1, 2030, N'content', N'ep:collection', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-16 09:37:31', N'1', N'2023-10-16 09:37:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, N'商城首页', N'', 2, 1, 2362, N'home', N'ep:home-filled', N'mall/home/index', N'MallHome', 0, N'1', N'1', N'1', N'', N'2023-10-16 12:10:33', N'', N'2023-10-16 12:10:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, N'核销订单', N'', 2, 2, 2166, N'pick-up-order', N'ep:list', N'mall/trade/delivery/pickUpOrder/index', N'PickUpOrder', 0, N'1', N'1', N'1', N'', N'2023-10-19 16:09:51', N'', N'2023-10-19 16:09:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, N'优惠活动', N'', 1, 99, 2030, N'youhui', N'ep:aim', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-21 19:23:49', N'1', N'2023-10-21 19:23:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, N'客户管理', N'', 2, 10, 2397, N'customer', N'fa:address-book-o', N'crm/customer/index', N'CrmCustomer', 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'1', N'2024-02-17 17:13:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, N'客户查询', N'crm:customer:query', 3, 1, 2391, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'', N'2023-10-29 09:04:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, N'客户创建', N'crm:customer:create', 3, 2, 2391, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'', N'2023-10-29 09:04:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, N'客户更新', N'crm:customer:update', 3, 3, 2391, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'', N'2023-10-29 09:04:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, N'客户删除', N'crm:customer:delete', 3, 4, 2391, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'', N'2023-10-29 09:04:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, N'客户导出', N'crm:customer:export', 3, 5, 2391, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 09:04:21', N'', N'2023-10-29 09:04:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, N'CRM 系统', N'', 1, 200, 0, N'/crm', N'ep:avatar', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-10-29 17:08:30', N'1', N'2024-02-04 15:37:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, N'合同管理', N'', 2, 50, 2397, N'contract', N'ep:notebook', N'crm/contract/index', N'CrmContract', 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'1', N'2024-02-17 17:15:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, N'合同查询', N'crm:contract:query', 3, 1, 2398, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'', N'2023-10-29 10:50:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, N'合同创建', N'crm:contract:create', 3, 2, 2398, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'', N'2023-10-29 10:50:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, N'合同更新', N'crm:contract:update', 3, 3, 2398, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'', N'2023-10-29 10:50:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, N'合同删除', N'crm:contract:delete', 3, 4, 2398, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'', N'2023-10-29 10:50:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, N'合同导出', N'crm:contract:export', 3, 5, 2398, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 10:50:41', N'', N'2023-10-29 10:50:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, N'线索管理', N'', 2, 8, 2397, N'clue', N'fa:pagelines', N'crm/clue/index', N'CrmClue', 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'1', N'2024-02-17 17:15:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, N'线索查询', N'crm:clue:query', 3, 1, 2404, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'', N'2023-10-29 11:06:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, N'线索创建', N'crm:clue:create', 3, 2, 2404, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'', N'2023-10-29 11:06:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, N'线索更新', N'crm:clue:update', 3, 3, 2404, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'', N'2023-10-29 11:06:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, N'线索删除', N'crm:clue:delete', 3, 4, 2404, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'', N'2023-10-29 11:06:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, N'线索导出', N'crm:clue:export', 3, 5, 2404, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:06:29', N'', N'2023-10-29 11:06:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, N'商机管理', N'', 2, 40, 2397, N'business', N'fa:bus', N'crm/business/index', N'CrmBusiness', 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'1', N'2024-02-17 17:14:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, N'商机查询', N'crm:business:query', 3, 1, 2410, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'', N'2023-10-29 11:12:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, N'商机创建', N'crm:business:create', 3, 2, 2410, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'', N'2023-10-29 11:12:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, N'商机更新', N'crm:business:update', 3, 3, 2410, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'', N'2023-10-29 11:12:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, N'商机删除', N'crm:business:delete', 3, 4, 2410, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'', N'2023-10-29 11:12:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, N'商机导出', N'crm:business:export', 3, 5, 2410, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:12:35', N'', N'2023-10-29 11:12:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, N'联系人管理', N'', 2, 20, 2397, N'contact', N'fa:address-book-o', N'crm/contact/index', N'CrmContact', 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'1', N'2024-02-17 17:13:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, N'联系人查询', N'crm:contact:query', 3, 1, 2416, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'', N'2023-10-29 11:14:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, N'联系人创建', N'crm:contact:create', 3, 2, 2416, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'', N'2023-10-29 11:14:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, N'联系人更新', N'crm:contact:update', 3, 3, 2416, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'', N'2023-10-29 11:14:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, N'联系人删除', N'crm:contact:delete', 3, 4, 2416, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'', N'2023-10-29 11:14:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, N'联系人导出', N'crm:contact:export', 3, 5, 2416, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:14:56', N'', N'2023-10-29 11:14:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, N'回款管理', N'', 2, 60, 2397, N'receivable', N'ep:money', N'crm/receivable/index', N'CrmReceivable', 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'1', N'2024-02-17 17:16:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, N'回款管理查询', N'crm:receivable:query', 3, 1, 2422, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, N'回款管理创建', N'crm:receivable:create', 3, 2, 2422, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, N'回款管理更新', N'crm:receivable:update', 3, 3, 2422, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, N'回款管理删除', N'crm:receivable:delete', 3, 4, 2422, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, N'回款管理导出', N'crm:receivable:export', 3, 5, 2422, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, N'回款计划', N'', 2, 61, 2397, N'receivable-plan', N'fa:money', N'crm/receivable/plan/index', N'CrmReceivablePlan', 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'1', N'2024-02-17 17:16:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, N'回款计划查询', N'crm:receivable-plan:query', 3, 1, 2428, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, N'回款计划创建', N'crm:receivable-plan:create', 3, 2, 2428, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, N'回款计划更新', N'crm:receivable-plan:update', 3, 3, 2428, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, N'回款计划删除', N'crm:receivable-plan:delete', 3, 4, 2428, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, N'回款计划导出', N'crm:receivable-plan:export', 3, 5, 2428, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 11:18:09', N'', N'2023-10-29 11:18:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, N'商城装修', N'', 2, 20, 2030, N'diy-template', N'fa6-solid:brush', N'mall/promotion/diy/template/index', N'DiyTemplate', 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, N'装修模板', N'', 2, 1, 2435, N'diy-template', N'fa6-solid:brush', N'mall/promotion/diy/template/index', N'DiyTemplate', 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, N'装修模板查询', N'promotion:diy-template:query', 3, 1, 2436, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, N'装修模板创建', N'promotion:diy-template:create', 3, 2, 2436, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, N'装修模板更新', N'promotion:diy-template:update', 3, 3, 2436, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, N'装修模板删除', N'promotion:diy-template:delete', 3, 4, 2436, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, N'装修模板使用', N'promotion:diy-template:use', 3, 5, 2436, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, N'装修页面', N'', 2, 2, 2435, N'diy-page', N'foundation:page-edit', N'mall/promotion/diy/page/index', N'DiyPage', 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, N'装修页面查询', N'promotion:diy-page:query', 3, 1, 2442, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:25', N'', N'2023-10-29 14:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, N'装修页面创建', N'promotion:diy-page:create', 3, 2, 2442, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:26', N'', N'2023-10-29 14:19:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, N'装修页面更新', N'promotion:diy-page:update', 3, 3, 2442, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:26', N'', N'2023-10-29 14:19:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, N'装修页面删除', N'promotion:diy-page:delete', 3, 4, 2442, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-10-29 14:19:26', N'', N'2023-10-29 14:19:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, N'三方登录', N'', 1, 10, 1, N'social', N'fa:rocket', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:12:01', N'1', N'2024-02-29 01:14:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, N'三方应用', N'', 2, 1, 2447, N'client', N'ep:set-up', N'views/system/social/client/index.vue', N'SocialClient', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:17:19', N'1', N'2023-11-04 12:17:19', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, N'三方应用查询', N'system:social-client:query', 3, 1, 2448, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:43:12', N'1', N'2023-11-04 12:43:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, N'三方应用创建', N'system:social-client:create', 3, 2, 2448, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:43:58', N'1', N'2023-11-04 12:43:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, N'三方应用更新', N'system:social-client:update', 3, 3, 2448, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:44:27', N'1', N'2023-11-04 12:44:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, N'三方应用删除', N'system:social-client:delete', 3, 4, 2448, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-04 12:44:43', N'1', N'2023-11-04 12:44:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, N'三方用户', N'system:social-user:query', 2, 2, 2447, N'user', N'ep:avatar', N'system/social/user/index.vue', N'SocialUser', 0, N'1', N'1', N'1', N'1', N'2023-11-04 14:01:05', N'1', N'2023-11-04 14:01:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, N'主子表(内嵌)', N'', 2, 12, 1070, N'demo03-inner', N'fa:power-off', N'infra/demo/demo03/inner/index', N'Demo03StudentInner', 0, N'1', N'1', N'1', N'', N'2023-11-13 04:39:51', N'1', N'2023-11-16 23:53:46', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, N'单表(增删改查)', N'', 2, 1, 1070, N'demo01-contact', N'ep:bicycle', N'infra/demo/demo01/index', N'Demo01Contact', 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'1', N'2023-11-16 20:34:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, N'示例联系人查询', N'infra:demo01-contact:query', 3, 1, 2478, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'', N'2023-11-15 14:42:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, N'示例联系人创建', N'infra:demo01-contact:create', 3, 2, 2478, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'', N'2023-11-15 14:42:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, N'示例联系人更新', N'infra:demo01-contact:update', 3, 3, 2478, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'', N'2023-11-15 14:42:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, N'示例联系人删除', N'infra:demo01-contact:delete', 3, 4, 2478, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'', N'2023-11-15 14:42:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, N'示例联系人导出', N'infra:demo01-contact:export', 3, 5, 2478, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-15 14:42:30', N'', N'2023-11-15 14:42:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, N'树表(增删改查)', N'', 2, 2, 1070, N'demo02-category', N'fa:tree', N'infra/demo/demo02/index', N'Demo02Category', 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'1', N'2023-11-16 20:35:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, N'示例分类查询', N'infra:demo02-category:query', 3, 1, 2484, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'', N'2023-11-16 12:18:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, N'示例分类创建', N'infra:demo02-category:create', 3, 2, 2484, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'', N'2023-11-16 12:18:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, N'示例分类更新', N'infra:demo02-category:update', 3, 3, 2484, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'', N'2023-11-16 12:18:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, N'示例分类删除', N'infra:demo02-category:delete', 3, 4, 2484, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'', N'2023-11-16 12:18:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, N'示例分类导出', N'infra:demo02-category:export', 3, 5, 2484, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:18:27', N'', N'2023-11-16 12:18:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, N'主子表(标准)', N'', 2, 10, 1070, N'demo03-normal', N'fa:battery-3', N'infra/demo/demo03/normal/index', N'Demo03StudentNormal', 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'1', N'2023-11-16 23:10:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, N'学生查询', N'infra:demo03-student:query', 3, 1, 2490, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'', N'2023-11-16 12:53:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, N'学生创建', N'infra:demo03-student:create', 3, 2, 2490, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'', N'2023-11-16 12:53:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, N'学生更新', N'infra:demo03-student:update', 3, 3, 2490, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'', N'2023-11-16 12:53:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, N'学生删除', N'infra:demo03-student:delete', 3, 4, 2490, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'', N'2023-11-16 12:53:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, N'学生导出', N'infra:demo03-student:export', 3, 5, 2490, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-16 12:53:37', N'', N'2023-11-16 12:53:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, N'主子表(ERP)', N'', 2, 11, 1070, N'demo03-erp', N'ep:calendar', N'infra/demo/demo03/erp/index', N'Demo03StudentERP', 0, N'1', N'1', N'1', N'', N'2023-11-16 15:50:59', N'1', N'2023-11-17 13:19:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, N'客户公海配置', N'', 2, 0, 2524, N'customer-pool-config', N'ep:data-analysis', N'crm/customer/poolConfig/index', N'CrmCustomerPoolConfig', 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:31', N'1', N'2024-01-03 19:52:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, N'客户公海配置保存', N'crm:customer-pool-config:update', 3, 1, 2516, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:31', N'', N'2023-11-18 13:33:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, N'客户限制配置', N'', 2, 1, 2524, N'customer-limit-config', N'ep:avatar', N'crm/customer/limitConfig/index', N'CrmCustomerLimitConfig', 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'1', N'2024-02-24 16:43:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, N'客户限制配置查询', N'crm:customer-limit-config:query', 3, 1, 2518, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'', N'2023-11-18 13:33:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, N'客户限制配置创建', N'crm:customer-limit-config:create', 3, 2, 2518, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'', N'2023-11-18 13:33:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, N'客户限制配置更新', N'crm:customer-limit-config:update', 3, 3, 2518, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'', N'2023-11-18 13:33:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, N'客户限制配置删除', N'crm:customer-limit-config:delete', 3, 4, 2518, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'', N'2023-11-18 13:33:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, N'客户限制配置导出', N'crm:customer-limit-config:export', 3, 5, 2518, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-11-18 13:33:53', N'', N'2023-11-18 13:33:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, N'系统配置', N'', 1, 999, 2397, N'config', N'ep:connection', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-11-18 21:58:00', N'1', N'2024-02-17 17:14:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, N'WebSocket', N'', 2, 5, 2, N'websocket', N'ep:connection', N'infra/webSocket/index', N'InfraWebSocket', 0, N'1', N'1', N'1', N'1', N'2023-11-23 19:41:55', N'1', N'2024-04-23 00:02:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, N'产品管理', N'', 2, 80, 2397, N'product', N'fa:product-hunt', N'crm/product/index', N'CrmProduct', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:45:26', N'1', N'2024-02-20 20:36:20', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, N'产品查询', N'crm:product:query', 3, 1, 2526, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:47:16', N'1', N'2023-12-05 22:47:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, N'产品创建', N'crm:product:create', 3, 2, 2526, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:47:41', N'1', N'2023-12-05 22:47:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, N'产品更新', N'crm:product:update', 3, 3, 2526, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:48:03', N'1', N'2023-12-05 22:48:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, N'产品删除', N'crm:product:delete', 3, 4, 2526, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:48:17', N'1', N'2023-12-05 22:48:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, N'产品导出', N'crm:product:export', 3, 5, 2526, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-05 22:48:29', N'1', N'2023-12-05 22:48:29', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, N'产品分类配置', N'', 2, 3, 2524, N'product/category', N'fa-solid:window-restore', N'crm/product/category/index', N'CrmProductCategory', 0, N'1', N'1', N'1', N'1', N'2023-12-06 12:52:36', N'1', N'2023-12-06 12:52:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, N'产品分类查询', N'crm:product-category:query', 3, 1, 2532, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-06 12:53:23', N'1', N'2023-12-06 12:53:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, N'产品分类创建', N'crm:product-category:create', 3, 2, 2532, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-06 12:53:41', N'1', N'2023-12-06 12:53:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, N'产品分类更新', N'crm:product-category:update', 3, 3, 2532, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-06 12:53:59', N'1', N'2023-12-06 12:53:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, N'产品分类删除', N'crm:product-category:delete', 3, 4, 2532, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2023-12-06 12:54:14', N'1', N'2023-12-06 12:54:14', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, N'关联商机', N'crm:contact:create-business', 3, 10, 2416, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-02 17:28:25', N'1', N'2024-01-02 17:28:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, N'取关商机', N'crm:contact:delete-business', 3, 11, 2416, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-02 17:28:43', N'1', N'2024-01-02 17:28:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, N'商品统计', N'', 2, 3, 2358, N'product', N'fa:product-hunt', N'mall/statistics/product/index', N'ProductStatistics', 0, N'1', N'1', N'1', N'', N'2023-12-15 18:54:28', N'1', N'2024-02-26 20:41:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, N'客户公海', N'', 2, 30, 2397, N'customer/pool', N'fa-solid:swimming-pool', N'crm/customer/pool/index', N'CrmCustomerPool', 0, N'1', N'1', N'1', N'1', N'2024-01-15 21:29:34', N'1', N'2024-02-17 17:14:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, N'订单查询', N'trade:order:query', 3, 1, 2076, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-16 08:52:00', N'1', N'2024-01-16 08:52:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, N'订单更新', N'trade:order:update', 3, 2, 2076, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-16 08:52:21', N'1', N'2024-01-16 08:52:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, N'支付&退款案例', N'', 2, 1, 2161, N'order', N'fa:paypal', N'pay/demo/order/index', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-18 23:45:00', N'1', N'2024-01-18 23:47:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, N'转账案例', N'', 2, 2, 2161, N'transfer', N'fa:transgender-alt', N'pay/demo/transfer/index', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-18 23:51:16', N'1', N'2024-01-18 23:51:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, N'钱包管理', N'', 1, 4, 1117, N'wallet', N'ep:wallet', N'', N'', 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'1', N'2024-02-29 08:58:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, N'充值套餐', N'', 2, 2, 2551, N'wallet-recharge-package', N'fa:leaf', N'pay/wallet/rechargePackage/index', N'WalletRechargePackage', 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, N'钱包充值套餐查询', N'pay:wallet-recharge-package:query', 3, 1, 2552, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, N'钱包充值套餐创建', N'pay:wallet-recharge-package:create', 3, 2, 2552, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, N'钱包充值套餐更新', N'pay:wallet-recharge-package:update', 3, 3, 2552, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, N'钱包充值套餐删除', N'pay:wallet-recharge-package:delete', 3, 4, 2552, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, N'钱包余额', N'', 2, 1, 2551, N'wallet-balance', N'fa:leaf', N'pay/wallet/balance/index', N'WalletBalance', 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, N'钱包余额查询', N'pay:wallet:query', 3, 1, 2557, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, N'转账订单', N'', 2, 3, 1117, N'transfer', N'ep:credit-card', N'pay/transfer/index', N'PayTransfer', 0, N'1', N'1', N'1', N'', N'2023-12-29 02:32:54', N'', N'2023-12-29 02:32:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, N'数据统计', N'', 1, 200, 2397, N'statistics', N'ep:data-line', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-01-26 22:50:35', N'1', N'2024-02-24 20:10:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, N'排行榜', N'crm:statistics-rank:query', 2, 1, 2560, N'ranking', N'fa:area-chart', N'crm/statistics/rank/index', N'CrmStatisticsRank', 0, N'1', N'1', N'1', N'1', N'2024-01-26 22:52:09', N'1', N'2024-04-24 19:39:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, N'客户导入', N'crm:customer:import', 3, 6, 2391, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-01 13:09:00', N'1', N'2024-02-01 13:09:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, N'ERP 系统', N'', 1, 300, 0, N'/erp', N'fa-solid:store', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-04 15:37:25', N'1', N'2024-02-04 15:37:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, N'产品管理', N'', 1, 40, 2563, N'product', N'fa:product-hunt', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-04 15:38:43', N'1', N'2024-02-04 15:38:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, N'产品信息', N'', 2, 0, 2564, N'product', N'fa-solid:apple-alt', N'erp/product/product/index', N'ErpProduct', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-05 14:42:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, N'产品查询', N'erp:product:query', 3, 1, 2565, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-04 17:21:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, N'产品创建', N'erp:product:create', 3, 2, 2565, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-04 17:22:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, N'产品更新', N'erp:product:update', 3, 3, 2565, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-04 17:22:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, N'产品删除', N'erp:product:delete', 3, 4, 2565, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-04 17:22:22', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, N'产品导出', N'erp:product:export', 3, 5, 2565, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-02-04 07:52:15', N'1', N'2024-02-04 17:22:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, N'产品分类', N'', 2, 1, 2564, N'product-category', N'fa:certificate', N'erp/product/category/index', N'ErpProductCategory', 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'1', N'2024-02-04 17:24:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, N'分类查询', N'erp:product-category:query', 3, 1, 2571, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'', N'2024-02-04 09:21:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, N'分类创建', N'erp:product-category:create', 3, 2, 2571, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'', N'2024-02-04 09:21:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, N'分类更新', N'erp:product-category:update', 3, 3, 2571, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'', N'2024-02-04 09:21:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, N'分类删除', N'erp:product-category:delete', 3, 4, 2571, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'', N'2024-02-04 09:21:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, N'分类导出', N'erp:product-category:export', 3, 5, 2571, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 09:21:04', N'', N'2024-02-04 09:21:04', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, N'产品单位', N'', 2, 2, 2564, N'unit', N'ep:opportunity', N'erp/product/unit/index', N'ErpProductUnit', 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'1', N'2024-02-04 19:54:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, N'单位查询', N'erp:product-unit:query', 3, 1, 2577, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'', N'2024-02-04 11:54:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, N'单位创建', N'erp:product-unit:create', 3, 2, 2577, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'', N'2024-02-04 11:54:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, N'单位更新', N'erp:product-unit:update', 3, 3, 2577, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'', N'2024-02-04 11:54:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, N'单位删除', N'erp:product-unit:delete', 3, 4, 2577, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'', N'2024-02-04 11:54:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, N'单位导出', N'erp:product-unit:export', 3, 5, 2577, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 11:54:08', N'', N'2024-02-04 11:54:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, N'库存管理', N'', 1, 30, 2563, N'stock', N'fa:window-restore', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-05 00:29:37', N'1', N'2024-02-05 00:29:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, N'仓库信息', N'', 2, 0, 2583, N'warehouse', N'ep:house', N'erp/stock/warehouse/index', N'ErpWarehouse', 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'1', N'2024-02-05 01:12:53', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, N'仓库查询', N'erp:warehouse:query', 3, 1, 2584, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'', N'2024-02-04 17:12:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, N'仓库创建', N'erp:warehouse:create', 3, 2, 2584, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'', N'2024-02-04 17:12:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, N'仓库更新', N'erp:warehouse:update', 3, 3, 2584, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'', N'2024-02-04 17:12:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, N'仓库删除', N'erp:warehouse:delete', 3, 4, 2584, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'', N'2024-02-04 17:12:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, N'仓库导出', N'erp:warehouse:export', 3, 5, 2584, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-04 17:12:09', N'', N'2024-02-04 17:12:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, N'产品库存', N'', 2, 1, 2583, N'stock', N'ep:coffee', N'erp/stock/stock/index', N'ErpStock', 0, N'1', N'1', N'1', N'', N'2024-02-05 06:40:50', N'1', N'2024-02-05 14:42:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, N'库存查询', N'erp:stock:query', 3, 1, 2590, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 06:40:50', N'', N'2024-02-05 06:40:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, N'库存导出', N'erp:stock:export', 3, 5, 2590, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 06:40:50', N'', N'2024-02-05 06:40:50', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, N'出入库明细', N'', 2, 2, 2583, N'record', N'fa-solid:blog', N'erp/stock/record/index', N'ErpStockRecord', 0, N'1', N'1', N'1', N'', N'2024-02-05 10:27:21', N'1', N'2024-02-06 17:26:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, N'库存明细查询', N'erp:stock-record:query', 3, 1, 2593, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 10:27:21', N'', N'2024-02-05 10:27:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, N'库存明细导出', N'erp:stock-record:export', 3, 5, 2593, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 10:27:21', N'', N'2024-02-05 10:27:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, N'其它入库', N'', 2, 3, 2583, N'in', N'ep:zoom-in', N'erp/stock/in/index', N'ErpStockIn', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-07 19:06:51', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, N'其它入库单查询', N'erp:stock-in:query', 3, 1, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, N'其它入库单创建', N'erp:stock-in:create', 3, 2, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, N'其它入库单更新', N'erp:stock-in:update', 3, 3, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, N'其它入库单删除', N'erp:stock-in:delete', 3, 4, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, N'其它入库单导出', N'erp:stock-in:export', 3, 5, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, N'采购管理', N'', 1, 10, 2563, N'purchase', N'fa:buysellads', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-06 16:01:01', N'1', N'2024-02-06 16:01:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, N'供应商信息', N'', 2, 4, 2602, N'supplier', N'fa:superpowers', N'erp/purchase/supplier/index', N'ErpSupplier', 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'1', N'2024-02-06 16:22:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, N'供应商查询', N'erp:supplier:query', 3, 1, 2603, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'', N'2024-02-06 08:21:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, N'供应商创建', N'erp:supplier:create', 3, 2, 2603, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'', N'2024-02-06 08:21:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, N'供应商更新', N'erp:supplier:update', 3, 3, 2603, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'', N'2024-02-06 08:21:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, N'供应商删除', N'erp:supplier:delete', 3, 4, 2603, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'', N'2024-02-06 08:21:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, N'供应商导出', N'erp:supplier:export', 3, 5, 2603, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-06 08:21:55', N'', N'2024-02-06 08:21:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, N'其它入库单审批', N'erp:stock-in:update-status', 3, 6, 2596, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-05 16:08:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, N'其它出库', N'', 2, 4, 2583, N'out', N'ep:zoom-out', N'erp/stock/out/index', N'ErpStockOut', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-07 19:06:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, N'其它出库单查询', N'erp:stock-out:query', 3, 1, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:39', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, N'其它出库单创建', N'erp:stock-out:create', 3, 2, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, N'其它出库单更新', N'erp:stock-out:update', 3, 3, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, N'其它出库单删除', N'erp:stock-out:delete', 3, 4, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, N'其它出库单导出', N'erp:stock-out:export', 3, 5, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, N'其它出库单审批', N'erp:stock-out:update-status', 3, 6, 2610, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 06:43:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, N'销售管理', N'', 1, 20, 2563, N'sale', N'fa:sellsy', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-07 15:12:32', N'1', N'2024-02-07 15:12:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, N'客户信息', N'', 2, 4, 2617, N'customer', N'ep:avatar', N'erp/sale/customer/index', N'ErpCustomer', 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'1', N'2024-02-07 15:22:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, N'客户查询', N'erp:customer:query', 3, 1, 2618, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'', N'2024-02-07 07:21:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, N'客户创建', N'erp:customer:create', 3, 2, 2618, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'', N'2024-02-07 07:21:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, N'客户更新', N'erp:customer:update', 3, 3, 2618, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'', N'2024-02-07 07:21:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, N'客户删除', N'erp:customer:delete', 3, 4, 2618, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'', N'2024-02-07 07:21:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, N'客户导出', N'erp:customer:export', 3, 5, 2618, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-07 07:21:45', N'', N'2024-02-07 07:21:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, N'库存调拨', N'', 2, 5, 2583, N'move', N'ep:folder-remove', N'erp/stock/move/index', N'ErpStockMove', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-16 18:53:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, N'库存调度单查询', N'erp:stock-move:query', 3, 1, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, N'库存调度单创建', N'erp:stock-move:create', 3, 2, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, N'库存调度单更新', N'erp:stock-move:update', 3, 3, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, N'库存调度单删除', N'erp:stock-move:delete', 3, 4, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, N'库存调度单导出', N'erp:stock-move:export', 3, 5, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, N'库存调度单审批', N'erp:stock-move:update-status', 3, 6, 2624, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:13:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, N'库存盘点', N'', 2, 6, 2583, N'check', N'ep:circle-check-filled', N'erp/stock/check/index', N'ErpStockCheck', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-08 08:31:09', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, N'库存盘点单查询', N'erp:stock-check:query', 3, 1, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, N'库存盘点单创建', N'erp:stock-check:create', 3, 2, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, N'库存盘点单更新', N'erp:stock-check:update', 3, 3, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, N'库存盘点单删除', N'erp:stock-check:delete', 3, 4, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, N'库存盘点单导出', N'erp:stock-check:export', 3, 5, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, N'库存盘点单审批', N'erp:stock-check:update-status', 3, 6, 2631, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:13:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, N'销售订单', N'', 2, 1, 2617, N'order', N'fa:first-order', N'erp/sale/order/index', N'ErpSaleOrder', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-10 21:59:20', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, N'销售订单查询', N'erp:sale-order:query', 3, 1, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, N'销售订单创建', N'erp:sale-order:create', 3, 2, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, N'销售订单更新', N'erp:sale-order:update', 3, 3, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, N'销售订单删除', N'erp:sale-order:delete', 3, 4, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, N'销售订单导出', N'erp:sale-order:export', 3, 5, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, N'销售订单审批', N'erp:sale-order:update-status', 3, 6, 2638, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:13:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, N'财务管理', N'', 1, 50, 2563, N'finance', N'ep:money', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-10 08:05:58', N'1', N'2024-02-10 08:06:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, N'结算账户', N'', 2, 10, 2645, N'account', N'fa:universal-access', N'erp/finance/account/index', N'ErpAccount', 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'1', N'2024-02-14 08:24:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, N'结算账户查询', N'erp:account:query', 3, 1, 2646, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'', N'2024-02-10 00:15:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, N'结算账户创建', N'erp:account:create', 3, 2, 2646, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'', N'2024-02-10 00:15:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, N'结算账户更新', N'erp:account:update', 3, 3, 2646, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'', N'2024-02-10 00:15:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, N'结算账户删除', N'erp:account:delete', 3, 4, 2646, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'', N'2024-02-10 00:15:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, N'结算账户导出', N'erp:account:export', 3, 5, 2646, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-10 00:15:07', N'', N'2024-02-10 00:15:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, N'销售出库', N'', 2, 2, 2617, N'out', N'ep:sold-out', N'erp/sale/out/index', N'ErpSaleOut', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-10 22:02:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, N'销售出库查询', N'erp:sale-out:query', 3, 1, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, N'销售出库创建', N'erp:sale-out:create', 3, 2, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, N'销售出库更新', N'erp:sale-out:update', 3, 3, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, N'销售出库删除', N'erp:sale-out:delete', 3, 4, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, N'销售出库导出', N'erp:sale-out:export', 3, 5, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, N'销售出库审批', N'erp:sale-out:update-status', 3, 6, 2652, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:13:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, N'销售退货', N'', 2, 3, 2617, N'return', N'fa-solid:bone', N'erp/sale/return/index', N'ErpSaleReturn', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-12 06:12:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, N'销售退货查询', N'erp:sale-return:query', 3, 1, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, N'销售退货创建', N'erp:sale-return:create', 3, 2, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, N'销售退货更新', N'erp:sale-return:update', 3, 3, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:55', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, N'销售退货删除', N'erp:sale-return:delete', 3, 4, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, N'销售退货导出', N'erp:sale-return:export', 3, 5, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:12:59', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, N'销售退货审批', N'erp:sale-return:update-status', 3, 6, 2659, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-07 11:13:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, N'采购订单', N'', 2, 1, 2602, N'order', N'fa-solid:border-all', N'erp/purchase/order/index', N'ErpPurchaseOrder', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-12 08:51:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, N'采购订单查询', N'erp:purchase-order:query', 3, 1, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, N'采购订单创建', N'erp:purchase-order:create', 3, 2, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, N'采购订单更新', N'erp:purchase-order:update', 3, 3, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, N'采购订单删除', N'erp:purchase-order:delete', 3, 4, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, N'采购订单导出', N'erp:purchase-order:export', 3, 5, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, N'采购订单审批', N'erp:purchase-order:update-status', 3, 6, 2666, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, N'采购入库', N'', 2, 2, 2602, N'in', N'fa-solid:gopuram', N'erp/purchase/in/index', N'ErpPurchaseIn', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-12 11:19:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, N'采购入库查询', N'erp:purchase-in:query', 3, 1, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, N'采购入库创建', N'erp:purchase-in:create', 3, 2, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, N'采购入库更新', N'erp:purchase-in:update', 3, 3, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, N'采购入库删除', N'erp:purchase-in:delete', 3, 4, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, N'采购入库导出', N'erp:purchase-in:export', 3, 5, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, N'采购入库审批', N'erp:purchase-in:update-status', 3, 6, 2673, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, N'采购退货', N'', 2, 3, 2602, N'return', N'ep:minus', N'erp/purchase/return/index', N'ErpPurchaseReturn', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-12 20:51:02', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, N'采购退货查询', N'erp:purchase-return:query', 3, 1, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, N'采购退货创建', N'erp:purchase-return:create', 3, 2, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, N'采购退货更新', N'erp:purchase-return:update', 3, 3, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, N'采购退货删除', N'erp:purchase-return:delete', 3, 4, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, N'采购退货导出', N'erp:purchase-return:export', 3, 5, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, N'采购退货审批', N'erp:purchase-return:update-status', 3, 6, 2680, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, N'付款单', N'', 2, 1, 2645, N'payment', N'ep:caret-right', N'erp/finance/payment/index', N'ErpFinancePayment', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-14 08:24:23', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, N'付款单查询', N'erp:finance-payment:query', 3, 1, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, N'付款单创建', N'erp:finance-payment:create', 3, 2, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, N'付款单更新', N'erp:finance-payment:update', 3, 3, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, N'付款单删除', N'erp:finance-payment:delete', 3, 4, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, N'付款单导出', N'erp:finance-payment:export', 3, 5, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, N'付款单审批', N'erp:finance-payment:update-status', 3, 6, 2687, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, N'收款单', N'', 2, 2, 2645, N'receipt', N'ep:expand', N'erp/finance/receipt/index', N'ErpFinanceReceipt', 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'1', N'2024-02-15 19:35:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, N'收款单查询', N'erp:finance-receipt:query', 3, 1, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, N'收款单创建', N'erp:finance-receipt:create', 3, 2, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:54', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, N'收款单更新', N'erp:finance-receipt:update', 3, 3, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:44:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, N'收款单删除', N'erp:finance-receipt:delete', 3, 4, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:00', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, N'收款单导出', N'erp:finance-receipt:export', 3, 5, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, N'收款单审批', N'erp:finance-receipt:update-status', 3, 6, 2694, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-02-05 16:08:56', N'', N'2024-02-12 00:45:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, N'待办事项', N'', 2, 0, 2397, N'backlog', N'fa-solid:tasks', N'crm/backlog/index', N'CrmBacklog', 0, N'1', N'1', N'1', N'1', N'2024-02-17 17:17:11', N'1', N'2024-02-17 17:17:11', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, N'ERP 首页', N'erp:statistics:query', 2, 0, 2563, N'home', N'ep:home-filled', N'erp/home/index.vue', N'ErpHome', 0, N'1', N'1', N'1', N'1', N'2024-02-18 16:49:40', N'1', N'2024-02-26 21:12:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, N'商机状态配置', N'', 2, 4, 2524, N'business-status', N'fa-solid:charging-station', N'crm/business/status/index', N'CrmBusinessStatus', 0, N'1', N'1', N'1', N'1', N'2024-02-21 20:15:17', N'1', N'2024-02-21 20:15:17', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, N'商机状态查询', N'crm:business-status:query', 3, 1, 2703, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-21 20:35:36', N'1', N'2024-02-21 20:36:06', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, N'商机状态创建', N'crm:business-status:create', 3, 2, 2703, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-21 20:35:57', N'1', N'2024-02-21 20:35:57', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, N'商机状态更新', N'crm:business-status:update', 3, 3, 2703, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-21 20:36:21', N'1', N'2024-02-21 20:36:21', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, N'商机状态删除', N'crm:business-status:delete', 3, 4, 2703, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-21 20:36:36', N'1', N'2024-02-21 20:36:36', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, N'合同配置', N'', 2, 5, 2524, N'contract-config', N'ep:connection', N'crm/contract/config/index', N'CrmContractConfig', 0, N'1', N'1', N'1', N'1', N'2024-02-24 16:44:40', N'1', N'2024-02-24 16:44:48', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, N'客户公海配置查询', N'crm:customer-pool-config:query', 3, 2, 2516, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-24 16:45:19', N'1', N'2024-02-24 16:45:28', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, N'合同配置更新', N'crm:contract-config:update', 3, 1, 2708, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-24 16:45:56', N'1', N'2024-02-24 16:45:56', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, N'合同配置查询', N'crm:contract-config:query', 3, 2, 2708, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-02-24 16:46:16', N'1', N'2024-02-24 16:46:16', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, N'客户分析', N'crm:statistics-customer:query', 2, 0, 2560, N'customer', N'ep:avatar', N'views/crm/statistics/customer/index.vue', N'CrmStatisticsCustomer', 0, N'1', N'1', N'1', N'1', N'2024-03-09 16:43:56', N'1', N'2024-04-24 19:42:52', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, N'抄送我的', N'bpm:process-instance-cc:query', 2, 30, 1200, N'copy', N'ep:copy-document', N'bpm/task/copy/index', N'BpmProcessInstanceCopy', 0, N'1', N'1', N'1', N'1', N'2024-03-17 21:50:23', N'1', N'2024-04-24 19:55:12', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, N'流程分类', N'', 2, 3, 1186, N'category', N'fa:object-ungroup', N'bpm/category/index', N'BpmCategory', 0, N'1', N'1', N'1', N'', N'2024-03-08 02:00:51', N'1', N'2024-03-21 23:51:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, N'分类查询', N'bpm:category:query', 3, 1, 2714, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-03-08 02:00:51', N'1', N'2024-03-19 14:36:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, N'分类创建', N'bpm:category:create', 3, 2, 2714, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-03-08 02:00:51', N'1', N'2024-03-19 14:36:31', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, N'分类更新', N'bpm:category:update', 3, 3, 2714, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-03-08 02:00:51', N'1', N'2024-03-19 14:36:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, N'分类删除', N'bpm:category:delete', 3, 4, 2714, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'', N'2024-03-08 02:00:51', N'1', N'2024-03-19 14:36:41', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, N'发起流程', N'', 2, 0, 1200, N'create', N'fa-solid:grin-stars', N'bpm/processInstance/create/index', N'BpmProcessInstanceCreate', 0, N'1', N'0', N'1', N'1', N'2024-03-19 19:46:05', N'1', N'2024-03-23 19:03:42', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, N'流程实例', N'', 2, 10, 1186, N'process-instance/manager', N'fa:square', N'bpm/processInstance/manager/index', N'BpmProcessInstanceManager', 0, N'1', N'1', N'1', N'1', N'2024-03-21 23:57:30', N'1', N'2024-03-21 23:57:30', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, N'流程实例的查询(管理员)', N'bpm:process-instance:manager-query', 3, 1, 2721, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-03-22 08:18:27', N'1', N'2024-03-22 08:19:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, N'流程实例的取消(管理员)', N'bpm:process-instance:cancel-by-admin', 3, 2, 2721, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-03-22 08:19:25', N'1', N'2024-03-22 08:19:25', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, N'流程任务', N'', 2, 11, 1186, N'process-tasnk', N'ep:collection-tag', N'bpm/task/manager/index', N'BpmManagerTask', 0, N'1', N'1', N'1', N'1', N'2024-03-22 08:43:22', N'1', N'2024-03-22 08:43:27', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, N'流程任务的查询(管理员)', N'bpm:task:mananger-query', 3, 1, 2724, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-03-22 08:43:49', N'1', N'2024-03-22 08:43:49', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, N'流程监听器', N'', 2, 5, 1186, N'process-listener', N'fa:assistive-listening-systems', N'bpm/processListener/index', N'BpmProcessListener', 0, N'1', N'1', N'1', N'', N'2024-03-09 16:05:34', N'1', N'2024-03-23 13:13:38', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, N'流程监听器查询', N'bpm:process-listener:query', 3, 1, 2726, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 16:05:34', N'', N'2024-03-09 16:05:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, N'流程监听器创建', N'bpm:process-listener:create', 3, 2, 2726, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 16:05:34', N'', N'2024-03-09 16:05:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, N'流程监听器更新', N'bpm:process-listener:update', 3, 3, 2726, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 16:05:34', N'', N'2024-03-09 16:05:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, N'流程监听器删除', N'bpm:process-listener:delete', 3, 4, 2726, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 16:05:34', N'', N'2024-03-09 16:05:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, N'流程表达式', N'', 2, 6, 1186, N'process-expression', N'fa:wpexplorer', N'bpm/processExpression/index', N'BpmProcessExpression', 0, N'1', N'1', N'1', N'', N'2024-03-09 22:35:08', N'1', N'2024-03-23 19:43:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, N'流程表达式查询', N'bpm:process-expression:query', 3, 1, 2731, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 22:35:08', N'', N'2024-03-09 22:35:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, N'流程表达式创建', N'bpm:process-expression:create', 3, 2, 2731, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 22:35:08', N'', N'2024-03-09 22:35:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, N'流程表达式更新', N'bpm:process-expression:update', 3, 3, 2731, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 22:35:08', N'', N'2024-03-09 22:35:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, N'流程表达式删除', N'bpm:process-expression:delete', 3, 4, 2731, N'', N'', N'', NULL, 0, N'1', N'1', N'1', N'', N'2024-03-09 22:35:08', N'', N'2024-03-09 22:35:08', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, N'员工业绩', N'crm:statistics-performance:query', 2, 3, 2560, N'performance', N'ep:dish-dot', N'crm/statistics/performance/index', N'CrmStatisticsPerformance', 0, N'1', N'1', N'1', N'1', N'2024-04-05 13:49:20', N'1', N'2024-04-24 19:42:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, N'客户画像', N'crm:statistics-portrait:query', 2, 4, 2560, N'portrait', N'ep:picture', N'crm/statistics/portrait/index', N'CrmStatisticsPortrait', 0, N'1', N'1', N'1', N'1', N'2024-04-05 13:57:40', N'1', N'2024-04-24 19:42:24', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, N'销售漏斗', N'crm:statistics-funnel:query', 2, 5, 2560, N'funnel', N'ep:grape', N'crm/statistics/funnel/index', N'CrmStatisticsFunnel', 0, N'1', N'1', N'1', N'1', N'2024-04-13 10:53:26', N'1', N'2024-04-24 19:39:33', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, N'消息中心', N'', 1, 7, 1, N'messages', N'ep:chat-dot-round', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-22 23:54:30', N'1', N'2024-04-23 09:36:35', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, N'监控中心', N'', 1, 10, 2, N'monitors', N'ep:monitor', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-23 00:04:44', N'1', N'2024-04-23 00:04:44', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, N'领取公海客户', N'crm:customer:receive', 3, 1, 2546, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:47:45', N'1', N'2024-04-24 19:47:45', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, N'分配公海客户', N'crm:customer:distribute', 3, 2, 2546, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:48:05', N'1', N'2024-04-24 19:48:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, N'商品统计查询', N'statistics:product:query', 3, 1, 2545, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:50:05', N'1', N'2024-04-24 19:50:05', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, N'商品统计导出', N'statistics:product:export', 3, 2, 2545, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:50:26', N'1', N'2024-04-24 19:50:26', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, N'支付渠道查询', N'pay:channel:query', 3, 10, 1126, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:53:01', N'1', N'2024-04-24 19:53:01', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, N'支付渠道创建', N'pay:channel:create', 3, 11, 1126, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:53:18', N'1', N'2024-04-24 19:53:18', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, N'支付渠道更新', N'pay:channel:update', 3, 12, 1126, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:53:32', N'1', N'2024-04-24 19:53:58', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, N'支付渠道删除', N'pay:channel:delete', 3, 13, 1126, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:54:34', N'1', N'2024-04-24 19:54:34', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, N'商品收藏查询', N'product:favorite:query', 3, 10, 2014, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:55:47', N'1', N'2024-04-24 19:55:47', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, N'商品浏览查询', N'product:browse-history:query', 3, 20, 2014, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:57:43', N'1', N'2024-04-24 19:57:43', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, N'售后同意', N'trade:after-sale:agree', 3, 2, 2073, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:58:40', N'1', N'2024-04-24 19:58:40', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, N'售后不同意', N'trade:after-sale:disagree', 3, 3, 2073, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 19:59:03', N'1', N'2024-04-24 19:59:03', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, N'售后确认退货', N'trade:after-sale:receive', 3, 4, 2073, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 20:00:07', N'1', N'2024-04-24 20:00:07', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, N'售后确认退款', N'trade:after-sale:refund', 3, 5, 2073, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 20:00:24', N'1', N'2024-04-24 20:00:24', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, N'删除项目', N'report:go-view-project:delete', 3, 2, 2153, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 20:01:37', N'1', N'2024-04-24 20:01:37', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, N'会员等级记录查询', N'member:level-record:query', 3, 10, 2325, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 20:02:32', N'1', N'2024-04-24 20:02:32', N'0') +GO +INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, N'会员经验记录查询', N'member:experience-record:query', 3, 11, 2325, N'', N'', N'', N'', 0, N'1', N'1', N'1', N'1', N'2024-04-24 20:02:51', N'1', N'2024-04-24 20:02:51', N'0') +GO +SET IDENTITY_INSERT system_menu OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notice +-- ---------------------------- +DROP TABLE IF EXISTS system_notice +GO +CREATE TABLE system_notice +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + title nvarchar(50) NOT NULL, + content nvarchar(max) NOT NULL, + type tinyint NOT NULL, + status tinyint DEFAULT 0 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'公告ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'公告标题', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'title' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'公告内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'公告类型(1通知 2公告)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'公告状态(0正常 1关闭)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知公告表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notice' +GO + +-- ---------------------------- +-- Records of system_notice +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_notice ON +GO +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'芋道的公众', N'

新版本内容133

', 1, 0, N'admin', N'2021-01-05 17:03:48', N'1', N'2022-05-04 21:00:20', N'0', 1) +GO +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'维护通知:2018-07-01 系统凌晨维护', N'

11112222

', 2, 1, N'admin', N'2021-01-05 17:03:48', N'1', N'2023-12-02 20:07:26', N'0', 1) +GO +INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, N'我是测试标题', N'

哈哈哈哈123

', 1, 0, N'110', N'2022-02-22 01:01:25', N'110', N'2022-02-22 01:01:46', N'0', 121) +GO +SET IDENTITY_INSERT system_notice OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notify_message +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_message +GO +CREATE TABLE system_notify_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type tinyint NOT NULL, + template_id bigint NOT NULL, + template_code nvarchar(64) NOT NULL, + template_nickname nvarchar(63) NOT NULL, + template_content nvarchar(1024) NOT NULL, + template_type int NOT NULL, + template_params nvarchar(255) NOT NULL, + read_status varchar(1) NOT NULL, + read_time datetime2 DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版发送人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版参数', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'template_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否已读', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'read_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阅读时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'read_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'站内信消息表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_message' +GO + +-- ---------------------------- +-- Records of system_notify_message +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_notify_message ON +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, N'test', N'123', N'我是 1,我开始 2 了', 1, N'{"name":"1","what":"2"}', N'1', N'2023-02-10 00:47:04', N'1', N'2023-01-28 11:44:08', N'1', N'2023-02-10 00:47:04', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, N'test', N'123', N'我是 1,我开始 2 了', 1, N'{"name":"1","what":"2"}', N'1', N'2023-02-10 00:47:04', N'1', N'2023-01-28 11:45:04', N'1', N'2023-02-10 00:47:04', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, N'register', N'系统消息', N'你好,欢迎 哈哈 加入大家庭!', 2, N'{"name":"哈哈"}', N'0', NULL, N'1', N'2023-01-28 21:02:20', N'1', N'2023-01-28 21:02:20', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, N'test', N'123', N'我是 芋艿,我开始 写代码 了', 1, N'{"name":"芋艿","what":"写代码"}', N'1', N'2023-02-10 00:47:04', N'1', N'2023-01-28 22:21:42', N'1', N'2023-02-10 00:47:04', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, N'test', N'123', N'我是 芋艿,我开始 写代码 了', 1, N'{"name":"芋艿","what":"写代码"}', N'1', N'2023-01-29 10:52:06', N'1', N'2023-01-28 22:22:07', N'1', N'2023-01-29 10:52:06', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, N'test', N'123', N'我是 2,我开始 3 了', 1, N'{"name":"2","what":"3"}', N'1', N'2023-01-29 10:52:06', N'1', N'2023-01-28 23:45:21', N'1', N'2023-01-29 10:52:06', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, N'register', N'系统消息', N'你好,欢迎 123 加入大家庭!', 2, N'{"name":"123"}', N'1', N'2023-01-29 10:52:06', N'1', N'2023-01-28 23:50:21', N'1', N'2023-01-29 10:52:06', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, N'brokerage_withdraw_audit_approve', N'system', N'您在2023-09-28 08:35:46提现¥0.09元的申请已通过审核', 2, N'{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', N'0', NULL, N'1', N'2023-09-28 16:36:22', N'1', N'2023-09-28 16:36:22', N'0', 1) +GO +INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, N'brokerage_withdraw_audit_approve', N'system', N'您在2023-09-30 20:59:40提现¥1.00元的申请已通过审核', 2, N'{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', N'0', NULL, N'1', N'2023-10-03 12:11:34', N'1', N'2023-10-03 12:11:34', N'0', 1) +GO +SET IDENTITY_INSERT system_notify_message OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_notify_template +-- ---------------------------- +DROP TABLE IF EXISTS system_notify_template +GO +CREATE TABLE system_notify_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(63) NOT NULL, + code nvarchar(64) NOT NULL, + nickname nvarchar(255) NOT NULL, + content nvarchar(1024) NOT NULL, + type tinyint NOT NULL, + params nvarchar(255) DEFAULT NULL NULL, + status tinyint NOT NULL, + remark nvarchar(255) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模版内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数数组', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'站内信模板表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_notify_template' +GO + +-- ---------------------------- +-- Table structure for system_oauth2_access_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_access_token +GO +CREATE TABLE system_oauth2_access_token +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type tinyint NOT NULL, + user_info nvarchar(512) NOT NULL, + access_token nvarchar(255) NOT NULL, + refresh_token nvarchar(32) NOT NULL, + client_id nvarchar(255) NOT NULL, + scopes nvarchar(255) DEFAULT NULL NULL, + expires_time datetime2 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token) +GO +CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户信息', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'user_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'访问令牌', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'access_token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'刷新令牌', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'refresh_token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'scopes' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'expires_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'OAuth2 访问令牌', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_access_token' +GO + +-- ---------------------------- +-- Table structure for system_oauth2_approve +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_approve +GO +CREATE TABLE system_oauth2_approve +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type tinyint NOT NULL, + client_id nvarchar(255) NOT NULL, + scope nvarchar(255) DEFAULT '' NOT NULL, + approved varchar(1) DEFAULT '0' NOT NULL, + expires_time datetime2 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'scope' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否接受', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'approved' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'expires_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'OAuth2 批准表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_approve' +GO + +-- ---------------------------- +-- Table structure for system_oauth2_client +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_client +GO +CREATE TABLE system_oauth2_client +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + client_id nvarchar(255) NOT NULL, + secret nvarchar(255) NOT NULL, + name nvarchar(255) NOT NULL, + logo nvarchar(255) NOT NULL, + description nvarchar(255) DEFAULT NULL NULL, + status tinyint NOT NULL, + access_token_validity_seconds int NOT NULL, + refresh_token_validity_seconds int NOT NULL, + redirect_uris nvarchar(255) NOT NULL, + authorized_grant_types nvarchar(255) NOT NULL, + scopes nvarchar(255) DEFAULT NULL NULL, + auto_approve_scopes nvarchar(255) DEFAULT NULL NULL, + authorities nvarchar(255) DEFAULT NULL NULL, + resource_ids nvarchar(255) DEFAULT NULL NULL, + additional_information nvarchar(4000) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端密钥', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'secret' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用图标', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'logo' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用描述', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'访问令牌的有效期', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'access_token_validity_seconds' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'刷新令牌的有效期', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'refresh_token_validity_seconds' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'可重定向的 URI 地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'redirect_uris' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'authorized_grant_types' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'scopes' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'自动通过的授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'auto_approve_scopes' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'权限', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'authorities' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'资源', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'resource_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'附加信息', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'additional_information' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'OAuth2 客户端表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_client' +GO + +-- ---------------------------- +-- Records of system_oauth2_client +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_oauth2_client ON +GO +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, N'default', N'admin123', N'芋道源码', N'http://test.yudao.iocoder.cn/a5e2e244368878a366b516805a4aabf1.png', N'我是描述', 0, 1800, 2592000, N'["https://www.iocoder.cn","https://doc.iocoder.cn"]', N'["password","authorization_code","implicit","refresh_token"]', N'["user.read","user.write"]', N'[]', N'["user.read","user.write"]', N'[]', N'{}', N'1', N'2022-05-11 21:47:12', N'1', N'2024-02-22 16:31:52', N'0') +GO +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, N'test', N'test2', N'biubiu', N'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', N'啦啦啦啦', 0, 1800, 43200, N'["https://www.iocoder.cn"]', N'["password","authorization_code","implicit"]', N'["user_info","projects"]', N'["user_info"]', N'[]', N'[]', N'{}', N'1', N'2022-05-12 00:28:20', N'1', N'2023-12-02 21:01:01', N'0') +GO +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, N'yudao-sso-demo-by-code', N'test', N'基于授权码模式,如何实现 SSO 单点登录?', N'http://test.yudao.iocoder.cn/fe4ed36596adad5120036ef61a6d0153654544d44af8dd4ad3ffe8f759933d6f.png', NULL, 0, 1800, 43200, N'["http://127.0.0.1:18080"]', N'["authorization_code","refresh_token"]', N'["user.read","user.write"]', N'[]', N'[]', N'[]', NULL, N'1', N'2022-09-29 13:28:31', N'1', N'2022-09-29 13:28:31', N'0') +GO +INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, N'yudao-sso-demo-by-password', N'test', N'基于密码模式,如何实现 SSO 单点登录?', N'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, N'["http://127.0.0.1:18080"]', N'["password","refresh_token"]', N'["user.read","user.write"]', N'[]', N'[]', N'[]', NULL, N'1', N'2022-10-04 17:40:16', N'1', N'2022-10-04 20:31:21', N'0') +GO +SET IDENTITY_INSERT system_oauth2_client OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_oauth2_code +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_code +GO +CREATE TABLE system_oauth2_code +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type tinyint NOT NULL, + code nvarchar(32) NOT NULL, + client_id nvarchar(255) NOT NULL, + scopes nvarchar(255) DEFAULT '' NULL, + expires_time datetime2 NOT NULL, + redirect_uri nvarchar(255) DEFAULT NULL NULL, + state nvarchar(255) DEFAULT '' NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'scopes' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'expires_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'可重定向的 URI 地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'redirect_uri' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'state' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'OAuth2 授权码表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_code' +GO + +-- ---------------------------- +-- Table structure for system_oauth2_refresh_token +-- ---------------------------- +DROP TABLE IF EXISTS system_oauth2_refresh_token +GO +CREATE TABLE system_oauth2_refresh_token +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + refresh_token nvarchar(32) NOT NULL, + user_type tinyint NOT NULL, + client_id nvarchar(255) NOT NULL, + scopes nvarchar(255) DEFAULT NULL NULL, + expires_time datetime2 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'刷新令牌', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'refresh_token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'授权范围', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'scopes' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'expires_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'OAuth2 刷新令牌', + 'SCHEMA', N'dbo', + 'TABLE', N'system_oauth2_refresh_token' +GO + +-- ---------------------------- +-- Table structure for system_operate_log +-- ---------------------------- +DROP TABLE IF EXISTS system_operate_log +GO +CREATE TABLE system_operate_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + trace_id nvarchar(64) DEFAULT '' NOT NULL, + user_id bigint NOT NULL, + user_type tinyint DEFAULT 0 NOT NULL, + type nvarchar(50) NOT NULL, + sub_type nvarchar(50) NOT NULL, + biz_id bigint NOT NULL, + action nvarchar(2000) DEFAULT '' NOT NULL, + extra nvarchar(2000) DEFAULT '' NOT NULL, + request_method nvarchar(16) DEFAULT '' NULL, + request_url nvarchar(255) DEFAULT '' NULL, + user_ip nvarchar(50) DEFAULT NULL NULL, + user_agent nvarchar(200) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志主键', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'链路追踪编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'trace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作模块类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'sub_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作数据模块编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'biz_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'action' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'拓展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'extra' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求方法名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'request_method' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'请求地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'request_url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'user_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'浏览器 UA', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'user_agent' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作日志记录 V2 版本', + 'SCHEMA', N'dbo', + 'TABLE', N'system_operate_log' +GO + +-- ---------------------------- +-- Table structure for system_post +-- ---------------------------- +DROP TABLE IF EXISTS system_post +GO +CREATE TABLE system_post +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + code nvarchar(64) NOT NULL, + name nvarchar(50) NOT NULL, + sort int NOT NULL, + status tinyint NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'显示顺序', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_post' +GO + +-- ---------------------------- +-- Records of system_post +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_post ON +GO +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'ceo', N'董事长', 1, 0, N'', N'admin', N'2021-01-06 17:03:48', N'1', N'2023-02-11 15:19:04', N'0', 1) +GO +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'se', N'项目经理', 2, 0, N'', N'admin', N'2021-01-05 17:03:48', N'1', N'2023-11-15 09:18:20', N'0', 1) +GO +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, N'user', N'普通员工', 4, 0, N'111', N'admin', N'2021-01-05 17:03:48', N'1', N'2023-12-02 10:04:37', N'0', 1) +GO +INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, N'HR', N'人力资源', 5, 0, N'', N'1', N'2024-03-24 20:45:40', N'1', N'2024-03-24 20:45:40', N'0', 1) +GO +SET IDENTITY_INSERT system_post OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_role +-- ---------------------------- +DROP TABLE IF EXISTS system_role +GO +CREATE TABLE system_role +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(30) NOT NULL, + code nvarchar(100) NOT NULL, + sort int NOT NULL, + data_scope tinyint DEFAULT 1 NOT NULL, + data_scope_dept_ids nvarchar(500) DEFAULT '' NOT NULL, + status tinyint NOT NULL, + type tinyint NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色权限字符串', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'显示顺序', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'data_scope' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据范围(指定部门数组)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'data_scope_dept_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role' +GO + +-- ---------------------------- +-- Records of system_role +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_role ON +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'超级管理员', N'super_admin', 1, 1, N'', 0, 1, N'超级管理员', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-22 05:08:21', N'0', 1) +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'普通角色', N'common', 2, 2, N'', 0, 1, N'普通角色', N'admin', N'2021-01-05 17:03:48', N'', N'2022-02-22 05:08:20', N'0', 1) +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, N'CRM 管理员', N'crm_admin', 2, 1, N'', 0, 1, N'CRM 专属角色', N'1', N'2024-02-24 10:51:13', N'1', N'2024-02-24 02:51:32', N'0', 1) +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, N'测试账号', N'test', 0, 1, N'[]', 0, 2, N'我想测试', N'', N'2021-01-06 13:49:35', N'1', N'2024-03-24 22:22:45', N'0', 1) +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, N'租户管理员', N'tenant_admin', 0, 1, N'', 0, 1, N'系统自动生成', N'1', N'2022-02-22 00:56:14', N'1', N'2022-02-22 00:56:14', N'0', 121) +GO +INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, N'租户管理员', N'tenant_admin', 0, 1, N'', 0, 1, N'系统自动生成', N'1', N'2022-03-07 21:37:58', N'1', N'2022-03-07 21:37:58', N'0', 122) +GO +SET IDENTITY_INSERT system_role OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS system_role_menu +GO +CREATE TABLE system_role_menu +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + role_id bigint NOT NULL, + menu_id bigint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'自增编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'role_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'菜单ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'menu_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色和菜单关联表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_role_menu' +GO + +-- ---------------------------- +-- Records of system_role_menu +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_role_menu ON +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, N'1', N'2022-02-22 00:56:14', N'1', N'2022-02-22 00:56:14', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, N'1', N'2022-02-22 13:09:12', N'1', N'2022-02-22 13:09:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, N'1', N'2022-02-22 13:16:57', N'1', N'2022-02-22 13:16:57', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, N'110', N'2022-02-23 00:23:55', N'110', N'2022-02-23 00:23:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, N'1', N'2022-03-07 21:37:58', N'1', N'2022-03-07 21:37:58', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1604, 101, 1216, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1605, 101, 1217, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1606, 101, 1218, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1607, 101, 1219, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1608, 101, 1220, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1609, 101, 1221, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1610, 101, 5, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1611, 101, 1222, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1612, 101, 1118, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1613, 101, 1119, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1614, 101, 1120, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1615, 101, 1185, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1616, 101, 1186, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1617, 101, 1187, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1618, 101, 1188, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1619, 101, 1189, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1620, 101, 1190, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1621, 101, 1191, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1622, 101, 1192, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1623, 101, 1193, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1624, 101, 1194, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1625, 101, 1195, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1626, 101, 1196, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1627, 101, 1197, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1628, 101, 1198, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1629, 101, 1199, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1630, 101, 1200, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1631, 101, 1201, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1632, 101, 1202, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1633, 101, 1207, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1634, 101, 1208, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1635, 101, 1209, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1636, 101, 1210, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1637, 101, 1211, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1638, 101, 1212, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1639, 101, 1213, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1640, 101, 1215, N'1', N'2022-03-19 21:45:52', N'1', N'2022-03-19 21:45:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1641, 101, 2, N'1', N'2022-04-01 22:21:24', N'1', N'2022-04-01 22:21:24', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1642, 101, 1031, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1643, 101, 1032, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1644, 101, 1033, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1645, 101, 1034, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1646, 101, 1035, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1647, 101, 1050, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1648, 101, 1051, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1649, 101, 1052, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1650, 101, 1053, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1651, 101, 1054, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1652, 101, 1056, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1653, 101, 1057, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1654, 101, 1058, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1655, 101, 1059, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1656, 101, 1060, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1657, 101, 1066, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1658, 101, 1067, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1659, 101, 1070, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1664, 101, 1075, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1666, 101, 1077, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1667, 101, 1078, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1668, 101, 1082, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1669, 101, 1083, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1670, 101, 1084, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1671, 101, 1085, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1672, 101, 1086, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1673, 101, 1087, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1674, 101, 1088, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1675, 101, 1089, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1679, 101, 1237, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1680, 101, 1238, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1681, 101, 1239, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1682, 101, 1240, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1683, 101, 1241, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1684, 101, 1242, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1685, 101, 1243, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1687, 101, 106, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1688, 101, 110, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1689, 101, 111, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1690, 101, 112, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1691, 101, 113, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1692, 101, 114, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1693, 101, 115, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1694, 101, 116, N'1', N'2022-04-01 22:21:37', N'1', N'2022-04-01 22:21:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, N'1', N'2022-09-21 22:08:51', N'1', N'2022-09-21 22:08:51', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, N'1', N'2022-09-21 22:08:52', N'1', N'2022-09-21 22:08:52', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, N'1', N'2022-09-21 22:08:53', N'1', N'2022-09-21 22:08:53', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, N'1', N'2022-09-21 22:08:54', N'1', N'2022-09-21 22:08:54', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, N'1', N'2022-09-21 22:08:55', N'1', N'2022-09-21 22:08:55', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, N'1', N'2022-09-21 22:08:56', N'1', N'2022-09-21 22:08:56', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, N'1', N'2022-09-21 22:43:23', N'1', N'2022-09-21 22:43:23', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, N'1', N'2022-09-21 22:43:23', N'1', N'2022-09-21 22:43:23', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, N'1', N'2022-09-21 22:43:23', N'1', N'2022-09-21 22:43:23', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, N'1', N'2022-09-21 22:43:23', N'1', N'2022-09-21 22:43:23', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, N'1', N'2022-09-21 22:43:23', N'1', N'2022-09-21 22:43:23', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, N'1', N'2022-09-21 22:43:24', N'1', N'2022-09-21 22:43:24', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, N'1', N'2022-09-21 22:43:24', N'1', N'2022-09-21 22:43:24', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, N'1', N'2022-09-21 22:43:24', N'1', N'2022-09-21 22:43:24', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, N'1', N'2022-09-21 22:43:24', N'1', N'2022-09-21 22:43:24', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, N'1', N'2022-09-21 22:43:24', N'1', N'2022-09-21 22:43:24', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, N'1', N'2022-09-21 22:48:13', N'1', N'2022-09-21 22:48:13', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2083, 2, 1163, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2084, 2, 1164, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2085, 2, 1165, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2089, 2, 1175, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2090, 2, 1176, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2091, 2, 1177, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2142, 2, 1014, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2144, 2, 1016, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, N'1', N'2023-01-25 08:42:52', N'1', N'2023-01-25 08:42:52', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, N'1', N'2023-01-25 08:42:58', N'1', N'2023-01-25 08:42:58', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, N'1', N'2023-01-25 08:43:12', N'1', N'2023-01-25 08:43:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, N'1', N'2023-01-25 08:43:12', N'1', N'2023-01-25 08:43:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, N'1', N'2023-01-25 08:43:12', N'1', N'2023-01-25 08:43:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, N'1', N'2023-01-25 08:43:12', N'1', N'2023-01-25 08:43:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, N'1', N'2023-01-25 08:43:12', N'1', N'2023-01-25 08:43:12', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2188, 101, 1024, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2189, 101, 1, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2190, 101, 1025, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2191, 101, 1026, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2192, 101, 1027, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2193, 101, 1028, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2194, 101, 1029, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2195, 101, 1030, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2196, 101, 1036, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2197, 101, 1037, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2198, 101, 1038, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2199, 101, 1039, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2200, 101, 1040, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2201, 101, 1042, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2202, 101, 1043, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2203, 101, 1045, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2204, 101, 1046, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2205, 101, 1048, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2206, 101, 2083, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2207, 101, 1063, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2208, 101, 1064, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2209, 101, 1065, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2210, 101, 1093, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2211, 101, 1094, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2212, 101, 1095, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2213, 101, 1096, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2214, 101, 1097, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2215, 101, 1098, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2216, 101, 1100, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2217, 101, 1101, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2218, 101, 1102, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2219, 101, 1103, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2220, 101, 1104, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2221, 101, 1105, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2222, 101, 1106, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2223, 101, 2130, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2224, 101, 1107, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2225, 101, 2131, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2226, 101, 1108, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2227, 101, 2132, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2228, 101, 1109, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2229, 101, 2133, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2230, 101, 2134, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2232, 101, 2135, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2234, 101, 2136, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2236, 101, 2137, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2238, 101, 2138, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2240, 101, 2139, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2242, 101, 2140, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2243, 101, 2141, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2244, 101, 2142, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2245, 101, 2143, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2246, 101, 2144, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2247, 101, 2145, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2248, 101, 2146, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2249, 101, 2147, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2250, 101, 100, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2251, 101, 2148, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2252, 101, 101, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2253, 101, 2149, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2254, 101, 102, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2255, 101, 2150, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2256, 101, 103, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2257, 101, 2151, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2258, 101, 104, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2259, 101, 2152, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2260, 101, 105, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2261, 101, 107, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2262, 101, 108, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2263, 101, 109, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2264, 101, 1138, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2265, 101, 1139, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2266, 101, 1140, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2267, 101, 1141, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2268, 101, 1142, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2269, 101, 1143, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2270, 101, 1224, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2271, 101, 1225, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2272, 101, 1226, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2273, 101, 1227, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2274, 101, 1228, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2275, 101, 1229, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2282, 101, 1261, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2283, 101, 1263, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2284, 101, 1264, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2285, 101, 1265, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2286, 101, 1266, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2287, 101, 1267, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2288, 101, 1001, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2289, 101, 1002, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2290, 101, 1003, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2291, 101, 1004, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2292, 101, 1005, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2293, 101, 1006, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2294, 101, 1007, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2295, 101, 1008, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2296, 101, 1009, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2297, 101, 1010, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2298, 101, 1011, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2299, 101, 1012, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2300, 101, 500, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2301, 101, 1013, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2302, 101, 501, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2303, 101, 1014, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2304, 101, 1015, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2305, 101, 1016, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2306, 101, 1017, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2307, 101, 1018, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2308, 101, 1019, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2309, 101, 1020, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2310, 101, 1021, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2311, 101, 1022, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2312, 101, 1023, N'1', N'2023-02-09 23:49:46', N'1', N'2023-02-09 23:49:46', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, N'1', N'2023-12-02 23:19:40', N'1', N'2023-12-02 23:19:40', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3013, 109, 1076, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3089, 111, 1076, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, N'1', N'2023-12-02 23:41:02', N'1', N'2023-12-02 23:41:02', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, N'1', N'2023-12-30 11:42:36', N'1', N'2023-12-30 11:42:36', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4196, 109, 1196, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, N'1', N'2024-03-30 17:53:17', N'1', N'2024-03-30 17:53:17', N'0', 121) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4255, 111, 1196, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, N'1', N'2024-03-30 17:53:18', N'1', N'2024-03-30 17:53:18', N'0', 122) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5777, 101, 2739, N'1', N'2024-04-30 09:38:37', N'1', N'2024-04-30 09:38:37', N'0', 1) +GO +INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5778, 101, 2740, N'1', N'2024-04-30 09:38:37', N'1', N'2024-04-30 09:38:37', N'0', 1) +GO +SET IDENTITY_INSERT system_role_menu OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_channel +GO +CREATE TABLE system_sms_channel +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + signature nvarchar(12) NOT NULL, + code nvarchar(63) NOT NULL, + status tinyint NOT NULL, + remark nvarchar(255) DEFAULT NULL NULL, + api_key nvarchar(128) NOT NULL, + api_secret nvarchar(128) DEFAULT NULL NULL, + callback_url nvarchar(255) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信签名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'signature' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'渠道编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'开启状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 的账号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'api_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 的秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'api_secret' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信发送回调 URL', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'callback_url' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信渠道', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_channel' +GO + +-- ---------------------------- +-- Records of system_sms_channel +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_sms_channel ON +GO +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, N'Ballcat', N'ALIYUN', 0, N'你要改哦,只有我可以用!!!!', N'LTAI5tCnKso2uG3kJ5gRav88', N'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, N'', N'2021-03-31 11:53:10', N'1', N'2023-12-02 22:10:17', N'0') +GO +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, N'测试渠道', N'DEBUG_DING_TALK', 0, N'123', N'696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', N'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, N'1', N'2021-04-13 00:23:14', N'1', N'2022-03-27 20:29:49', N'0') +GO +INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (6, N'测试演示', N'DEBUG_DING_TALK', 0, N'仅测试', N'696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', N'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, N'1', N'2022-04-10 23:07:59', N'1', N'2023-12-02 22:10:08', N'0') +GO +SET IDENTITY_INSERT system_sms_channel OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_sms_code +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_code +GO +CREATE TABLE system_sms_code +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + mobile nvarchar(11) NOT NULL, + code nvarchar(6) NOT NULL, + create_ip nvarchar(15) NOT NULL, + scene tinyint NOT NULL, + today_index tinyint NOT NULL, + used tinyint NOT NULL, + used_time datetime2 DEFAULT NULL NULL, + used_ip nvarchar(255) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'手机号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'mobile' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'验证码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'create_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送场景', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'今日发送的第几条', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'today_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否使用', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'used' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'使用时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'used_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'使用 IP', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'used_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'手机验证码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_code' +GO + +-- ---------------------------- +-- Table structure for system_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_log +GO +CREATE TABLE system_sms_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + channel_id bigint NOT NULL, + channel_code nvarchar(63) NOT NULL, + template_id bigint NOT NULL, + template_code nvarchar(63) NOT NULL, + template_type tinyint NOT NULL, + template_content nvarchar(255) NOT NULL, + template_params nvarchar(255) NOT NULL, + api_template_id nvarchar(63) NOT NULL, + mobile nvarchar(11) NOT NULL, + user_id bigint DEFAULT NULL NULL, + user_type tinyint DEFAULT NULL NULL, + send_status tinyint DEFAULT 0 NOT NULL, + send_time datetime2 DEFAULT NULL NULL, + api_send_code nvarchar(63) DEFAULT NULL NULL, + api_send_msg nvarchar(255) DEFAULT NULL NULL, + api_request_id nvarchar(255) DEFAULT NULL NULL, + api_serial_no nvarchar(255) DEFAULT NULL NULL, + receive_status tinyint DEFAULT 0 NOT NULL, + receive_time datetime2 DEFAULT NULL NULL, + api_receive_code nvarchar(63) DEFAULT NULL NULL, + api_receive_msg nvarchar(255) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信渠道编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'channel_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信渠道编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'channel_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'template_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'template_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'template_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'template_content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信参数', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'template_params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 的模板编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_template_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'手机号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'mobile' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'send_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'发送时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'send_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 发送结果的编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_send_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 发送失败的提示', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_send_msg' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 发送返回的唯一请求 ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_request_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 发送返回的序号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_serial_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'receive_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'receive_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'API 接收结果的编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_receive_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'API 接收结果的说明', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'api_receive_msg' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信日志', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_log' +GO + +-- ---------------------------- +-- Table structure for system_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS system_sms_template +GO +CREATE TABLE system_sms_template +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + type tinyint NOT NULL, + status tinyint NOT NULL, + code nvarchar(63) NOT NULL, + name nvarchar(63) NOT NULL, + content nvarchar(255) NOT NULL, + params nvarchar(255) NOT NULL, + remark nvarchar(255) DEFAULT NULL NULL, + api_template_id nvarchar(63) NOT NULL, + channel_id bigint NOT NULL, + channel_code nvarchar(63) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'开启状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板名称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'模板内容', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'content' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数数组', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'params' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信 API 的模板编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'api_template_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信渠道编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'channel_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信渠道编码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'channel_code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'短信模板', + 'SCHEMA', N'dbo', + 'TABLE', N'system_sms_template' +GO + +-- ---------------------------- +-- Records of system_sms_template +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_sms_template ON +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, N'test_01', N'测试验证码短信', N'正在进行登录操作{operation},您的验证码是{code}', N'["operation","code"]', N'测试备注', N'4383920', 6, N'DEBUG_DING_TALK', N'', N'2021-03-31 10:49:38', N'1', N'2023-12-02 22:32:47', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, N'test_02', N'公告通知', N'您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', N'["code"]', NULL, N'SMS_207945135', 2, N'ALIYUN', N'', N'2021-03-31 11:56:30', N'1', N'2021-04-10 01:22:02', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, N'test-01', N'测试模板', N'哈哈哈 {name}', N'["name"]', N'f哈哈哈', N'4383920', 6, N'DEBUG_DING_TALK', N'1', N'2021-04-10 01:07:21', N'1', N'2022-12-10 21:26:09', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, N'test-04', N'测试下', N'老鸡{name},牛逼{code}', N'["name","code"]', N'哈哈哈哈', N'suibian', 4, N'DEBUG_DING_TALK', N'1', N'2021-04-13 00:29:53', N'1', N'2023-12-02 22:35:34', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, N'user-sms-login', N'前台用户短信登录', N'您的验证码是{code}', N'["code"]', NULL, N'4372216', 6, N'DEBUG_DING_TALK', N'1', N'2021-10-11 08:10:00', N'1', N'2022-12-10 21:25:59', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, N'bpm_task_assigned', N'【工作流】任务被分配', N'您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', N'["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, N'suibian', 4, N'DEBUG_DING_TALK', N'1', N'2022-01-21 22:31:19', N'1', N'2022-01-22 00:03:36', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, N'bpm_process_instance_reject', N'【工作流】流程被不通过', N'您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', N'["processInstanceName","reason","detailUrl"]', NULL, N'suibian', 4, N'DEBUG_DING_TALK', N'1', N'2022-01-22 00:03:31', N'1', N'2022-05-01 12:33:14', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, N'bpm_process_instance_approve', N'【工作流】流程被通过', N'您的流程被审批通过:{processInstanceName},查看链接:{detailUrl}', N'["processInstanceName","detailUrl"]', NULL, N'suibian', 4, N'DEBUG_DING_TALK', N'1', N'2022-01-22 00:04:31', N'1', N'2022-03-27 20:32:21', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, N'demo', N'演示模板', N'我就是测试一下下', N'[]', NULL, N'biubiubiu', 6, N'DEBUG_DING_TALK', N'1', N'2022-04-10 23:22:49', N'1', N'2023-03-24 23:45:07', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, N'user-update-mobile', N'会员用户 - 修改手机', N'您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', N'["code"]', N'', N'null', 4, N'DEBUG_DING_TALK', N'1', N'2023-08-19 18:58:01', N'1', N'2023-08-19 11:34:04', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, N'user-update-password', N'会员用户 - 修改密码', N'您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', N'["code"]', N'', N'null', 4, N'DEBUG_DING_TALK', N'1', N'2023-08-19 18:58:01', N'1', N'2023-08-19 11:34:18', N'0') +GO +INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, N'user-reset-password', N'会员用户 - 重置密码', N'您的验证码{code},该验证码 5 分钟内有效,请勿泄漏于他人!', N'["code"]', N'', N'null', 4, N'DEBUG_DING_TALK', N'1', N'2023-08-19 18:58:01', N'1', N'2023-12-02 22:35:27', N'0') +GO +SET IDENTITY_INSERT system_sms_template OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_social_client +-- ---------------------------- +DROP TABLE IF EXISTS system_social_client +GO +CREATE TABLE system_social_client +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(255) NOT NULL, + social_type tinyint NOT NULL, + user_type tinyint NOT NULL, + client_id nvarchar(255) NOT NULL, + client_secret nvarchar(255) NOT NULL, + agent_id nvarchar(255) DEFAULT NULL NULL, + status tinyint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'应用名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交平台的类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'social_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'client_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端密钥', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'client_secret' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'代理编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'agent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'状态', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交客户端表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client' +GO + +-- ---------------------------- +-- Records of system_social_client +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_social_client ON +GO +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'钉钉', 20, 2, N'dingvrnreaje3yqvzhxg', N'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, 0, N'', N'2023-10-18 11:21:18', N'1', N'2023-12-20 21:28:26', N'1', 1) +GO +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'钉钉(王土豆)', 20, 2, N'dingtsu9hpepjkbmthhw', N'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, 0, N'', N'2023-10-18 11:21:18', N'', N'2023-12-20 21:28:26', N'1', 121) +GO +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, N'微信公众号', 31, 1, N'wx5b23ba7a5589ecbb', N'2a7b3b20c537e52e74afd395eb85f61f', NULL, 0, N'', N'2023-10-18 16:07:46', N'1', N'2023-12-20 21:28:23', N'1', 1) +GO +INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, N'微信小程序', 34, 1, N'wx63c280fe3248a3e7', N'6f270509224a7ae1296bbf1c8cb97aed', NULL, 0, N'', N'2023-10-19 13:37:41', N'1', N'2023-12-20 21:28:25', N'1', 1) +GO +SET IDENTITY_INSERT system_social_client OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_social_user +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user +GO +CREATE TABLE system_social_user +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + type tinyint NOT NULL, + openid nvarchar(32) NOT NULL, + token nvarchar(256) DEFAULT NULL NULL, + raw_token_info nvarchar(1024) NOT NULL, + nickname nvarchar(32) NOT NULL, + avatar nvarchar(255) DEFAULT NULL NULL, + raw_user_info nvarchar(1024) NOT NULL, + code nvarchar(256) NOT NULL, + state nvarchar(256) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键(自增策略)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交平台的类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交 openid', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'openid' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交 token', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'原始 Token 数据,一般是 JSON 格式', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'raw_token_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户昵称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户头像', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'avatar' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'原始用户数据,一般是 JSON 格式', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'raw_user_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最后一次的认证 code', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'code' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最后一次的认证 state', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'state' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交用户表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user' +GO + +-- ---------------------------- +-- Table structure for system_social_user_bind +-- ---------------------------- +DROP TABLE IF EXISTS system_social_user_bind +GO +CREATE TABLE system_social_user_bind +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + user_type tinyint NOT NULL, + social_type tinyint NOT NULL, + social_user_id bigint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键(自增策略)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'user_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交平台的类型', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'social_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交用户的编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'social_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'社交绑定表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_user_bind' +GO + +-- ---------------------------- +-- Table structure for system_tenant +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant +GO +CREATE TABLE system_tenant +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(30) NOT NULL, + contact_user_id bigint DEFAULT NULL NULL, + contact_name nvarchar(30) NOT NULL, + contact_mobile nvarchar(500) DEFAULT NULL NULL, + status tinyint DEFAULT 0 NOT NULL, + website nvarchar(256) DEFAULT '' NULL, + package_id bigint NOT NULL, + expire_time datetime2 NOT NULL, + account_count int NOT NULL, + creator nvarchar(64) DEFAULT '' NOT NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'联系人的用户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'contact_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'联系人', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'contact_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'联系手机', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'contact_mobile' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'绑定域名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'website' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户套餐编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'package_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'expire_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'账号数量', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'account_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant' +GO + +-- ---------------------------- +-- Records of system_tenant +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_tenant ON +GO +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, N'芋道源码', NULL, N'芋艿', N'17321315478', 0, N'www.iocoder.cn', 0, N'2099-02-19 17:14:16', 9999, N'1', N'2021-01-05 17:03:47', N'1', N'2023-11-06 11:41:41', N'0') +GO +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, N'小租户', 110, N'小王2', N'15601691300', 0, N'zsxq.iocoder.cn', 111, N'2024-03-11 00:00:00', 20, N'1', N'2022-02-22 00:56:14', N'1', N'2023-11-06 11:41:47', N'0') +GO +INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, N'测试租户', 113, N'芋道', N'15601691300', 0, N'test.iocoder.cn', 111, N'2022-04-30 00:00:00', 50, N'1', N'2022-03-07 21:37:58', N'1', N'2023-11-06 11:41:53', N'0') +GO +SET IDENTITY_INSERT system_tenant OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_tenant_package +-- ---------------------------- +DROP TABLE IF EXISTS system_tenant_package +GO +CREATE TABLE system_tenant_package +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(30) NOT NULL, + status tinyint DEFAULT 0 NOT NULL, + remark nvarchar(256) DEFAULT '' NULL, + menu_ids nvarchar(4000) NOT NULL, + creator nvarchar(64) DEFAULT '' NOT NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'套餐编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'套餐名', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'关联的菜单编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'menu_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户套餐表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_tenant_package' +GO + +-- ---------------------------- +-- Records of system_tenant_package +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_tenant_package ON +GO +INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, N'普通套餐', 0, N'小功能', N'[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1076,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2484,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', N'1', N'2022-02-22 00:54:00', N'1', N'2024-03-30 17:53:17', N'0') +GO +SET IDENTITY_INSERT system_tenant_package OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_user_post +-- ---------------------------- +DROP TABLE IF EXISTS system_user_post +GO +CREATE TABLE system_user_post +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint DEFAULT 0 NOT NULL, + post_id bigint DEFAULT 0 NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'id', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'post_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户岗位表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_post' +GO + +-- ---------------------------- +-- Records of system_user_post +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_user_post ON +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, N'admin', N'2022-05-02 07:25:24', N'admin', N'2022-05-02 07:25:24', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, N'admin', N'2022-05-02 07:25:24', N'admin', N'2022-05-02 07:25:24', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, N'1', N'2022-05-16 19:36:28', N'1', N'2022-05-16 19:36:28', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, N'1', N'2022-07-09 17:40:26', N'1', N'2022-07-09 17:40:26', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, N'1', N'2022-07-09 17:44:44', N'1', N'2022-07-09 17:44:44', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, N'1', N'2024-03-24 20:45:51', N'1', N'2024-03-24 20:45:51', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, N'1', N'2024-04-04 09:37:14', N'1', N'2024-04-04 09:37:14', N'0', 1) +GO +INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, N'1', N'2024-04-04 09:37:14', N'1', N'2024-04-04 09:37:14', N'0', 1) +GO +SET IDENTITY_INSERT system_user_post OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_user_role +-- ---------------------------- +DROP TABLE IF EXISTS system_user_role +GO +CREATE TABLE system_user_role +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + user_id bigint NOT NULL, + role_id bigint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'自增编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'role_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户和角色关联表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_user_role' +GO + +-- ---------------------------- +-- Records of system_user_role +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_user_role ON +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, N'', N'2022-01-11 13:19:45', N'', N'2022-05-12 12:35:17', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, N'', N'2022-01-11 13:19:45', N'', N'2022-05-12 12:35:13', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 100, 101, N'', N'2022-01-11 13:19:45', N'', N'2022-05-12 12:35:13', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, N'', N'2022-01-11 13:19:45', N'', N'2022-05-12 12:35:12', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, N'', N'2022-01-11 13:19:45', N'', N'2022-05-12 12:35:11', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, N'1', N'2022-01-11 13:19:45', N'1', N'2022-01-11 13:19:45', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, N'1', N'2022-02-22 00:56:14', N'1', N'2022-02-22 00:56:14', N'0', 121) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, N'110', N'2022-02-23 13:14:38', N'110', N'2022-02-23 13:14:38', N'0', 121) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, N'1', N'2022-03-07 21:37:58', N'1', N'2022-03-07 21:37:58', N'0', 122) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, N'1', N'2022-05-12 20:39:29', N'1', N'2022-05-12 20:39:29', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 104, 101, N'1', N'2022-05-28 15:43:57', N'1', N'2022-05-28 15:43:57', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, N'1', N'2022-07-21 22:08:30', N'1', N'2022-07-21 22:08:30', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, N'1', N'2024-03-15 20:00:24', N'1', N'2024-03-15 20:00:24', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, N'1', N'2024-03-17 09:12:08', N'1', N'2024-03-17 09:12:08', N'0', 1) +GO +INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (38, 114, 101, N'1', N'2024-03-24 22:23:03', N'1', N'2024-03-24 22:23:03', N'0', 1) +GO +SET IDENTITY_INSERT system_user_role OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for system_users +-- ---------------------------- +DROP TABLE IF EXISTS system_users +GO +CREATE TABLE system_users +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + username nvarchar(30) NOT NULL, + password nvarchar(100) DEFAULT '' NOT NULL, + nickname nvarchar(30) NOT NULL, + remark nvarchar(500) DEFAULT NULL NULL, + dept_id bigint DEFAULT NULL NULL, + post_ids nvarchar(255) DEFAULT NULL NULL, + email nvarchar(50) DEFAULT '' NULL, + mobile nvarchar(11) DEFAULT '' NULL, + sex tinyint DEFAULT 0 NULL, + avatar nvarchar(512) DEFAULT '' NULL, + status tinyint DEFAULT 0 NOT NULL, + login_ip nvarchar(50) DEFAULT '' NULL, + login_date datetime2 DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户账号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户昵称', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'nickname' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门ID', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'岗位编号数组', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'post_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户邮箱', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'email' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'手机号码', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'mobile' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户性别', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'sex' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'头像地址', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'avatar' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'帐号状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最后登录IP', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'login_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最后登录时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'login_date' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'system_users' +GO + +-- ---------------------------- +-- Records of system_users +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT system_users ON +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'admin', N'$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', N'芋道源码', N'管理员', 103, N'[1]', N'aoteman@126.com', N'18818260277', 2, N'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, N'0:0:0:0:0:0:0:1', N'2024-04-29 21:50:32', N'admin', N'2021-01-05 17:03:47', NULL, N'2024-04-29 21:50:32', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, N'yudao', N'$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', N'芋道', N'不要吓我', 104, N'[1]', N'yudao@iocoder.cn', N'15601691300', 1, N'', 1, N'127.0.0.1', N'2022-07-09 23:03:33', N'', N'2021-01-07 09:07:17', NULL, N'2022-07-09 23:03:33', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, N'yuanma', N'$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', N'源码', NULL, 106, NULL, N'yuanma@iocoder.cn', N'15601701300', 0, N'', 0, N'0:0:0:0:0:0:0:1', N'2024-03-18 21:09:04', N'', N'2021-01-13 23:50:35', NULL, N'2024-03-18 21:09:04', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, N'test', N'$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', N'测试号', NULL, 107, N'[1,2]', N'111@qq.com', N'15601691200', 1, N'', 0, N'0:0:0:0:0:0:0:1', N'2024-03-26 07:11:35', N'', N'2021-01-21 02:13:53', NULL, N'2024-03-26 07:11:35', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, N'admin107', N'$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', N'芋艿', NULL, NULL, NULL, N'', N'15601691300', 0, N'', 0, N'', NULL, N'1', N'2022-02-20 22:59:33', N'1', N'2022-02-27 08:26:51', N'0', 118) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, N'admin108', N'$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', N'芋艿', NULL, NULL, NULL, N'', N'15601691300', 0, N'', 0, N'', NULL, N'1', N'2022-02-20 23:00:50', N'1', N'2022-02-27 08:26:53', N'0', 119) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, N'admin109', N'$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', N'芋艿', NULL, NULL, NULL, N'', N'15601691300', 0, N'', 0, N'', NULL, N'1', N'2022-02-20 23:11:50', N'1', N'2022-02-27 08:26:56', N'0', 120) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, N'admin110', N'$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', N'小王', NULL, NULL, NULL, N'', N'15601691300', 0, N'', 0, N'127.0.0.1', N'2022-09-25 22:47:33', N'1', N'2022-02-22 00:56:14', NULL, N'2022-09-25 22:47:33', N'0', 121) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, N'test', N'$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', N'测试用户', NULL, NULL, N'[]', N'', N'', 0, N'', 0, N'0:0:0:0:0:0:0:1', N'2023-12-30 11:42:17', N'110', N'2022-02-23 13:14:33', NULL, N'2023-12-30 11:42:17', N'0', 121) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, N'newobject', N'$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', N'新对象', NULL, 100, N'[]', N'', N'15601691235', 1, N'', 0, N'0:0:0:0:0:0:0:1', N'2024-03-16 23:11:38', N'1', N'2022-02-23 19:08:03', NULL, N'2024-03-16 23:11:38', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, N'aoteman', N'$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', N'芋道', NULL, NULL, NULL, N'', N'15601691300', 0, N'', 0, N'127.0.0.1', N'2022-03-19 18:38:51', N'1', N'2022-03-07 21:37:58', NULL, N'2022-03-19 18:38:51', N'0', 122) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, N'hrmgr', N'$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', N'hr 小姐姐', NULL, NULL, N'[5]', N'', N'15601691236', 1, N'', 0, N'0:0:0:0:0:0:0:1', N'2024-03-24 22:21:05', N'1', N'2022-03-19 21:50:58', NULL, N'2024-03-24 22:21:05', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, N'aotemane', N'$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', N'阿呆', N'11222', 102, N'[1,2]', N'7648@qq.com', N'15601691229', 2, N'', 0, N'', NULL, N'1', N'2022-04-30 02:55:43', N'1', N'2024-04-04 09:37:14', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, N'admin123', N'$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', N'测试号', N'1111', 100, N'[2]', N'', N'15601691234', 1, N'', 0, N'', NULL, N'1', N'2022-07-09 17:40:26', N'1', N'2022-07-09 17:40:26', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, N'goudan', N'$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', N'狗蛋', NULL, 103, N'[1]', N'', N'15601691239', 1, N'', 0, N'0:0:0:0:0:0:0:1', N'2024-03-17 09:10:27', N'1', N'2022-07-09 17:44:43', N'1', N'2024-04-04 09:48:05', N'0', 1) +GO +INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (131, N'hh', N'$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', N'呵呵', NULL, 100, N'[]', N'777@qq.com', N'15601882312', 1, N'', 0, N'', NULL, N'1', N'2024-04-27 08:45:56', N'1', N'2024-04-27 08:45:56', N'0', 1) +GO +SET IDENTITY_INSERT system_users OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo01_contact +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo01_contact +GO +CREATE TABLE yudao_demo01_contact +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(100) DEFAULT '' NOT NULL, + sex tinyint NOT NULL, + birthday datetime2 NOT NULL, + description nvarchar(255) NOT NULL, + avatar nvarchar(512) DEFAULT NULL NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名字', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'性别', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'sex' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'出生年', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'birthday' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'简介', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'头像', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'avatar' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'示例联系人表', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo01_contact' +GO + +-- ---------------------------- +-- Records of yudao_demo01_contact +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT yudao_demo01_contact ON +GO +INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'土豆', 2, N'2023-11-07 00:00:00', N'

天蚕土豆!呀

', N'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', N'1', N'2023-11-15 23:34:30', N'1', N'2023-11-15 23:47:39', N'0', 1) +GO +SET IDENTITY_INSERT yudao_demo01_contact OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo02_category +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo02_category +GO +CREATE TABLE yudao_demo02_category +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(100) DEFAULT '' NOT NULL, + parent_id bigint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名字', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父级编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'示例分类表', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo02_category' +GO + +-- ---------------------------- +-- Records of yudao_demo02_category +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT yudao_demo02_category ON +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, N'土豆', 0, N'1', N'2023-11-15 23:34:30', N'1', N'2023-11-16 20:24:23', N'0', 1) +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'番茄', 0, N'1', N'2023-11-16 20:24:00', N'1', N'2023-11-16 20:24:15', N'0', 1) +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, N'怪怪', 0, N'1', N'2023-11-16 20:24:32', N'1', N'2023-11-16 20:24:32', N'0', 1) +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, N'小番茄', 2, N'1', N'2023-11-16 20:24:39', N'1', N'2023-11-16 20:24:39', N'0', 1) +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, N'大番茄', 2, N'1', N'2023-11-16 20:24:46', N'1', N'2023-11-16 20:24:46', N'0', 1) +GO +INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, N'11', 3, N'1', N'2023-11-24 19:29:34', N'1', N'2023-11-24 19:29:34', N'0', 1) +GO +SET IDENTITY_INSERT yudao_demo02_category OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_course +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_course +GO +CREATE TABLE yudao_demo03_course +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + student_id bigint NOT NULL, + name nvarchar(100) DEFAULT '' NOT NULL, + score tinyint NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'学生编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'student_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名字', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'分数', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'score' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'学生课程表', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_course' +GO + +-- ---------------------------- +-- Records of yudao_demo03_course +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT yudao_demo03_course ON +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, N'语文', 66, N'1', N'2023-11-16 23:21:49', N'1', N'2023-11-16 23:21:49', N'0', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, N'数学', 22, N'1', N'2023-11-16 23:21:49', N'1', N'2023-11-16 23:21:49', N'0', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, N'体育', 23, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 15:44:40', N'1', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, N'计算机', 11, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 15:44:40', N'1', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, N'体育', 23, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 15:47:09', N'1', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, N'计算机', 11, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 15:47:09', N'1', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, N'体育', 23, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 23:47:10', N'0', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, N'计算机', 11, N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 23:47:10', N'0', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, N'电脑', 33, N'1', N'2023-11-17 00:20:42', N'1', N'2023-11-16 16:20:45', N'1', 1) +GO +INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, N'滑雪', 12, N'1', N'2023-11-17 13:13:20', N'1', N'2023-11-17 13:13:20', N'0', 1) +GO +SET IDENTITY_INSERT yudao_demo03_course OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_grade +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_grade +GO +CREATE TABLE yudao_demo03_grade +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + student_id bigint NOT NULL, + name nvarchar(100) DEFAULT '' NOT NULL, + teacher nvarchar(255) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'学生编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'student_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名字', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'班主任', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'teacher' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'学生班级表', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_grade' +GO + +-- ---------------------------- +-- Records of yudao_demo03_grade +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT yudao_demo03_grade ON +GO +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, N'三年 2 班', N'周杰伦', N'1', N'2023-11-16 23:21:49', N'1', N'2023-11-16 23:21:49', N'0', 1) +GO +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, N'华为', N'遥遥领先', N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-16 23:47:10', N'0', 1) +GO +INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, N'小图', N'小娃111', N'1', N'2023-11-17 13:10:23', N'1', N'2023-11-17 13:10:23', N'0', 1) +GO +SET IDENTITY_INSERT yudao_demo03_grade OFF +GO +COMMIT +GO +-- @formatter:on + +-- ---------------------------- +-- Table structure for yudao_demo03_student +-- ---------------------------- +DROP TABLE IF EXISTS yudao_demo03_student +GO +CREATE TABLE yudao_demo03_student +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(100) DEFAULT '' NOT NULL, + sex tinyint NOT NULL, + birthday datetime2 NOT NULL, + description nvarchar(255) NOT NULL, + creator nvarchar(64) DEFAULT '' NULL, + create_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + updater nvarchar(64) DEFAULT '' NULL, + update_time datetime2 DEFAULT CURRENT_TIMESTAMP NOT NULL, + deleted bit DEFAULT 0 NOT NULL, + tenant_id bigint DEFAULT 0 NOT NULL +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名字', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'性别', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'sex' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'出生日期', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'birthday' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'简介', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'creator' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'updater' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否删除', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户编号', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'学生表', + 'SCHEMA', N'dbo', + 'TABLE', N'yudao_demo03_student' +GO + +-- ---------------------------- +-- Records of yudao_demo03_student +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT yudao_demo03_student ON +GO +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, N'小白', 1, N'2023-11-16 00:00:00', N'

厉害

', N'1', N'2023-11-16 23:21:49', N'1', N'2023-11-17 16:49:06', N'0', 1) +GO +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, N'大黑', 2, N'2023-11-13 00:00:00', N'

你在教我做事?

', N'1', N'2023-11-16 23:22:46', N'1', N'2023-11-17 16:49:07', N'0', 1) +GO +INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, N'小花', 1, N'2023-11-07 00:00:00', N'

哈哈哈

', N'1', N'2023-11-17 00:04:47', N'1', N'2023-11-17 16:49:08', N'0', 1) +GO +SET IDENTITY_INSERT yudao_demo03_student OFF +GO +COMMIT +GO +-- @formatter:on + diff --git a/ruoyi-vue-pro-master/sql/tools/.gitignore b/ruoyi-vue-pro-master/sql/tools/.gitignore new file mode 100644 index 0000000..e00c3e7 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/.gitignore @@ -0,0 +1,8 @@ +# 忽略python虚拟环境 +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ diff --git a/ruoyi-vue-pro-master/sql/tools/README.md b/ruoyi-vue-pro-master/sql/tools/README.md new file mode 100644 index 0000000..c053652 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/README.md @@ -0,0 +1,131 @@ +## 0. 友情提示 + +在 `sql/tools` 目录下,我们提供一些数据库相关的工具,包括测试数据库的快速启动、MySQL 转换其它数据库等等。 + +注意!所有的操作,必须在 `sql/tools` 目录下执行。 + +## 1. 测试数据库的快速启动 + +基于 Docker Compose,快速启动 MySQL、Oracle、PostgreSQL、SQL Server 等数据库。 + +注意!使用 Docker Compose 启动完测试数据后,因为会自动导入项目的 SQL 脚本,所以可能需要等待 1-2 分钟。 + +### 1.1 MySQL + +```Bash +docker compose up -d mysql +``` + +#### 1.2 Oracle + +```Bash +docker compose up -d oracle +``` + +暂不支持 MacBook Apple Silicon,因为 Oracle 官方没有提供 Apple Silicon 版本的 Docker 镜像。 + +### 1.3 PostgreSQL + +```Bash +docker compose up -d postgres +``` + +### 1.4 SQL Server + +```Bash +docker compose up -d sqlserver +# 注意:启动完 sqlserver 后,需要手动再执行如下命令,因为 SQL Server 不支持初始化脚本 +docker compose exec sqlserver bash /tmp/create_schema.sh +``` + +暂不支持 MacBook Apple Silicon,因为 SQL Server 官方没有提供 Apple Silicon 版本的 Docker 镜像。 + +### 1.5 DM 达梦 + +① 下载达梦 Docker 镜像:https://download.dameng.com/eco/dm8/dm8_20230808_rev197096_x86_rh6_64_single.tar + +② 加载镜像文件,在镜像 tar 文件所在目录运行: + +```Bash +docker load -i dm8_20230808_rev197096_x86_rh6_64_single.tar +``` + +③ 在项目 `sql/tools` 目录下运行: + +```Bash +docker compose up -d dm8 +# 注意:启动完 dm 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本 +docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql' +exit +``` + +**注意**: `sql/dm/ruoyi-vue-pro-dm8.sql` 文件编码必须为 `GBK` 或者 `GBK` 超集,否则会出现中文乱码。 + +暂不支持 MacBook Apple Silicon,因为 达梦 官方没有提供 Apple Silicon 版本的 Docker 镜像。 + +### 1.6 KingbaseES 人大金仓 + +① 下载人大金仓 Docker 镜像: + +> x86_64 版本: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar + +> aarch64 版本:https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar + +② 加载镜像文件,在镜像 tar 文件所在目录运行: + +```Bash +docker load -i x86_64/kdb_x86_64_V009R001C001B0025.tar +``` + +③ 在项目 `sql/tools` 目录下运行: + +```Bash +docker compose up -d kingbase +# 注意:启动完 kingbase 后,需要手动再执行如下命令 +docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql' +``` + +### 1.7 华为 OpenGauss + +```Bash +docker compose up -d opengauss +# 注意:启动完 opengauss 后,需要手动再执行如下命令 +docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql' +``` + +## 1.X 容器的销毁重建 + +开发测试过程中,有时候需要创建全新干净的数据库。由于测试数据 Docker 容器采用数据卷 Volume 挂载数据库实例的数据目录,因此销毁数据需要停止容器后,删除数据卷,然后再重新创建容器。 + +以 postgres 为例,操作如下: + +```Bash +docker compose down postgres +docker volume rm ruoyi-vue-pro_postgres +``` + +## 2. MySQL 转换其它数据库 + +### 2.1 实现原理 + +通过读取 MySQL 的 `sql/mysql/ruoyi-vue-pro.sql` 数据库文件,转换成 Oracle、PostgreSQL、SQL Server、达梦、人大金仓 等数据库的脚本。 + +### 2.2 使用方法 + +① 安装依赖库 `simple-ddl-parser` + +```bash +pip install simple-ddl-parser +# pip3 install simple-ddl-parser +``` + +② 执行如下命令打印生成 postgres 的脚本内容,其他可选参数有:`oracle`、`sqlserver`、`dm8`、`kingbase`: + +```Bash +python3 convertor.py postgres +# python3 convertor.py postgres > tmp.sql +``` + +程序将 SQL 脚本打印到终端,可以重定向到临时文件 `tmp.sql`。 + +确认无误后,可以利用 IDEA 进行格式化。当然,也可以直接导入到数据库中。 diff --git a/ruoyi-vue-pro-master/sql/tools/convertor.py b/ruoyi-vue-pro-master/sql/tools/convertor.py new file mode 100644 index 0000000..f672cd7 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/convertor.py @@ -0,0 +1,844 @@ +# encoding=utf8 +"""芋道系统数据库迁移工具 + +Author: dhb52 (https://gitee.com/dhb52) + +pip install simple-ddl-parser +""" + +import argparse +import pathlib +import re +import time +from abc import ABC, abstractmethod +from typing import Dict, Generator, Optional, Tuple, Union + +from simple_ddl_parser import DDLParser + +PREAMBLE = """/* + Yudao Database Transfer Tool + + Source Server Type : MySQL + + Target Server Type : {db_type} + + Date: {date} +*/ + +""" + + +def load_and_clean(sql_file: str) -> str: + """加载源 SQL 文件,并清理内容方便下一步 ddl 解析 + + Args: + sql_file (str): sql文件路径 + + Returns: + str: 清理后的sql文件内容 + """ + REPLACE_PAIR_LIST = ( + (" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "), + (" KEY `", " INDEX `"), + ("UNIQUE INDEX", "UNIQUE KEY"), + ("b'0'", "'0'"), + ("b'1'", "'1'"), + ) + + content = open(sql_file).read() + for replace_pair in REPLACE_PAIR_LIST: + content = content.replace(*replace_pair) + content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content) + content = re.sub(r"ENGINE.*;", ";", content) + return content + + +class Convertor(ABC): + def __init__(self, src: str, db_type) -> None: + self.src = src + self.db_type = db_type + self.content = load_and_clean(self.src) + self.table_script_list = re.findall(r"CREATE TABLE [^;]*;", self.content) + + @abstractmethod + def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]) -> str: + """字段类型转换 + + Args: + type (str): 字段类型 + size (Optional[Union[int, Tuple[int]]]): 字段长度描述, 如varchar(255), decimal(10,2) + + Returns: + str: 类型定义 + """ + pass + + @abstractmethod + def gen_create(self, table_ddl: Dict) -> str: + """生成 create 脚本 + + Args: + table_ddl (Dict): 表DDL + + Returns: + str: 生成脚本 + """ + pass + + @abstractmethod + def gen_pk(self, table_name: str) -> str: + """生成主键定义 + + Args: + table_name (str): 表名 + + Returns: + str: 生成脚本 + """ + pass + + @abstractmethod + def gen_index(self, ddl: Dict) -> str: + """生成索引定义 + + Args: + table_ddl (Dict): 表DDL + + Returns: + str: 生成脚本 + """ + pass + + @abstractmethod + def gen_comment(self, table_sql: str, table_name: str) -> str: + """生成字段/表注释 + + Args: + table_sql (str): 原始表SQL + table_name (str): 表名 + + Returns: + str: 生成脚本 + """ + pass + + @abstractmethod + def gen_insert(self, table_name: str) -> str: + """生成 insert 语句块 + + Args: + table_name (str): 表名 + + Returns: + str: 生成脚本 + """ + pass + + def gen_dual(self) -> str: + """生成虚拟 dual 表 + + Returns: + str: 生成脚本, 默认返回空脚本, 表示当前数据库无需手工创建 + """ + return "" + + @staticmethod + def inserts(table_name: str, script_content: str) -> Generator: + PREFIX = f"INSERT INTO `{table_name}`" + + # 收集 `table_name` 对应的 insert 语句 + for line in script_content.split("\n"): + if line.startswith(PREFIX): + head, tail = line.replace(PREFIX, "").split(" VALUES ", maxsplit=1) + head = head.strip().replace("`", "").lower() + tail = tail.strip().replace(r"\"", '"') + # tail = tail.replace("b'0'", "'0'").replace("b'1'", "'1'") + yield f"INSERT INTO {table_name.lower()} {head} VALUES {tail}" + + @staticmethod + def index(ddl: Dict) -> Generator: + """生成索引定义 + + Args: + ddl (Dict): 表DDL + + Yields: + Generator[str]: create index 语句 + """ + + def generate_columns(columns): + keys = [ + f"{col['name'].lower()}{' ' + col['order'].lower() if col['order'] != 'ASC' else ''}" + for col in columns[0] + ] + return ", ".join(keys) + + for no, index in enumerate(ddl["index"], 1): + columns = generate_columns(index["columns"]) + table_name = ddl["table_name"].lower() + yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})" + + @staticmethod + def filed_comments(table_sql: str) -> Generator: + for line in table_sql.split("\n"): + match = re.match(r"^`([^`]+)`.* COMMENT '([^']+)'", line.strip()) + if match: + field = match.group(1) + comment_string = match.group(2).replace("\\n", "\n") + yield field, comment_string + + def table_comment(self, table_sql: str) -> str: + match = re.search(r"COMMENT \= '([^']+)';", table_sql) + return match.group(1) if match else None + + def print(self): + """打印转换后的sql脚本到终端""" + print( + PREAMBLE.format( + db_type=self.db_type, + date=time.strftime("%Y-%m-%d %H:%M:%S"), + ) + ) + + dual = self.gen_dual() + if dual: + print( + f"""-- ---------------------------- +-- Table structure for dual +-- ---------------------------- +{dual} +""" + ) + + error_scripts = [] + for table_sql in self.table_script_list: + ddl = DDLParser(table_sql.replace("`", "")).run() + + # 如果parse失败, 需要跟进 + if len(ddl) == 0: + error_scripts.append(table_sql) + continue + + table_ddl = ddl[0] + table_name = table_ddl["table_name"] + + # 忽略 quartz 的内容 + if table_name.lower().startswith("qrtz"): + continue + + # 为每个表生成个5个基本部分 + create = self.gen_create(table_ddl) + pk = self.gen_pk(table_name) + index = self.gen_index(table_ddl) + comment = self.gen_comment(table_sql, table_name) + inserts = self.gen_insert(table_name) + + # 组合当前表的DDL脚本 + script = f"""{create} + +{pk} + +{index} + +{comment} + +{inserts} +""" + + # 清理 + script = re.sub("\n{3,}", "\n\n", script).strip() + "\n" + + print(script) + + # 将parse失败的脚本打印出来 + if error_scripts: + for script in error_scripts: + print(script) + + +class PostgreSQLConvertor(Convertor): + def __init__(self, src): + super().__init__(src, "PostgreSQL") + + def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]): + """类型转换""" + + type = type.lower() + + if type == "varchar": + return f"varchar({size})" + if type == "int": + return "int4" + if type == "bigint" or type == "bigint unsigned": + return "int8" + if type == "datetime": + return "timestamp" + if type == "bit": + return "bool" + if type in ("tinyint", "smallint"): + return "int2" + if type == "text": + return "text" + if type in ("blob", "mediumblob"): + return "bytea" + if type == "decimal": + return ( + f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric" + ) + + def gen_create(self, ddl: Dict) -> str: + """生成 create""" + + def _generate_column(col): + name = col["name"].lower() + if name == "deleted": + return "deleted int2 NOT NULL DEFAULT 0" + + type = col["type"].lower() + full_type = self.translate_type(type, col["size"]) + nullable = "NULL" if col["nullable"] else "NOT NULL" + default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + return f"{name} {full_type} {nullable} {default}" + + table_name = ddl["table_name"].lower() + columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]] + filed_def_list = ",\n ".join(columns) + script = f"""-- ---------------------------- +-- Table structure for {table_name} +-- ---------------------------- +DROP TABLE IF EXISTS {table_name}; +CREATE TABLE {table_name} ( + {filed_def_list} +);""" + + return script + + def gen_index(self, ddl: Dict) -> str: + return "\n".join(f"{script};" for script in self.index(ddl)) + + def gen_comment(self, table_sql: str, table_name: str) -> str: + """生成字段及表的注释""" + + script = "" + for field, comment_string in self.filed_comments(table_sql): + script += ( + f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" + ) + + table_comment = self.table_comment(table_sql) + if table_comment: + script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" + + return script + + def gen_pk(self, table_name) -> str: + """生成主键定义""" + return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" + + def gen_insert(self, table_name: str) -> str: + """生成 insert 语句,以及根据最后的 insert id+1 生成 Sequence""" + + inserts = list(Convertor.inserts(table_name, self.content)) + ## 生成 insert 脚本 + script = "" + last_id = 0 + if inserts: + inserts_lines = "\n".join(inserts) + script += f"""\n\n-- ---------------------------- +-- Records of {table_name.lower()} +-- ---------------------------- +-- @formatter:off +BEGIN; +{inserts_lines} +COMMIT; +-- @formatter:on""" + match = re.search(r"VALUES \((\d+),", inserts[-1]) + if match: + last_id = int(match.group(1)) + + # 生成 Sequence + script += ( + "\n\n" + + f"""DROP SEQUENCE IF EXISTS {table_name}_seq; +CREATE SEQUENCE {table_name}_seq + START {last_id + 1};""" + ) + + return script + + def gen_dual(self) -> str: + return """DROP TABLE IF EXISTS dual; +CREATE TABLE dual +( + id int2 +); + +COMMENT ON TABLE dual IS '数据库连接的表'; + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1); +-- @formatter:on""" + + +class OracleConvertor(Convertor): + def __init__(self, src): + super().__init__(src, "Oracle") + + def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]): + """类型转换""" + type = type.lower() + + if type == "varchar": + return f"varchar2({size if size < 4000 else 4000})" + if type == "int": + return "number" + if type == "bigint" or type == "bigint unsigned": + return "number" + if type == "datetime": + return "date" + if type == "bit": + return "number(1,0)" + if type in ("tinyint", "smallint"): + return "smallint" + if type == "text": + return "clob" + if type in ("blob", "mediumblob"): + return "blob" + if type == "decimal": + return ( + f"number({','.join(str(s) for s in size)})" if len(size) else "number" + ) + + def gen_create(self, ddl) -> str: + """生成 CREATE 语句""" + + def generate_column(col): + name = col["name"].lower() + if name == "deleted": + return "deleted number(1,0) DEFAULT 0 NOT NULL" + + type = col["type"].lower() + full_type = self.translate_type(type, col["size"]) + nullable = "NULL" if col["nullable"] else "NOT NULL" + default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + # Oracle 中 size 不能作为字段名 + field_name = '"size"' if name == "size" else name + # Oracle DEFAULT 定义在 NULLABLE 之前 + return f"{field_name} {full_type} {default} {nullable}" + + table_name = ddl["table_name"].lower() + columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]] + field_def_list = ",\n ".join(columns) + script = f"""-- ---------------------------- +-- Table structure for {table_name} +-- ---------------------------- +CREATE TABLE {table_name} ( + {field_def_list} +);""" + + # oracle INSERT '' 不能通过 NOT NULL 校验 + script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL") + + return script + + def gen_index(self, ddl: Dict) -> str: + return "\n".join(f"{script};" for script in self.index(ddl)) + + def gen_comment(self, table_sql: str, table_name: str) -> str: + script = "" + for field, comment_string in self.filed_comments(table_sql): + script += ( + f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" + ) + + table_comment = self.table_comment(table_sql) + if table_comment: + script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" + + return script + + def gen_pk(self, table_name: str) -> str: + """生成主键定义""" + return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" + + def gen_index(self, ddl: Dict) -> str: + return "\n".join(f"{script};" for script in self.index(ddl)) + + def gen_insert(self, table_name: str) -> str: + """拷贝 INSERT 语句""" + inserts = [] + for insert_script in Convertor.inserts(table_name, self.content): + # 对日期数据添加 TO_DATE 转换 + insert_script = re.sub( + r"('\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')", + r"to_date(\g<1>, 'SYYYY-MM-DD HH24:MI:SS')", + insert_script, + ) + inserts.append(insert_script) + + ## 生成 insert 脚本 + script = "" + last_id = 0 + if inserts: + inserts_lines = "\n".join(inserts) + script += f"""\n\n-- ---------------------------- +-- Records of {table_name.lower()} +-- ---------------------------- +-- @formatter:off +{inserts_lines} +COMMIT; +-- @formatter:on""" + match = re.search(r"VALUES \((\d+),", inserts[-1]) + if match: + last_id = int(match.group(1)) + + # 生成 Sequence + script += f""" + +CREATE SEQUENCE {table_name}_seq + START WITH {last_id + 1};""" + + return script + + +class SQLServerConvertor(Convertor): + """_summary_ + + Args: + Convertor (_type_): _description_ + """ + + def __init__(self, src): + super().__init__(src, "Microsoft SQL Server") + + def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]): + """类型转换""" + + type = type.lower() + + if type == "varchar": + return f"nvarchar({size if size < 4000 else 4000})" + if type == "int": + return "int" + if type == "bigint" or type == "bigint unsigned": + return "bigint" + if type == "datetime": + return "datetime2" + if type == "bit": + return "varchar(1)" + if type in ("tinyint", "smallint"): + return "tinyint" + if type == "text": + return "nvarchar(max)" + if type in ("blob", "mediumblob"): + return "varbinary(max)" + if type == "decimal": + return ( + f"numeric({','.join(str(s) for s in size)})" if len(size) else "numeric" + ) + + def gen_create(self, ddl: Dict) -> str: + """生成 create""" + + def _generate_column(col): + name = col["name"].lower() + if name == "id": + return "id bigint NOT NULL PRIMARY KEY IDENTITY" + if name == "deleted": + return "deleted bit DEFAULT 0 NOT NULL" + + type = col["type"].lower() + full_type = self.translate_type(type, col["size"]) + nullable = "NULL" if col["nullable"] else "NOT NULL" + default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + return f"{name} {full_type} {default} {nullable}" + + table_name = ddl["table_name"].lower() + columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]] + filed_def_list = ",\n ".join(columns) + script = f"""-- ---------------------------- +-- Table structure for {table_name} +-- ---------------------------- +DROP TABLE IF EXISTS {table_name} +GO +CREATE TABLE {table_name} ( + {filed_def_list} +) +GO""" + + return script + + def gen_comment(self, table_sql: str, table_name: str) -> str: + """生成字段及表的注释""" + + script = "" + + for field, comment_string in self.filed_comments(table_sql): + script += f"""EXEC sp_addextendedproperty + 'MS_Description', N'{comment_string}', + 'SCHEMA', N'dbo', + 'TABLE', N'{table_name}', + 'COLUMN', N'{field}' +GO + +""" + + table_comment = self.table_comment(table_sql) + if table_comment: + script += f"""EXEC sp_addextendedproperty + 'MS_Description', N'{table_comment}', + 'SCHEMA', N'dbo', + 'TABLE', N'{table_name}' +GO + +""" + return script + + def gen_pk(self, table_name: str) -> str: + """生成主键定义""" + return "" + + def gen_index(self, ddl: Dict) -> str: + """生成 index""" + return "\n".join(f"{script}\nGO" for script in self.index(ddl)) + + def gen_insert(self, table_name: str) -> str: + """生成 insert 语句""" + + # 收集 `table_name` 对应的 insert 语句 + inserts = [] + for insert_script in Convertor.inserts(table_name, self.content): + # SQLServer: 字符串前加N,hack,是否存在替换字符串内容的风险 + insert_script = insert_script.replace(", '", ", N'").replace( + "VALUES ('", "VALUES (N')" + ) + # 删除 insert 的结尾分号 + insert_script = re.sub(";$", r"\nGO", insert_script) + inserts.append(insert_script) + + ## 生成 insert 脚本 + script = "" + if inserts: + inserts_lines = "\n".join(inserts) + script += f"""\n\n-- ---------------------------- +-- Records of {table_name.lower()} +-- ---------------------------- +-- @formatter:off +BEGIN TRANSACTION +GO +SET IDENTITY_INSERT {table_name.lower()} ON +GO +{inserts_lines} +SET IDENTITY_INSERT {table_name.lower()} OFF +GO +COMMIT +GO +-- @formatter:on""" + + return script + + def gen_dual(self) -> str: + return """DROP TABLE IF EXISTS dual +GO +CREATE TABLE dual +( + id int +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据库连接的表', + 'SCHEMA', N'dbo', + 'TABLE', N'dual' +GO + +-- ---------------------------- +-- Records of dual +-- ---------------------------- +-- @formatter:off +INSERT INTO dual VALUES (1) +GO +-- @formatter:on""" + + +class DM8Convertor(Convertor): + def __init__(self, src): + super().__init__(src, "DM8") + + def translate_type(self, type: str, size: Optional[Union[int, Tuple[int]]]): + """类型转换""" + type = type.lower() + + if type == "varchar": + return f"varchar({size})" + if type == "int": + return "int" + if type == "bigint" or type == "bigint unsigned": + return "bigint" + if type == "datetime": + return "datetime" + if type == "bit": + return "bit" + if type in ("tinyint", "smallint"): + return "smallint" + if type == "text": + return "text" + if type == "blob": + return "blob" + if type == "mediumblob": + return "varchar(10240)" + if type == "decimal": + return ( + f"decimal({','.join(str(s) for s in size)})" if len(size) else "decimal" + ) + + def gen_create(self, ddl) -> str: + """生成 CREATE 语句""" + + def generate_column(col): + name = col["name"].lower() + if name == "id": + return "id bigint NOT NULL PRIMARY KEY IDENTITY" + + type = col["type"].lower() + full_type = self.translate_type(type, col["size"]) + nullable = "NULL" if col["nullable"] else "NOT NULL" + default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + return f"{name} {full_type} {default} {nullable}" + + table_name = ddl["table_name"].lower() + columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]] + field_def_list = ",\n ".join(columns) + script = f"""-- ---------------------------- +-- Table structure for {table_name} +-- ---------------------------- +CREATE TABLE {table_name} ( + {field_def_list} +);""" + + # oracle INSERT '' 不能通过 NOT NULL 校验 + script = script.replace("DEFAULT '' NOT NULL", "DEFAULT '' NULL") + + return script + + def gen_index(self, ddl: Dict) -> str: + return "\n".join(f"{script};" for script in self.index(ddl)) + + def gen_comment(self, table_sql: str, table_name: str) -> str: + script = "" + for field, comment_string in self.filed_comments(table_sql): + script += ( + f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" + ) + + table_comment = self.table_comment(table_sql) + if table_comment: + script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" + + return script + + def gen_pk(self, table_name: str) -> str: + """生成主键定义""" + return "" + + def gen_index(self, ddl: Dict) -> str: + return "\n".join(f"{script};" for script in self.index(ddl)) + + def gen_insert(self, table_name: str) -> str: + """拷贝 INSERT 语句""" + inserts = list(Convertor.inserts(table_name, self.content)) + + ## 生成 insert 脚本 + script = "" + if inserts: + inserts_lines = "\n".join(inserts) + script += f"""\n\n-- ---------------------------- +-- Records of {table_name.lower()} +-- ---------------------------- +-- @formatter:off +SET IDENTITY_INSERT {table_name.lower()} ON; +{inserts_lines} +COMMIT; +SET IDENTITY_INSERT {table_name.lower()} OFF; +-- @formatter:on""" + + return script + + +class KingbaseConvertor(PostgreSQLConvertor): + def __init__(self, src): + super().__init__(src) + self.db_type = "Kingbase" + + def gen_create(self, ddl: Dict) -> str: + """生成 create""" + + def _generate_column(col): + name = col["name"].lower() + if name == "deleted": + return "deleted int2 NOT NULL DEFAULT 0" + + type = col["type"].lower() + full_type = self.translate_type(type, col["size"]) + nullable = "NULL" if col["nullable"] else "NOT NULL" + default = f"DEFAULT {col['default']}" if col["default"] is not None else "" + return f"{name} {full_type} {nullable} {default}" + + table_name = ddl["table_name"].lower() + columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]] + filed_def_list = ",\n ".join(columns) + script = f"""-- ---------------------------- +-- Table structure for {table_name} +-- ---------------------------- +DROP TABLE IF EXISTS {table_name}; +CREATE TABLE {table_name} ( + {filed_def_list} +);""" + + # Kingbase INSERT '' 不能通过 NOT NULL 校验 + script = script.replace("NOT NULL DEFAULT ''", "NULL DEFAULT ''") + + return script + + +class OpengaussConvertor(KingbaseConvertor): + def __init__(self, src): + super().__init__(src) + self.db_type = "OpenGauss" + + +def main(): + parser = argparse.ArgumentParser(description="芋道系统数据库转换工具") + parser.add_argument( + "type", + type=str, + help="目标数据库类型", + choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss"], + ) + args = parser.parse_args() + + sql_file = pathlib.Path("../mysql/ruoyi-vue-pro.sql").resolve().as_posix() + convertor = None + if args.type == "postgres": + convertor = PostgreSQLConvertor(sql_file) + elif args.type == "oracle": + convertor = OracleConvertor(sql_file) + elif args.type == "sqlserver": + convertor = SQLServerConvertor(sql_file) + elif args.type == "dm8": + convertor = DM8Convertor(sql_file) + elif args.type == "kingbase": + convertor = KingbaseConvertor(sql_file) + elif args.type == "opengauss": + convertor = OpengaussConvertor(sql_file) + else: + raise NotImplementedError(f"不支持目标数据库类型: {args.type}") + + convertor.print() + + +if __name__ == "__main__": + main() diff --git a/ruoyi-vue-pro-master/sql/tools/docker-compose.yaml b/ruoyi-vue-pro-master/sql/tools/docker-compose.yaml new file mode 100644 index 0000000..d6f615d --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/docker-compose.yaml @@ -0,0 +1,126 @@ +name: ruoyi-vue-pro + +volumes: + mysql: { } + postgres: { } + sqlserver: { } + dm8: { } + kingbase: { } + opengauss: { } + +services: + mysql: + image: mysql:8.0.33 + restart: unless-stopped + environment: + TZ: Asia/Shanghai + MYSQL_ROOT_PASSWORD: 123456 + MYSQL_DATABASE: ruoyi-vue-pro + ports: + - "3306:3306" + volumes: + - mysql:/var/lib/mysql/ + # 注入初始化脚本 + - ./mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/init.sql:ro + command: + --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 + + postgres: + image: postgres:14.2 + restart: unless-stopped + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: 123456 + POSTGRES_DB: ruoyi-vue-pro + ports: + - "5432:5432" + volumes: + - postgres:/var/lib/postgresql/data + # 注入初始化脚本 + - ../postgresql/quartz.sql:/docker-entrypoint-initdb.d/quartz.sql:ro + - ../postgresql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro + + oracle: + image: gvenzl/oracle-xe:18-slim-faststart + restart: unless-stopped + environment: + ## 登录信息 SID: XE user: system password: oracle + ORACLE_PASSWORD: oracle + ports: + - "1521:1521" + volumes: + - ../oracle/ruoyi-vue-pro.sql:/tmp/schema.sql:ro + # 创建app用户: ROOT/123456@//localhost/XEPDB1 + - ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro + - ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro + + sqlserver: + image: mcr.microsoft.com/mssql/server:2017-latest + restart: unless-stopped + environment: + TZ: Asia/Shanghai + ACCEPT_EULA: "Y" + SA_PASSWORD: "Yudao@2024" + ports: + - "1433:1433" + volumes: + - sqlserver:/var/opt/mssql + - ../sqlserver/ruoyi-vue-pro.sql:/tmp/schema.sql:ro + # docker compose exec sqlserver bash /tmp/create_schema.sh + - ./sqlserver/create_schema.sh:/tmp/create_schema.sh:ro + + + dm8: + # wget https://download.dameng.com/eco/dm8/dm8_20230808_rev197096_x86_rh6_64_single.tar + # docker load -i dm8_20230808_rev197096_x86_rh6_64_single.tar + image: dm8_single:dm8_20230808_rev197096_x86_rh6_64 + restart: unless-stopped + environment: + PAGE_SIZE: 16 + LD_LIBRARY_PATH: /opt/dmdbms/bin + EXTENT_SIZE: 32 + BLANK_PAD_MODE: 1 + LOG_SIZE: 1024 + UNICODE_FLAG: 1 + LENGTH_IN_CHAR: 1 + INSTANCE_NAME: dm8_test + ports: + - "5236:5236" + volumes: + - dm8:/opt/dmdbms/data + - ../dm/ruoyi-vue-pro-dm8.sql:/tmp/schema.sql:ro + # docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql' + + kingbase: + # x86_64: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar + # aarch64: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar + # docker load -i kdb_x86_64_V009R001C001B0025.tar + image: kingbase_v009r001c001b0025_single_x86:v1 + restart: unless-stopped + environment: + DB_USER: root + DB_PASSWORD: 123456 + ports: + - "54321:54321" + volumes: + - kingbase:/home/kingbase/userdata + - ../kingbase/ruoyi-vue-pro.sql:/tmp/schema.sql:ro + # docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql' + + opengauss: + image: opengauss/opengauss:5.0.0 + restart: unless-stopped + environment: + GS_USERNAME: root + GS_PASSWORD: Yudao@2024 + LD_LIBRARY_PATH: /usr/local/opengauss/lib:/usr/lib + ports: + - "5432:5432" + volumes: + - opengauss:/var/lib/opengauss + - ../opengauss/ruoyi-vue-pro.sql:/tmp/schema.sql:ro + # docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql' \ No newline at end of file diff --git a/ruoyi-vue-pro-master/sql/tools/oracle/1_create_user.sql b/ruoyi-vue-pro-master/sql/tools/oracle/1_create_user.sql new file mode 100644 index 0000000..58c9658 --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/oracle/1_create_user.sql @@ -0,0 +1,3 @@ +ALTER SESSION SET CONTAINER=XEPDB1; +CREATE USER ROOT IDENTIFIED BY 123456 QUOTA UNLIMITED ON USERS; +GRANT CONNECT, RESOURCE TO ROOT; diff --git a/ruoyi-vue-pro-master/sql/tools/oracle/2_create_schema.sh b/ruoyi-vue-pro-master/sql/tools/oracle/2_create_schema.sh new file mode 100644 index 0000000..ce7955d --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/oracle/2_create_schema.sh @@ -0,0 +1 @@ +sqlplus -s ROOT/123456@//localhost/XEPDB1 @/tmp/schema.sql diff --git a/ruoyi-vue-pro-master/sql/tools/sqlserver/create_schema.sh b/ruoyi-vue-pro-master/sql/tools/sqlserver/create_schema.sh new file mode 100644 index 0000000..172650b --- /dev/null +++ b/ruoyi-vue-pro-master/sql/tools/sqlserver/create_schema.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -Q "CREATE DATABASE [ruoyi-vue-pro]; +GO" +/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -d 'ruoyi-vue-pro' -i /tmp/schema.sql diff --git a/ruoyi-vue-pro-master/yudao-dependencies/pom.xml b/ruoyi-vue-pro-master/yudao-dependencies/pom.xml new file mode 100644 index 0000000..d857ebd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-dependencies/pom.xml @@ -0,0 +1,655 @@ + + + 4.0.0 + + cn.iocoder.boot + yudao-dependencies + ${revision} + pom + + ${project.artifactId} + 基础 bom 文件,管理整个项目的依赖版本 + https://github.com/YunaiV/ruoyi-vue-pro + + + 2.1.0-jdk8-snapshot + 1.5.0 + + 2.7.18 + + 1.6.15 + 4.3.0 + 2.5 + + 1.2.21 + 3.5.5 + 3.5.5 + 4.3.0 + 1.4.10 + 2.2.11 + 3.18.0 + 8.1.3.62 + 8.6.0 + 5.0.2 + + 2.2.3 + + 2.2.7 + + 8.12.0 + 2.7.15 + 0.33.0 + + 7.2.11.RELEASE + 1.0.13 + 4.11.0 + + 6.8.0 + + 1.0.10 + 1.17.2 + 1.18.30 + 1.5.5.Final + 5.8.25 + 3.3.3 + 2.3 + 1.0.5 + 1.2.83 + 33.0.0-jre + 5.1.0 + 2.14.5 + 3.10.0 + 0.1.55 + 2.9.1 + 2.7.0 + 3.0.6 + + 3.5.0 + 4.11.0 + 2.15.1 + 8.5.7 + 4.6.4 + 2.2.1 + 3.1.880 + 1.0.8 + 1.6.6 + 2.12.2 + 4.6.0 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + io.github.mouzt + bizlog-sdk + ${bizlog-sdk.version} + + + org.springframework.boot + spring-boot-starter + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + ${revision} + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-data-permission + ${revision} + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + ${revision} + + + + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + ${revision} + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + ${revision} + + + + cn.iocoder.boot + yudao-spring-boot-starter-websocket + ${revision} + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + ${knife4j.version} + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + ${revision} + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-generator + ${mybatis-plus-generator.version} + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${dynamic-datasource.version} + + + com.github.yulichang + mybatis-plus-join-boot-starter + ${mybatis-plus-join.version} + + + + com.fhs-opensource + easy-trans-spring-boot-starter + ${easy-trans.version} + + + org.springframework + spring-context + + + org.springframework.cloud + spring-cloud-commons + + + + + com.fhs-opensource + easy-trans-mybatis-plus-extend + ${easy-trans.version} + + + com.fhs-opensource + easy-trans-anno + ${easy-trans.version} + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + ${revision} + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + com.dameng + DmJdbcDriver18 + ${dm8.jdbc.version} + + + + org.opengauss + opengauss-jdbc + ${opengauss.jdbc.version} + + + + cn.com.kingbase + kingbase8 + ${kingbase.jdbc.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-job + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + ${revision} + + + + org.apache.rocketmq + rocketmq-spring-boot-starter + ${rocketmq-spring.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-protection + ${revision} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + redisson-spring-boot-starter + org.redisson + + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-monitor + ${revision} + + + + org.apache.skywalking + apm-toolkit-trace + ${skywalking.version} + + + org.apache.skywalking + apm-toolkit-logback-1.x + ${skywalking.version} + + + org.apache.skywalking + apm-toolkit-opentracing + ${skywalking.version} + + + + + + + + + + + + + io.opentracing + opentracing-api + ${opentracing.version} + + + io.opentracing + opentracing-util + ${opentracing.version} + + + io.opentracing + opentracing-noop + ${opentracing.version} + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + de.codecentric + spring-boot-admin-server-cloud + + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + ${revision} + test + + + + org.mockito + mockito-inline + ${mockito-inline.version} + + + + org.springframework.boot + spring-boot-starter-test + ${spring.boot.version} + + + asm + org.ow2.asm + + + org.mockito + mockito-core + + + + + + com.github.fppt + jedis-mock + ${jedis-mock.version} + + + + uk.co.jemos.podam + podam + ${podam.version} + + + + + org.flowable + flowable-spring-boot-starter-process + ${flowable.version} + + + org.flowable + flowable-spring-boot-starter-actuator + ${flowable.version} + + + + + + cn.iocoder.boot + yudao-common + ${revision} + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + ${revision} + + + + org.projectlombok + lombok + ${lombok.version} + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-jdk8 + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + + com.alibaba + easyexcel + ${easyexcel.verion} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.tika + tika-core + ${tika-core.version} + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + com.alibaba + fastjson + ${fastjson.version} + + + + com.google.guava + guava + ${guava.version} + + + + com.google.inject + guice + ${guice.version} + + + + com.alibaba + transmittable-thread-local + ${transmittable-thread-local.version} + + + + commons-net + commons-net + ${commons-net.version} + + + + com.jcraft + jsch + ${jsch.version} + + + + com.xingyuv + spring-boot-starter-captcha-plus + ${captcha-plus.version} + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + org.jsoup + jsoup + ${jsoup.version} + + + + + com.squareup.okio + okio + ${okio.version} + + + com.squareup.okhttp3 + okhttp + ${okhttp3.version} + + + io.minio + minio + ${minio.version} + + + + + com.aliyun + aliyun-java-sdk-core + ${aliyun-java-sdk-core.version} + + + opentracing-api + io.opentracing + + + opentracing-util + io.opentracing + + + + + com.aliyun + aliyun-java-sdk-dysmsapi + ${aliyun-java-sdk-dysmsapi.version} + + + com.tencentcloudapi + tencentcloud-sdk-java-sms + ${tencentcloud-sdk-java.version} + + + + + com.xingyuv + spring-boot-starter-justauth + ${justauth.version} + + + cn.hutool + hutool-core + + + + + + com.github.binarywang + weixin-java-pay + ${weixin-java.version} + + + com.github.binarywang + wx-java-mp-spring-boot-starter + ${weixin-java.version} + + + com.github.binarywang + wx-java-miniapp-spring-boot-starter + ${weixin-java.version} + + + + + org.jeecgframework.jimureport + jimureport-spring-boot-starter + ${jimureport.version} + + + com.alibaba + druid + + + + + xerces + xercesImpl + ${xercesImpl.version} + + + + + + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + resolveCiFriendliesOnly + true + + + + + flatten + + flatten + process-resources + + + + clean + + flatten.clean + clean + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/pom.xml b/ruoyi-vue-pro-master/yudao-framework/pom.xml new file mode 100644 index 0000000..76e6740 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + yudao + cn.iocoder.boot + ${revision} + + pom + + yudao-common + yudao-spring-boot-starter-mybatis + yudao-spring-boot-starter-redis + yudao-spring-boot-starter-web + yudao-spring-boot-starter-security + yudao-spring-boot-starter-websocket + + yudao-spring-boot-starter-monitor + yudao-spring-boot-starter-protection + yudao-spring-boot-starter-job + yudao-spring-boot-starter-mq + + yudao-spring-boot-starter-excel + yudao-spring-boot-starter-test + + yudao-spring-boot-starter-biz-tenant + yudao-spring-boot-starter-biz-data-permission + yudao-spring-boot-starter-biz-ip + + + yudao-framework + + 该包是技术组件,每个子包,代表一个组件。每个组件包括两部分: + 1. core 包:是该组件的核心封装 + 2. config 包:是该组件基于 Spring 的配置 + + 技术组件,也分成两类: + 1. 框架组件:和我们熟悉的 MyBatis、Redis 等等的拓展 + 2. 业务组件:和业务相关的组件的封装,例如说数据字典、操作日志等等。 + 如果是业务组件,Maven 名字会包含 biz + + https://github.com/YunaiV/ruoyi-vue-pro + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml new file mode 100644 index 0000000..f364df7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/pom.xml @@ -0,0 +1,149 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-common + jar + + ${project.artifactId} + 定义基础 pojo 类、枚举、工具类等等 + https://github.com/YunaiV/ruoyi-vue-pro + + + + + org.springframework + spring-core + provided + + + org.springframework + spring-expression + provided + + + org.springframework + spring-aop + provided + + + org.aspectj + aspectjweaver + provided + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.springframework + spring-web + provided + + + + jakarta.servlet + jakarta.servlet-api + provided + + + + org.springdoc + springdoc-openapi-ui + provided + + + + + org.apache.skywalking + apm-toolkit-trace + + + + + org.projectlombok + lombok + + + + org.mapstruct + mapstruct + + + org.mapstruct + mapstruct-jdk8 + + + org.mapstruct + mapstruct-processor + + + + com.google.guava + guava + provided + + + + com.fasterxml.jackson.core + jackson-databind + provided + + + com.fasterxml.jackson.core + jackson-core + provided + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + provided + + + + org.slf4j + slf4j-api + provided + + + + jakarta.validation + jakarta.validation-api + provided + + + + cn.hutool + hutool-all + + + + com.alibaba + transmittable-thread-local + + + + com.fhs-opensource + easy-trans-anno + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/IntArrayValuable.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/IntArrayValuable.java new file mode 100644 index 0000000..8914231 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/IntArrayValuable.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.framework.common.core; + +/** + * 可生成 Int 数组的接口 + * + * @author 芋道源码 + */ +public interface IntArrayValuable { + + /** + * @return int 数组 + */ + int[] array(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/KeyValue.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/KeyValue.java new file mode 100644 index 0000000..07a8f39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/core/KeyValue.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.common.core; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * Key Value 的键值对 + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class KeyValue implements Serializable { + + private K key; + private V value; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/CommonStatusEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/CommonStatusEnum.java new file mode 100644 index 0000000..facf326 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/CommonStatusEnum.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.common.enums; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 通用状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum CommonStatusEnum implements IntArrayValuable { + + ENABLE(0, "开启"), + DISABLE(1, "关闭"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isEnable(Integer status) { + return ObjUtil.equal(ENABLE.status, status); + } + + public static boolean isDisable(Integer status) { + return ObjUtil.equal(DISABLE.status, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java new file mode 100644 index 0000000..498b671 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.common.enums; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 时间间隔的枚举 + * + * @author dhb52 + */ +@Getter +@AllArgsConstructor +public enum DateIntervalEnum implements IntArrayValuable { + + DAY(1, "天"), + WEEK(2, "周"), + MONTH(3, "月"), + QUARTER(4, "季度"), + YEAR(5, "年") + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getInterval).toArray(); + + /** + * 类型 + */ + private final Integer interval; + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static DateIntervalEnum valueOf(Integer interval) { + return ArrayUtil.firstMatch(item -> item.getInterval().equals(interval), DateIntervalEnum.values()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DocumentEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DocumentEnum.java new file mode 100644 index 0000000..a96ee24 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DocumentEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 文档地址 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum DocumentEnum { + + REDIS_INSTALL("https://gitee.com/zhijiantianya/ruoyi-vue-pro/issues/I4VCSJ", "Redis 安装文档"), + TENANT("https://doc.iocoder.cn", "SaaS 多租户文档"); + + private final String url; + private final String memo; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java new file mode 100644 index 0000000..f256712 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.common.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 终端的枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum TerminalEnum implements IntArrayValuable { + + UNKNOWN(0, "未知"), // 目的:在无法解析到 terminal 时,使用它 + WECHAT_MINI_PROGRAM(10, "微信小程序"), + WECHAT_WAP(11, "微信公众号"), + H5(20, "H5 网页"), + APP(31, "手机 App"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TerminalEnum::getTerminal).toArray(); + + /** + * 终端 + */ + private final Integer terminal; + /** + * 终端名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/UserTypeEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/UserTypeEnum.java new file mode 100644 index 0000000..c950c52 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/UserTypeEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.framework.common.enums; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 全局用户类型枚举 + */ +@AllArgsConstructor +@Getter +public enum UserTypeEnum implements IntArrayValuable { + + MEMBER(1, "会员"), // 面向 c 端,普通用户 + ADMIN(2, "管理员"); // 面向 b 端,管理后台 + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(UserTypeEnum::getValue).toArray(); + + /** + * 类型 + */ + private final Integer value; + /** + * 类型名 + */ + private final String name; + + public static UserTypeEnum valueOf(Integer value) { + return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values()); + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java new file mode 100644 index 0000000..11a5ee0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.common.enums; + +/** + * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期 + * + * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enums 包下 + * + * @author 芋道源码 + */ +public interface WebFilterOrderEnum { + + int CORS_FILTER = Integer.MIN_VALUE; + + int TRACE_FILTER = CORS_FILTER + 1; + + int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500; + + // OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等 + + int TENANT_CONTEXT_FILTER = - 104; // 需要保证在 ApiAccessLogFilter 前面 + + int API_ACCESS_LOG_FILTER = -103; // 需要保证在 RequestBodyCacheFilter 后面 + + int XSS_FILTER = -102; // 需要保证在 RequestBodyCacheFilter 后面 + + // Spring Security Filter 默认为 -100,可见 org.springframework.boot.autoconfigure.security.SecurityProperties 配置属性类 + + int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后面 + + int FLOWABLE_FILTER = -98; // 需要保证在 Spring Security 过滤后面 + + int DEMO_FILTER = Integer.MAX_VALUE; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ErrorCode.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ErrorCode.java new file mode 100644 index 0000000..45feaec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ErrorCode.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.common.exception; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.exception.enums.ServiceErrorCodeRange; +import lombok.Data; + +/** + * 错误码对象 + * + * 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants} + * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange} + * + * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 + */ +@Data +public class ErrorCode { + + /** + * 错误码 + */ + private final Integer code; + /** + * 错误提示 + */ + private final String msg; + + public ErrorCode(Integer code, String message) { + this.code = code; + this.msg = message; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServerException.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServerException.java new file mode 100644 index 0000000..fac56d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServerException.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.common.exception; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 服务器异常 Exception + */ +@Data +@EqualsAndHashCode(callSuper = true) +public final class ServerException extends RuntimeException { + + /** + * 全局错误码 + * + * @see GlobalErrorCodeConstants + */ + private Integer code; + /** + * 错误提示 + */ + private String message; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServerException() { + } + + public ServerException(ErrorCode errorCode) { + this.code = errorCode.getCode(); + this.message = errorCode.getMsg(); + } + + public ServerException(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public ServerException setCode(Integer code) { + this.code = code; + return this; + } + + @Override + public String getMessage() { + return message; + } + + public ServerException setMessage(String message) { + this.message = message; + return this; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServiceException.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServiceException.java new file mode 100644 index 0000000..5c6967e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/ServiceException.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.common.exception; + +import cn.iocoder.yudao.framework.common.exception.enums.ServiceErrorCodeRange; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 业务逻辑异常 Exception + */ +@Data +@EqualsAndHashCode(callSuper = true) +public final class ServiceException extends RuntimeException { + + /** + * 业务错误码 + * + * @see ServiceErrorCodeRange + */ + private Integer code; + /** + * 错误提示 + */ + private String message; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException() { + } + + public ServiceException(ErrorCode errorCode) { + this.code = errorCode.getCode(); + this.message = errorCode.getMsg(); + } + + public ServiceException(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public ServiceException setCode(Integer code) { + this.code = code; + return this; + } + + @Override + public String getMessage() { + return message; + } + + public ServiceException setMessage(String message) { + this.message = message; + return this; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java new file mode 100644 index 0000000..edf31f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.framework.common.exception.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * 全局错误码枚举 + * 0-999 系统异常编码保留 + * + * 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status + * 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的 + * 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。 + * + * @author 芋道源码 + */ +public interface GlobalErrorCodeConstants { + + ErrorCode SUCCESS = new ErrorCode(0, "成功"); + + // ========== 客户端错误段 ========== + + ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确"); + ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录"); + ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限"); + ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到"); + ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确"); + ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许 + ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试"); + + // ========== 服务端错误段 ========== + + ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常"); + ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启"); + ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项"); + + // ========== 自定义错误段 ========== + ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求 + ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作"); + + ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/ServiceErrorCodeRange.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/ServiceErrorCodeRange.java new file mode 100644 index 0000000..94dd67c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/ServiceErrorCodeRange.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.common.exception.enums; + +/** + * 业务异常的错误码区间,解决:解决各模块错误码定义,避免重复,在此只声明不做实际使用 + * + * 一共 10 位,分成四段 + * + * 第一段,1 位,类型 + * 1 - 业务级别异常 + * x - 预留 + * 第二段,3 位,系统类型 + * 001 - 用户系统 + * 002 - 商品系统 + * 003 - 订单系统 + * 004 - 支付系统 + * 005 - 优惠劵系统 + * ... - ... + * 第三段,3 位,模块 + * 不限制规则。 + * 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子: + * 001 - OAuth2 模块 + * 002 - User 模块 + * 003 - MobileCode 模块 + * 第四段,3 位,错误码 + * 不限制规则。 + * 一般建议,每个模块自增。 + * + * @author 芋道源码 + */ +public class ServiceErrorCodeRange { + + // 模块 infra 错误码区间 [1-001-000-000 ~ 1-002-000-000) + // 模块 system 错误码区间 [1-002-000-000 ~ 1-003-000-000) + // 模块 report 错误码区间 [1-003-000-000 ~ 1-004-000-000) + // 模块 member 错误码区间 [1-004-000-000 ~ 1-005-000-000) + // 模块 mp 错误码区间 [1-006-000-000 ~ 1-007-000-000) + // 模块 pay 错误码区间 [1-007-000-000 ~ 1-008-000-000) + // 模块 bpm 错误码区间 [1-009-000-000 ~ 1-010-000-000) + + // 模块 product 错误码区间 [1-008-000-000 ~ 1-009-000-000) + // 模块 trade 错误码区间 [1-011-000-000 ~ 1-012-000-000) + // 模块 promotion 错误码区间 [1-013-000-000 ~ 1-014-000-000) + + // 模块 crm 错误码区间 [1-020-000-000 ~ 1-021-000-000) + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java new file mode 100644 index 0000000..03c0859 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.framework.common.exception.util; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; + +/** + * {@link ServiceException} 工具类 + * + * 目的在于,格式化异常信息提示。 + * 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化 + * + */ +@Slf4j +public class ServiceExceptionUtil { + + // ========== 和 ServiceException 的集成 ========== + + public static ServiceException exception(ErrorCode errorCode) { + return exception0(errorCode.getCode(), errorCode.getMsg()); + } + + public static ServiceException exception(ErrorCode errorCode, Object... params) { + return exception0(errorCode.getCode(), errorCode.getMsg(), params); + } + + public static ServiceException exception0(Integer code, String messagePattern, Object... params) { + String message = doFormat(code, messagePattern, params); + return new ServiceException(code, message); + } + + public static ServiceException invalidParamException(String messagePattern, Object... params) { + return exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), messagePattern, params); + } + + // ========== 格式化方法 ========== + + /** + * 将错误编号对应的消息使用 params 进行格式化。 + * + * @param code 错误编号 + * @param messagePattern 消息模版 + * @param params 参数 + * @return 格式化后的提示 + */ + @VisibleForTesting + public static String doFormat(int code, String messagePattern, Object... params) { + StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50); + int i = 0; + int j; + int l; + for (l = 0; l < params.length; l++) { + j = messagePattern.indexOf("{}", i); + if (j == -1) { + log.error("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params); + if (i == 0) { + return messagePattern; + } else { + sbuf.append(messagePattern.substring(i)); + return sbuf.toString(); + } + } else { + sbuf.append(messagePattern, i, j); + sbuf.append(params[l]); + i = j + 2; + } + } + if (messagePattern.indexOf("{}", i) != -1) { + log.error("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params); + } + sbuf.append(messagePattern.substring(i)); + return sbuf.toString(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/package-info.java new file mode 100644 index 0000000..f3f2574 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/package-info.java @@ -0,0 +1,6 @@ +/** + * 基础的通用类,和框架无关 + * + * 例如说,CommonResult 为通用返回 + */ +package cn.iocoder.yudao.framework.common; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java new file mode 100644 index 0000000..e29292d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.framework.common.pojo; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.Objects; + +/** + * 通用返回 + * + * @param 数据泛型 + */ +@Data +public class CommonResult implements Serializable { + + /** + * 错误码 + * + * @see ErrorCode#getCode() + */ + private Integer code; + /** + * 返回数据 + */ + private T data; + /** + * 错误提示,用户可阅读 + * + * @see ErrorCode#getMsg() () + */ + private String msg; + + /** + * 将传入的 result 对象,转换成另外一个泛型结果的对象 + * + * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 + * + * @param result 传入的 result 对象 + * @param 返回的泛型 + * @return 新的 CommonResult 对象 + */ + public static CommonResult error(CommonResult result) { + return error(result.getCode(), result.getMsg()); + } + + public static CommonResult error(Integer code, String message) { + Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!"); + CommonResult result = new CommonResult<>(); + result.code = code; + result.msg = message; + return result; + } + + public static CommonResult error(ErrorCode errorCode) { + return error(errorCode.getCode(), errorCode.getMsg()); + } + + public static CommonResult success(T data) { + CommonResult result = new CommonResult<>(); + result.code = GlobalErrorCodeConstants.SUCCESS.getCode(); + result.data = data; + result.msg = ""; + return result; + } + + public static boolean isSuccess(Integer code) { + return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode()); + } + + @JsonIgnore // 避免 jackson 序列化 + public boolean isSuccess() { + return isSuccess(code); + } + + @JsonIgnore // 避免 jackson 序列化 + public boolean isError() { + return !isSuccess(); + } + + // ========= 和 Exception 异常体系集成 ========= + + /** + * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常 + */ + public void checkError() throws ServiceException { + if (isSuccess()) { + return; + } + // 业务异常 + throw new ServiceException(code, msg); + } + + /** + * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常 + * 如果没有,则返回 {@link #data} 数据 + */ + @JsonIgnore // 避免 jackson 序列化 + public T getCheckedData() { + checkError(); + return data; + } + + public static CommonResult error(ServiceException serviceException) { + return error(serviceException.getCode(), serviceException.getMessage()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java new file mode 100644 index 0000000..97819f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.common.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.Max; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Schema(description="分页参数") +@Data +public class PageParam implements Serializable { + + private static final Integer PAGE_NO = 1; + private static final Integer PAGE_SIZE = 10; + + /** + * 每页条数 - 不分页 + * + * 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。 + */ + public static final Integer PAGE_SIZE_NONE = -1; + + @Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED,example = "1") + @NotNull(message = "页码不能为空") + @Min(value = 1, message = "页码最小值为 1") + private Integer pageNo = PAGE_NO; + + @Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "每页条数不能为空") + @Min(value = 1, message = "每页条数最小值为 1") + @Max(value = 100, message = "每页条数最大值为 100") + private Integer pageSize = PAGE_SIZE; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java new file mode 100644 index 0000000..ff9087a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.framework.common.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Schema(description = "分页结果") +@Data +public final class PageResult implements Serializable { + + @Schema(description = "数据", requiredMode = Schema.RequiredMode.REQUIRED) + private List list; + + @Schema(description = "总量", requiredMode = Schema.RequiredMode.REQUIRED) + private Long total; + + public PageResult() { + } + + public PageResult(List list, Long total) { + this.list = list; + this.total = total; + } + + public PageResult(Long total) { + this.list = new ArrayList<>(); + this.total = total; + } + + public static PageResult empty() { + return new PageResult<>(0L); + } + + public static PageResult empty(Long total) { + return new PageResult<>(total); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortablePageParam.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortablePageParam.java new file mode 100644 index 0000000..2365c41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortablePageParam.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.common.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "可排序的分页参数") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SortablePageParam extends PageParam { + + @Schema(description = "排序字段") + private List sortingFields; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortingField.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortingField.java new file mode 100644 index 0000000..07a68b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortingField.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.common.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 排序字段 DTO + * + * 类名加了 ing 的原因是,避免和 ES SortField 重名。 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SortingField implements Serializable { + + /** + * 顺序 - 升序 + */ + public static final String ORDER_ASC = "asc"; + /** + * 顺序 - 降序 + */ + public static final String ORDER_DESC = "desc"; + + /** + * 字段 + */ + private String field; + /** + * 顺序 + */ + private String order; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java new file mode 100644 index 0000000..12a6e17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.framework.common.util.cache; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +import java.time.Duration; +import java.util.concurrent.Executors; + +/** + * Cache 工具类 + * + * @author 芋道源码 + */ +public class CacheUtils { + + /** + * 构建异步刷新的 LoadingCache 对象 + * + * 注意:如果你的缓存和 ThreadLocal 有关系,要么自己处理 ThreadLocal 的传递,要么使用 {@link #buildCache(Duration, CacheLoader)} 方法 + * + * 或者简单理解: + * 1、和“人”相关的,使用 {@link #buildCache(Duration, CacheLoader)} 方法 + * 2、和“全局”、“系统”相关的,使用当前缓存方法 + * + * @param duration 过期时间 + * @param loader CacheLoader 对象 + * @return LoadingCache 对象 + */ + public static LoadingCache buildAsyncReloadingCache(Duration duration, CacheLoader loader) { + return CacheBuilder.newBuilder() + // 只阻塞当前数据加载线程,其他线程返回旧值 + .refreshAfterWrite(duration) + // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 + .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置 + } + + /** + * 构建同步刷新的 LoadingCache 对象 + * + * @param duration 过期时间 + * @param loader CacheLoader 对象 + * @return LoadingCache 对象 + */ + public static LoadingCache buildCache(Duration duration, CacheLoader loader) { + return CacheBuilder.newBuilder().refreshAfterWrite(duration).build(loader); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java new file mode 100644 index 0000000..4285b8f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.framework.common.util.collection; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.IterUtil; +import cn.hutool.core.util.ArrayUtil; + +import java.util.Collection; +import java.util.function.Consumer; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * Array 工具类 + * + * @author 芋道源码 + */ +public class ArrayUtils { + + /** + * 将 object 和 newElements 合并成一个数组 + * + * @param object 对象 + * @param newElements 数组 + * @param 泛型 + * @return 结果数组 + */ + @SafeVarargs + public static Consumer[] append(Consumer object, Consumer... newElements) { + if (object == null) { + return newElements; + } + Consumer[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length); + result[0] = object; + System.arraycopy(newElements, 0, result, 1, newElements.length); + return result; + } + + public static V[] toArray(Collection from, Function mapper) { + return toArray(convertList(from, mapper)); + } + + @SuppressWarnings("unchecked") + public static T[] toArray(Collection from) { + if (CollectionUtil.isEmpty(from)) { + return (T[]) (new Object[0]); + } + return ArrayUtil.toArray(from, (Class) IterUtil.getElementType(from.iterator())); + } + + public static T get(T[] array, int index) { + if (null == array || index >= array.length) { + return null; + } + return array[index]; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java new file mode 100644 index 0000000..91f5347 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java @@ -0,0 +1,322 @@ +package cn.iocoder.yudao.framework.common.util.collection; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; +import com.google.common.collect.ImmutableMap; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.Arrays.asList; + +/** + * Collection 工具类 + * + * @author 芋道源码 + */ +public class CollectionUtils { + + public static boolean containsAny(Object source, Object... targets) { + return asList(targets).contains(source); + } + + public static boolean isAnyEmpty(Collection... collections) { + return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty); + } + + public static boolean anyMatch(Collection from, Predicate predicate) { + return from.stream().anyMatch(predicate); + } + + public static List filterList(Collection from, Predicate predicate) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().filter(predicate).collect(Collectors.toList()); + } + + public static List distinct(Collection from, Function keyMapper) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return distinct(from, keyMapper, (t1, t2) -> t1); + } + + public static List distinct(Collection from, Function keyMapper, BinaryOperator cover) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return new ArrayList<>(convertMap(from, keyMapper, Function.identity(), cover).values()); + } + + public static List convertList(T[] from, Function func) { + if (ArrayUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return convertList(Arrays.asList(from), func); + } + + public static List convertList(Collection from, Function func) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public static List convertList(Collection from, Function func, Predicate filter) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public static List convertListByFlatMap(Collection from, + Function> func) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public static List convertListByFlatMap(Collection from, + Function mapper, + Function> func) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public static List mergeValuesFromMap(Map> map) { + return map.values() + .stream() + .flatMap(List::stream) + .collect(Collectors.toList()); + } + + public static Set convertSet(Collection from) { + return convertSet(from, v -> v); + } + + public static Set convertSet(Collection from, Function func) { + if (CollUtil.isEmpty(from)) { + return new HashSet<>(); + } + return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + public static Set convertSet(Collection from, Function func, Predicate filter) { + if (CollUtil.isEmpty(from)) { + return new HashSet<>(); + } + return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + public static Map convertMapByFilter(Collection from, Predicate filter, Function keyFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v)); + } + + public static Set convertSetByFlatMap(Collection from, + Function> func) { + if (CollUtil.isEmpty(from)) { + return new HashSet<>(); + } + return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + public static Set convertSetByFlatMap(Collection from, + Function mapper, + Function> func) { + if (CollUtil.isEmpty(from)) { + return new HashSet<>(); + } + return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + public static Map convertMap(Collection from, Function keyFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return convertMap(from, keyFunc, Function.identity()); + } + + public static Map convertMap(Collection from, Function keyFunc, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return supplier.get(); + } + return convertMap(from, keyFunc, Function.identity(), supplier); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, BinaryOperator mergeFunction) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return convertMap(from, keyFunc, valueFunc, mergeFunction, HashMap::new); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return supplier.get(); + } + return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1, supplier); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, BinaryOperator mergeFunction, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream().collect(Collectors.toMap(keyFunc, valueFunc, mergeFunction, supplier)); + } + + public static Map> convertMultiMap(Collection from, Function keyFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(t -> t, Collectors.toList()))); + } + + public static Map> convertMultiMap(Collection from, Function keyFunc, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream() + .collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toList()))); + } + + // 暂时没想好名字,先以 2 结尾噶 + public static Map> convertMultiMap2(Collection from, Function keyFunc, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet()))); + } + + public static Map convertImmutableMap(Collection from, Function keyFunc) { + if (CollUtil.isEmpty(from)) { + return Collections.emptyMap(); + } + ImmutableMap.Builder builder = ImmutableMap.builder(); + from.forEach(item -> builder.put(keyFunc.apply(item), item)); + return builder.build(); + } + + /** + * 对比老、新两个列表,找出新增、修改、删除的数据 + * + * @param oldList 老列表 + * @param newList 新列表 + * @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同 + * 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据 + * @return [新增列表、修改列表、删除列表] + */ + public static List> diffList(Collection oldList, Collection newList, + BiFunction sameFunc) { + List createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除 + List updateList = new ArrayList<>(); + List deleteList = new ArrayList<>(); + + // 通过以 oldList 为主遍历,找出 updateList 和 deleteList + for (T oldObj : oldList) { + // 1. 寻找是否有匹配的 + T foundObj = null; + for (Iterator iterator = createList.iterator(); iterator.hasNext(); ) { + T newObj = iterator.next(); + // 1.1 不匹配,则直接跳过 + if (!sameFunc.apply(oldObj, newObj)) { + continue; + } + // 1.2 匹配,则移除,并结束寻找 + iterator.remove(); + foundObj = newObj; + break; + } + // 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中 + if (foundObj != null) { + updateList.add(foundObj); + } else { + deleteList.add(oldObj); + } + } + return asList(createList, updateList, deleteList); + } + + public static boolean containsAny(Collection source, Collection candidates) { + return org.springframework.util.CollectionUtils.containsAny(source, candidates); + } + + public static T getFirst(List from) { + return !CollectionUtil.isEmpty(from) ? from.get(0) : null; + } + + public static T findFirst(Collection from, Predicate predicate) { + return findFirst(from, predicate, Function.identity()); + } + + public static U findFirst(Collection from, Predicate predicate, Function func) { + if (CollUtil.isEmpty(from)) { + return null; + } + return from.stream().filter(predicate).findFirst().map(func).orElse(null); + } + + public static > V getMaxValue(Collection from, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return null; + } + assert !from.isEmpty(); // 断言,避免告警 + T t = from.stream().max(Comparator.comparing(valueFunc)).get(); + return valueFunc.apply(t); + } + + public static > V getMinValue(List from, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return null; + } + assert from.size() > 0; // 断言,避免告警 + T t = from.stream().min(Comparator.comparing(valueFunc)).get(); + return valueFunc.apply(t); + } + + public static > V getSumValue(List from, Function valueFunc, + BinaryOperator accumulator) { + return getSumValue(from, valueFunc, accumulator, null); + } + + public static > V getSumValue(Collection from, Function valueFunc, + BinaryOperator accumulator, V defaultValue) { + if (CollUtil.isEmpty(from)) { + return defaultValue; + } + assert !from.isEmpty(); // 断言,避免告警 + return from.stream().map(valueFunc).filter(Objects::nonNull).reduce(accumulator).orElse(defaultValue); + } + + public static void addIfNotNull(Collection coll, T item) { + if (item == null) { + return; + } + coll.add(item); + } + + public static Collection singleton(T obj) { + return obj == null ? Collections.emptyList() : Collections.singleton(obj); + } + + public static List newArrayList(List> list) { + return list.stream().flatMap(Collection::stream).collect(Collectors.toList()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java new file mode 100644 index 0000000..a59b53f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.common.util.collection; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +/** + * Map 工具类 + * + * @author 芋道源码 + */ +public class MapUtils { + + /** + * 从哈希表表中,获得 keys 对应的所有 value 数组 + * + * @param multimap 哈希表 + * @param keys keys + * @return value 数组 + */ + public static List getList(Multimap multimap, Collection keys) { + List result = new ArrayList<>(); + keys.forEach(k -> { + Collection values = multimap.get(k); + if (CollectionUtil.isEmpty(values)) { + return; + } + result.addAll(values); + }); + return result; + } + + /** + * 从哈希表查找到 key 对应的 value,然后进一步处理 + * key 为 null 时, 不处理 + * 注意,如果查找到的 value 为 null 时,不进行处理 + * + * @param map 哈希表 + * @param key key + * @param consumer 进一步处理的逻辑 + */ + public static void findAndThen(Map map, K key, Consumer consumer) { + if (ObjUtil.isNull(key) || CollUtil.isEmpty(map)) { + return; + } + V value = map.get(key); + if (value == null) { + return; + } + consumer.accept(value); + } + + public static Map convertMap(List> keyValues) { + Map map = Maps.newLinkedHashMapWithExpectedSize(keyValues.size()); + keyValues.forEach(keyValue -> map.put(keyValue.getKey(), keyValue.getValue())); + return map; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/SetUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/SetUtils.java new file mode 100644 index 0000000..e8eba66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/SetUtils.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.common.util.collection; + +import cn.hutool.core.collection.CollUtil; + +import java.util.Set; + +/** + * Set 工具类 + * + * @author 芋道源码 + */ +public class SetUtils { + + @SafeVarargs + public static Set asSet(T... objs) { + return CollUtil.newHashSet(objs); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java new file mode 100644 index 0000000..b51a838 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.framework.common.util.date; + +import cn.hutool.core.date.LocalDateTimeUtil; + +import java.time.*; +import java.util.Calendar; +import java.util.Date; + +/** + * 时间工具类 + * + * @author 芋道源码 + */ +public class DateUtils { + + /** + * 时区 - 默认 + */ + public static final String TIME_ZONE_DEFAULT = "GMT+8"; + + /** + * 秒转换成毫秒 + */ + public static final long SECOND_MILLIS = 1000; + + public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd"; + + public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; + + /** + * 将 LocalDateTime 转换成 Date + * + * @param date LocalDateTime + * @return LocalDateTime + */ + public static Date of(LocalDateTime date) { + if (date == null) { + return null; + } + // 将此日期时间与时区相结合以创建 ZonedDateTime + ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault()); + // 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳 + Instant instant = zonedDateTime.toInstant(); + // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间 + return Date.from(instant); + } + + /** + * 将 Date 转换成 LocalDateTime + * + * @param date Date + * @return LocalDateTime + */ + public static LocalDateTime of(Date date) { + if (date == null) { + return null; + } + // 转为时间戳 + Instant instant = date.toInstant(); + // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间 + return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + } + + public static Date addTime(Duration duration) { + return new Date(System.currentTimeMillis() + duration.toMillis()); + } + + public static boolean isExpired(LocalDateTime time) { + LocalDateTime now = LocalDateTime.now(); + return now.isAfter(time); + } + + /** + * 创建指定时间 + * + * @param year 年 + * @param mouth 月 + * @param day 日 + * @return 指定时间 + */ + public static Date buildTime(int year, int mouth, int day) { + return buildTime(year, mouth, day, 0, 0, 0); + } + + /** + * 创建指定时间 + * + * @param year 年 + * @param mouth 月 + * @param day 日 + * @param hour 小时 + * @param minute 分钟 + * @param second 秒 + * @return 指定时间 + */ + public static Date buildTime(int year, int mouth, int day, + int hour, int minute, int second) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, mouth - 1); + calendar.set(Calendar.DAY_OF_MONTH, day); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + calendar.set(Calendar.MILLISECOND, 0); // 一般情况下,都是 0 毫秒 + return calendar.getTime(); + } + + public static Date max(Date a, Date b) { + if (a == null) { + return b; + } + if (b == null) { + return a; + } + return a.compareTo(b) > 0 ? a : b; + } + + public static LocalDateTime max(LocalDateTime a, LocalDateTime b) { + if (a == null) { + return b; + } + if (b == null) { + return a; + } + return a.isAfter(b) ? a : b; + } + + /** + * 是否今天 + * + * @param date 日期 + * @return 是否 + */ + public static boolean isToday(LocalDateTime date) { + return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now()); + } + + /** + * 是否昨天 + * + * @param date 日期 + * @return 是否 + */ + public static boolean isYesterday(LocalDateTime date) { + return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now().minusDays(1)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java new file mode 100644 index 0000000..c3b3b53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -0,0 +1,309 @@ +package cn.iocoder.yudao.framework.common.util.date; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; + +import java.time.*; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAdjusters; +import java.util.ArrayList; +import java.util.List; + +/** + * 时间工具类,用于 {@link java.time.LocalDateTime} + * + * @author 芋道源码 + */ +public class LocalDateTimeUtils { + + /** + * 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值 + */ + public static LocalDateTime EMPTY = buildTime(1970, 1, 1); + + /** + * 解析时间 + * + * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功 + * + * @param time 时间 + * @return 时间字符串 + */ + public static LocalDateTime parse(String time) { + try { + return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN); + } catch (DateTimeParseException e) { + return LocalDateTimeUtil.parse(time); + } + } + + public static LocalDateTime addTime(Duration duration) { + return LocalDateTime.now().plus(duration); + } + + public static LocalDateTime minusTime(Duration duration) { + return LocalDateTime.now().minus(duration); + } + + public static boolean beforeNow(LocalDateTime date) { + return date.isBefore(LocalDateTime.now()); + } + + public static boolean afterNow(LocalDateTime date) { + return date.isAfter(LocalDateTime.now()); + } + + /** + * 创建指定时间 + * + * @param year 年 + * @param mouth 月 + * @param day 日 + * @return 指定时间 + */ + public static LocalDateTime buildTime(int year, int mouth, int day) { + return LocalDateTime.of(year, mouth, day, 0, 0, 0); + } + + public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1, + int year2, int mouth2, int day2) { + return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)}; + } + + /** + * 判指定断时间,是否在该时间范围内 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param time 指定时间 + * @return 是否 + */ + public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) { + if (startTime == null || endTime == null || time == null) { + return false; + } + return LocalDateTimeUtil.isIn(parse(time), startTime, endTime); + } + + /** + * 判断当前时间是否在该时间范围内 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 是否 + */ + public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) { + if (startTime == null || endTime == null) { + return false; + } + return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime); + } + + /** + * 判断当前时间是否在该时间范围内 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 是否 + */ + public static boolean isBetween(String startTime, String endTime) { + if (startTime == null || endTime == null) { + return false; + } + LocalDate nowDate = LocalDate.now(); + return LocalDateTimeUtil.isIn(LocalDateTime.now(), + LocalDateTime.of(nowDate, LocalTime.parse(startTime)), + LocalDateTime.of(nowDate, LocalTime.parse(endTime))); + } + + /** + * 判断时间段是否重叠 + * + * @param startTime1 开始 time1 + * @param endTime1 结束 time1 + * @param startTime2 开始 time2 + * @param endTime2 结束 time2 + * @return 重叠:true 不重叠:false + */ + public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) { + LocalDate nowDate = LocalDate.now(); + return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1), + LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2)); + } + + /** + * 获取指定日期所在的月份的开始时间 + * 例如:2023-09-30 00:00:00,000 + * + * @param date 日期 + * @return 月份的开始时间 + */ + public static LocalDateTime beginOfMonth(LocalDateTime date) { + return date.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); + } + + /** + * 获取指定日期所在的月份的最后时间 + * 例如:2023-09-30 23:59:59,999 + * + * @param date 日期 + * @return 月份的结束时间 + */ + public static LocalDateTime endOfMonth(LocalDateTime date) { + return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); + } + + /** + * 获得指定日期所在季度 + * + * @param date 日期 + * @return 所在季度 + */ + public static int getQuarterOfYear(LocalDateTime date) { + return (date.getMonthValue() - 1) / 3 + 1; + } + + /** + * 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负 + * + * @param dateTime 日期 + * @return 相差天数 + */ + public static Long between(LocalDateTime dateTime) { + return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS); + } + + /** + * 获取今天的开始时间 + * + * @return 今天 + */ + public static LocalDateTime getToday() { + return LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + } + + /** + * 获取昨天的开始时间 + * + * @return 昨天 + */ + public static LocalDateTime getYesterday() { + return LocalDateTimeUtil.beginOfDay(LocalDateTime.now().minusDays(1)); + } + + /** + * 获取本月的开始时间 + * + * @return 本月 + */ + public static LocalDateTime getMonth() { + return beginOfMonth(LocalDateTime.now()); + } + + /** + * 获取本年的开始时间 + * + * @return 本年 + */ + public static LocalDateTime getYear() { + return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN); + } + + public static List getDateRangeList(LocalDateTime startTime, + LocalDateTime endTime, + Integer interval) { + // 1.1 找到枚举 + DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval); + Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval); + // 1.2 将时间对齐 + startTime = LocalDateTimeUtil.beginOfDay(startTime); + endTime = LocalDateTimeUtil.endOfDay(endTime); + + // 2. 循环,生成时间范围 + List timeRanges = new ArrayList<>(); + switch (intervalEnum) { + case DAY: + while (startTime.isBefore(endTime)) { + timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)}); + startTime = startTime.plusDays(1); + } + break; + case WEEK: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfWeek}); + startTime = endOfWeek.plusNanos(1); + } + break; + case MONTH: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfMonth}); + startTime = endOfMonth.plusNanos(1); + } + break; + case QUARTER: + while (startTime.isBefore(endTime)) { + int quarterOfYear = getQuarterOfYear(startTime); + LocalDateTime quarterEnd = quarterOfYear == 4 + ? startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1) + : startTime.withMonth(quarterOfYear * 3 + 1).withDayOfMonth(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, quarterEnd}); + startTime = quarterEnd.plusNanos(1); + } + break; + case YEAR: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfYear}); + startTime = endOfYear.plusNanos(1); + } + break; + default: + throw new IllegalArgumentException("Invalid interval: " + interval); + } + // 3. 兜底,最后一个时间,需要保持在 endTime 之前 + LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges); + if (lastTimeRange != null) { + lastTimeRange[1] = endTime; + } + return timeRanges; + } + + /** + * 格式化时间范围 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param interval 时间间隔 + * @return 时间范围 + */ + public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) { + // 1. 找到枚举 + DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval); + Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval); + + // 2. 循环,生成时间范围 + switch (intervalEnum) { + case DAY: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN); + case WEEK: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN) + + StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime)); + case MONTH: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN); + case QUARTER: + return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime)); + case YEAR: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN); + default: + throw new IllegalArgumentException("Invalid interval: " + interval); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java new file mode 100644 index 0000000..d36b2c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.framework.common.util.http; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.map.TableMap; +import cn.hutool.core.net.url.UrlBuilder; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.servlet.http.HttpServletRequest; +import java.net.URI; +import java.nio.charset.Charset; +import java.util.Map; + +/** + * HTTP 工具类 + * + * @author 芋道源码 + */ +public class HttpUtils { + + @SuppressWarnings("unchecked") + public static String replaceUrlQuery(String url, String key, String value) { + UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); + // 先移除 + TableMap query = (TableMap) + ReflectUtil.getFieldValue(builder.getQuery(), "query"); + query.remove(key); + // 后添加 + builder.addQuery(key, value); + return builder.build(); + } + + private String append(String base, Map query, boolean fragment) { + return append(base, query, null, fragment); + } + + /** + * 拼接 URL + * + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 append 方法 + * + * @param base 基础 URL + * @param query 查询参数 + * @param keys query 的 key,对应的原本的 key 的映射。例如说 query 里有个 key 是 xx,实际它的 key 是 extra_xx,则通过 keys 里添加这个映射 + * @param fragment URL 的 fragment,即拼接到 # 中 + * @return 拼接后的 URL + */ + public static String append(String base, Map query, Map keys, boolean fragment) { + UriComponentsBuilder template = UriComponentsBuilder.newInstance(); + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(base); + URI redirectUri; + try { + // assume it's encoded to start with (if it came in over the wire) + redirectUri = builder.build(true).toUri(); + } catch (Exception e) { + // ... but allow client registrations to contain hard-coded non-encoded values + redirectUri = builder.build().toUri(); + builder = UriComponentsBuilder.fromUri(redirectUri); + } + template.scheme(redirectUri.getScheme()).port(redirectUri.getPort()).host(redirectUri.getHost()) + .userInfo(redirectUri.getUserInfo()).path(redirectUri.getPath()); + + if (fragment) { + StringBuilder values = new StringBuilder(); + if (redirectUri.getFragment() != null) { + String append = redirectUri.getFragment(); + values.append(append); + } + for (String key : query.keySet()) { + if (values.length() > 0) { + values.append("&"); + } + String name = key; + if (keys != null && keys.containsKey(key)) { + name = keys.get(key); + } + values.append(name).append("={").append(key).append("}"); + } + if (values.length() > 0) { + template.fragment(values.toString()); + } + UriComponents encoded = template.build().expand(query).encode(); + builder.fragment(encoded.getFragment()); + } else { + for (String key : query.keySet()) { + String name = key; + if (keys != null && keys.containsKey(key)) { + name = keys.get(key); + } + template.queryParam(name, "{" + key + "}"); + } + template.fragment(redirectUri.getFragment()); + UriComponents encoded = template.build().expand(query).encode(); + builder.query(encoded.getQuery()); + } + return builder.build().toUriString(); + } + + public static String[] obtainBasicAuthorization(HttpServletRequest request) { + String clientId; + String clientSecret; + // 先从 Header 中获取 + String authorization = request.getHeader("Authorization"); + authorization = StrUtil.subAfter(authorization, "Basic ", true); + if (StringUtils.hasText(authorization)) { + authorization = Base64.decodeStr(authorization); + clientId = StrUtil.subBefore(authorization, ":", false); + clientSecret = StrUtil.subAfter(authorization, ":", false); + // 再从 Param 中获取 + } else { + clientId = request.getParameter("client_id"); + clientSecret = request.getParameter("client_secret"); + } + + // 如果两者非空,则返回 + if (StrUtil.isNotEmpty(clientId) && StrUtil.isNotEmpty(clientSecret)) { + return new String[]{clientId, clientSecret}; + } + return null; + } + + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java new file mode 100644 index 0000000..2f870d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.framework.common.util.io; + +import cn.hutool.core.io.FileTypeUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import lombok.SneakyThrows; + +import java.io.ByteArrayInputStream; +import java.io.File; + +/** + * 文件工具类 + * + * @author 芋道源码 + */ +public class FileUtils { + + /** + * 创建临时文件 + * 该文件会在 JVM 退出时,进行删除 + * + * @param data 文件内容 + * @return 文件 + */ + @SneakyThrows + public static File createTempFile(String data) { + File file = createTempFile(); + // 写入内容 + FileUtil.writeUtf8String(data, file); + return file; + } + + /** + * 创建临时文件 + * 该文件会在 JVM 退出时,进行删除 + * + * @param data 文件内容 + * @return 文件 + */ + @SneakyThrows + public static File createTempFile(byte[] data) { + File file = createTempFile(); + // 写入内容 + FileUtil.writeBytes(data, file); + return file; + } + + /** + * 创建临时文件,无内容 + * 该文件会在 JVM 退出时,进行删除 + * + * @return 文件 + */ + @SneakyThrows + public static File createTempFile() { + // 创建文件,通过 UUID 保证唯一 + File file = File.createTempFile(IdUtil.simpleUUID(), null); + // 标记 JVM 退出时,自动删除 + file.deleteOnExit(); + return file; + } + + /** + * 生成文件路径 + * + * @param content 文件内容 + * @param originalName 原始文件名 + * @return path,唯一不可重复 + */ + public static String generatePath(byte[] content, String originalName) { + String sha256Hex = DigestUtil.sha256Hex(content); + // 情况一:如果存在 name,则优先使用 name 的后缀 + if (StrUtil.isNotBlank(originalName)) { + String extName = FileNameUtil.extName(originalName); + return StrUtil.isBlank(extName) ? sha256Hex : sha256Hex + "." + extName; + } + // 情况二:基于 content 计算 + return sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/IoUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/IoUtils.java new file mode 100644 index 0000000..4a19f47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/IoUtils.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.common.util.io; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; + +import java.io.InputStream; + +/** + * IO 工具类,用于 {@link cn.hutool.core.io.IoUtil} 缺失的方法 + * + * @author 芋道源码 + */ +public class IoUtils { + + /** + * 从流中读取 UTF8 编码的内容 + * + * @param in 输入流 + * @param isClose 是否关闭 + * @return 内容 + * @throws IORuntimeException IO 异常 + */ + public static String readUtf8(InputStream in, boolean isClose) throws IORuntimeException { + return StrUtil.utf8Str(IoUtil.read(in, isClose)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java new file mode 100644 index 0000000..2cbe93c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java @@ -0,0 +1,202 @@ +package cn.iocoder.yudao.framework.common.util.json; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@Slf4j +public class JsonUtils { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + static { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值 + objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 + } + + /** + * 初始化 objectMapper 属性 + *

+ * 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean + * + * @param objectMapper ObjectMapper 对象 + */ + public static void init(ObjectMapper objectMapper) { + JsonUtils.objectMapper = objectMapper; + } + + @SneakyThrows + public static String toJsonString(Object object) { + return objectMapper.writeValueAsString(object); + } + + @SneakyThrows + public static byte[] toJsonByte(Object object) { + return objectMapper.writeValueAsBytes(object); + } + + @SneakyThrows + public static String toJsonPrettyString(Object object) { + return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); + } + + public static T parseObject(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + return objectMapper.readValue(text, clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, String path, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + JsonNode treeNode = objectMapper.readTree(text); + JsonNode pathNode = treeNode.path(path); + return objectMapper.readValue(pathNode.toString(), clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Type type) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + /** + * 将字符串解析成指定类型的对象 + * 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下, + * 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。 + * + * @param text 字符串 + * @param clazz 类型 + * @return 对象 + */ + public static T parseObject2(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + return JSONUtil.toBean(text, clazz); + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return objectMapper.readValue(bytes, clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", bytes, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + /** + * 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null + * + * @param text 字符串 + * @param typeReference 类型引用 + * @return 指定类型的对象 + */ + public static T parseObjectQuietly(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (IOException e) { + return null; + } + } + + public static List parseArray(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, String path, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + JsonNode treeNode = objectMapper.readTree(text); + JsonNode pathNode = treeNode.path(path); + return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static JsonNode parseTree(String text) { + try { + return objectMapper.readTree(text); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static JsonNode parseTree(byte[] text) { + try { + return objectMapper.readTree(text); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static boolean isJson(String text) { + return JSONUtil.isTypeJSON(text); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/monitor/TracerUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/monitor/TracerUtils.java new file mode 100644 index 0000000..81092b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/monitor/TracerUtils.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.framework.common.util.monitor; + +import org.apache.skywalking.apm.toolkit.trace.TraceContext; + +/** + * 链路追踪工具类 + * + * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下 + * + * @author 芋道源码 + */ +public class TracerUtils { + + /** + * 私有化构造方法 + */ + private TracerUtils() { + } + + /** + * 获得链路追踪编号,直接返回 SkyWalking 的 TraceId。 + * 如果不存在的话为空字符串!!! + * + * @return 链路追踪编号 + */ + public static String getTraceId() { + return TraceContext.traceId(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java new file mode 100644 index 0000000..90888d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.framework.common.util.number; + +import cn.hutool.core.math.Money; +import cn.hutool.core.util.NumberUtil; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 金额工具类 + * + * @author 芋道源码 + */ +public class MoneyUtils { + + /** + * 金额的小数位数 + */ + private static final int PRICE_SCALE = 2; + + /** + * 百分比对应的 BigDecimal 对象 + */ + public static final BigDecimal PERCENT_100 = BigDecimal.valueOf(100); + + /** + * 计算百分比金额,四舍五入 + * + * @param price 金额 + * @param rate 百分比,例如说 56.77% 则传入 56.77 + * @return 百分比金额 + */ + public static Integer calculateRatePrice(Integer price, Double rate) { + return calculateRatePrice(price, rate, 0, RoundingMode.HALF_UP).intValue(); + } + + /** + * 计算百分比金额,向下传入 + * + * @param price 金额 + * @param rate 百分比,例如说 56.77% 则传入 56.77 + * @return 百分比金额 + */ + public static Integer calculateRatePriceFloor(Integer price, Double rate) { + return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue(); + } + + /** + * 计算百分比金额 + * + * @param price 金额(单位分) + * @param count 数量 + * @param percent 折扣(单位分),列如 60.2%,则传入 6020 + * @return 商品总价 + */ + public static Integer calculator(Integer price, Integer count, Integer percent) { + price = price * count; + if (percent == null) { + return price; + } + return MoneyUtils.calculateRatePriceFloor(price, (double) (percent / 100)); + } + + /** + * 计算百分比金额 + * + * @param price 金额 + * @param rate 百分比,例如说 56.77% 则传入 56.77 + * @param scale 保留小数位数 + * @param roundingMode 舍入模式 + */ + public static BigDecimal calculateRatePrice(Number price, Number rate, int scale, RoundingMode roundingMode) { + return NumberUtil.toBigDecimal(price).multiply(NumberUtil.toBigDecimal(rate)) // 乘以 + .divide(BigDecimal.valueOf(100), scale, roundingMode); // 除以 100 + } + + /** + * 分转元 + * + * @param fen 分 + * @return 元 + */ + public static BigDecimal fenToYuan(int fen) { + return new Money(0, fen).getAmount(); + } + + /** + * 分转元(字符串) + * + * 例如说 fen 为 1 时,则结果为 0.01 + * + * @param fen 分 + * @return 元 + */ + public static String fenToYuanStr(int fen) { + return new Money(0, fen).toString(); + } + + /** + * 金额相乘,默认进行四舍五入 + * + * 位数:{@link #PRICE_SCALE} + * + * @param price 金额 + * @param count 数量 + * @return 金额相乘结果 + */ + public static BigDecimal priceMultiply(BigDecimal price, BigDecimal count) { + if (price == null || count == null) { + return null; + } + return price.multiply(count).setScale(PRICE_SCALE, RoundingMode.HALF_UP); + } + + /** + * 金额相乘(百分比),默认进行四舍五入 + * + * 位数:{@link #PRICE_SCALE} + * + * @param price 金额 + * @param percent 百分比 + * @return 金额相乘结果 + */ + public static BigDecimal priceMultiplyPercent(BigDecimal price, BigDecimal percent) { + if (price == null || percent == null) { + return null; + } + return price.multiply(percent).divide(PERCENT_100, PRICE_SCALE, RoundingMode.HALF_UP); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java new file mode 100644 index 0000000..c928e2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.common.util.number; + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; + +import java.math.BigDecimal; + +/** + * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能 + * + * @author 芋道源码 + */ +public class NumberUtils { + + public static Long parseLong(String str) { + return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null; + } + + public static Integer parseInt(String str) { + return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null; + } + + /** + * 通过经纬度获取地球上两点之间的距离 + * + * 参考 <DistanceUtil> 实现,目前它已经被 hutool 删除 + * + * @param lat1 经度1 + * @param lng1 纬度1 + * @param lat2 经度2 + * @param lng2 纬度2 + * @return 距离,单位:千米 + */ + public static double getDistance(double lat1, double lng1, double lat2, double lng2) { + double radLat1 = lat1 * Math.PI / 180.0; + double radLat2 = lat2 * Math.PI / 180.0; + double a = radLat1 - radLat2; + double b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0; + double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + + Math.cos(radLat1) * Math.cos(radLat2) + * Math.pow(Math.sin(b / 2), 2))); + distance = distance * 6378.137; + distance = Math.round(distance * 10000d) / 10000d; + return distance; + } + + /** + * 提供精确的乘法运算 + * + * 和 hutool {@link NumberUtil#mul(BigDecimal...)} 的差别是,如果存在 null,则返回 null + * + * @param values 多个被乘值 + * @return 积 + */ + public static BigDecimal mul(BigDecimal... values) { + for (BigDecimal value : values) { + if (value == null) { + return null; + } + } + return NumberUtil.mul(values); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java new file mode 100644 index 0000000..720b565 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.common.util.object; + +import cn.hutool.core.bean.BeanUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; + +import java.util.List; +import java.util.function.Consumer; + +/** + * Bean 工具类 + * + * 1. 默认使用 {@link cn.hutool.core.bean.BeanUtil} 作为实现类,虽然不同 bean 工具的性能有差别,但是对绝大多数同学的项目,不用在意这点性能 + * 2. 针对复杂的对象转换,可以搜参考 AuthConvert 实现,通过 mapstruct + default 配合实现 + * + * @author 芋道源码 + */ +public class BeanUtils { + + public static T toBean(Object source, Class targetClass) { + return BeanUtil.toBean(source, targetClass); + } + + public static T toBean(Object source, Class targetClass, Consumer peek) { + T target = toBean(source, targetClass); + if (target != null) { + peek.accept(target); + } + return target; + } + + public static List toBean(List source, Class targetType) { + if (source == null) { + return null; + } + return CollectionUtils.convertList(source, s -> toBean(s, targetType)); + } + + public static List toBean(List source, Class targetType, Consumer peek) { + List list = toBean(source, targetType); + if (list != null) { + list.forEach(peek); + } + return list; + } + + public static PageResult toBean(PageResult source, Class targetType) { + return toBean(source, targetType, null); + } + + public static PageResult toBean(PageResult source, Class targetType, Consumer peek) { + if (source == null) { + return null; + } + List list = toBean(source.getList(), targetType); + if (peek != null) { + list.forEach(peek); + } + return new PageResult<>(list, source.getTotal()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java new file mode 100644 index 0000000..c08316d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.common.util.object; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.function.Consumer; + +/** + * Object 工具类 + * + * @author 芋道源码 + */ +public class ObjectUtils { + + /** + * 复制对象,并忽略 Id 编号 + * + * @param object 被复制对象 + * @param consumer 消费者,可以二次编辑被复制对象 + * @return 复制后的对象 + */ + public static T cloneIgnoreId(T object, Consumer consumer) { + T result = ObjectUtil.clone(object); + // 忽略 id 编号 + Field field = ReflectUtil.getField(object.getClass(), "id"); + if (field != null) { + ReflectUtil.setFieldValue(result, field, null); + } + // 二次编辑 + if (result != null) { + consumer.accept(result); + } + return result; + } + + public static > T max(T obj1, T obj2) { + if (obj1 == null) { + return obj2; + } + if (obj2 == null) { + return obj1; + } + return obj1.compareTo(obj2) > 0 ? obj1 : obj2; + } + + @SafeVarargs + public static T defaultIfNull(T... array) { + for (T item : array) { + if (item != null) { + return item; + } + } + return null; + } + + @SafeVarargs + public static boolean equalsAny(T obj, T... array) { + return Arrays.asList(array).contains(obj); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/PageUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/PageUtils.java new file mode 100644 index 0000000..cf077db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/PageUtils.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.framework.common.util.object; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.func.Func1; +import cn.hutool.core.lang.func.LambdaUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.framework.common.pojo.SortingField; +import org.springframework.util.Assert; + +import static java.util.Collections.singletonList; + +/** + * {@link cn.iocoder.yudao.framework.common.pojo.PageParam} 工具类 + * + * @author 芋道源码 + */ +public class PageUtils { + + private static final Object[] ORDER_TYPES = new String[]{SortingField.ORDER_ASC, SortingField.ORDER_DESC}; + + public static int getStart(PageParam pageParam) { + return (pageParam.getPageNo() - 1) * pageParam.getPageSize(); + } + + /** + * 构建排序字段(默认倒序) + * + * @param func 排序字段的 Lambda 表达式 + * @param 排序字段所属的类型 + * @return 排序字段 + */ + public static SortingField buildSortingField(Func1 func) { + return buildSortingField(func, SortingField.ORDER_DESC); + } + + /** + * 构建排序字段 + * + * @param func 排序字段的 Lambda 表达式 + * @param order 排序类型 {@link SortingField#ORDER_ASC} {@link SortingField#ORDER_DESC} + * @param 排序字段所属的类型 + * @return 排序字段 + */ + public static SortingField buildSortingField(Func1 func, String order) { + Assert.isTrue(ArrayUtil.contains(ORDER_TYPES, order), String.format("字段的排序类型只能是 %s/%s", ORDER_TYPES)); + + String fieldName = LambdaUtil.getFieldName(func); + return new SortingField(fieldName, order); + } + + /** + * 构建默认的排序字段 + * 如果排序字段为空,则设置排序字段;否则忽略 + * + * @param sortablePageParam 排序分页查询参数 + * @param func 排序字段的 Lambda 表达式 + * @param 排序字段所属的类型 + */ + public static void buildDefaultSortingField(SortablePageParam sortablePageParam, Func1 func) { + if (sortablePageParam != null && CollUtil.isEmpty(sortablePageParam.getSortingFields())) { + sortablePageParam.setSortingFields(singletonList(buildSortingField(func))); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/package-info.java new file mode 100644 index 0000000..cd8ae6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/package-info.java @@ -0,0 +1,7 @@ +/** + * 对于工具类的选择,优先查找 Hutool 中有没对应的方法 + * 如果没有,则自己封装对应的工具类,以 Utils 结尾,用于区分 + * + * ps:如果担心 Hutool 存在坑的问题,可以阅读 Hutool 的实现源码,以确保可靠性。并且,可以补充相关的单元测试。 + */ +package cn.iocoder.yudao.framework.common.util; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java new file mode 100644 index 0000000..8edbb50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.framework.common.util.servlet; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import org.springframework.http.MediaType; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.Map; + +/** + * 客户端工具类 + * + * @author 芋道源码 + */ +public class ServletUtils { + + /** + * 返回 JSON 字符串 + * + * @param response 响应 + * @param object 对象,会序列化成 JSON 字符串 + */ + @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码 + public static void writeJSON(HttpServletResponse response, Object object) { + String content = JsonUtils.toJsonString(object); + ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE); + } + + /** + * 返回附件 + * + * @param response 响应 + * @param filename 文件名 + * @param content 附件内容 + */ + public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { + // 设置 header 和 contentType + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + // 输出附件 + IoUtil.write(response.getOutputStream(), false, content); + } + + /** + * @param request 请求 + * @return ua + */ + public static String getUserAgent(HttpServletRequest request) { + String ua = request.getHeader("User-Agent"); + return ua != null ? ua : ""; + } + + /** + * 获得请求 + * + * @return HttpServletRequest + */ + public static HttpServletRequest getRequest() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (!(requestAttributes instanceof ServletRequestAttributes)) { + return null; + } + return ((ServletRequestAttributes) requestAttributes).getRequest(); + } + + public static String getUserAgent() { + HttpServletRequest request = getRequest(); + if (request == null) { + return null; + } + return getUserAgent(request); + } + + public static String getClientIP() { + HttpServletRequest request = getRequest(); + if (request == null) { + return null; + } + return ServletUtil.getClientIP(request); + } + + public static boolean isJsonRequest(ServletRequest request) { + return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE); + } + + public static String getBody(HttpServletRequest request) { + // 只有在 json 请求在读取,因为只有 CacheRequestBodyFilter 才会进行缓存,支持重复读取 + if (isJsonRequest(request)) { + return ServletUtil.getBody(request); + } + return null; + } + + public static byte[] getBodyBytes(HttpServletRequest request) { + // 只有在 json 请求在读取,因为只有 CacheRequestBodyFilter 才会进行缓存,支持重复读取 + if (isJsonRequest(request)) { + return ServletUtil.getBodyBytes(request); + } + return null; + } + + public static String getClientIP(HttpServletRequest request) { + return ServletUtil.getClientIP(request); + } + + public static Map getParamMap(HttpServletRequest request) { + return ServletUtil.getParamMap(request); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java new file mode 100644 index 0000000..9a7f881 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.framework.common.util.spring; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Spring EL 表达式的工具类 + * + * @author mashu + */ +public class SpringExpressionUtils { + + /** + * Spring EL 表达式解析器 + */ + private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); + /** + * 参数名发现器 + */ + private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); + + private SpringExpressionUtils() { + } + + /** + * 从切面中,单个解析 EL 表达式的结果 + * + * @param joinPoint 切面点 + * @param expressionString EL 表达式数组 + * @return 执行界面 + */ + public static Object parseExpression(JoinPoint joinPoint, String expressionString) { + Map result = parseExpressions(joinPoint, Collections.singletonList(expressionString)); + return result.get(expressionString); + } + + /** + * 从切面中,批量解析 EL 表达式的结果 + * + * @param joinPoint 切面点 + * @param expressionStrings EL 表达式数组 + * @return 结果,key 为表达式,value 为对应值 + */ + public static Map parseExpressions(JoinPoint joinPoint, List expressionStrings) { + // 如果为空,则不进行解析 + if (CollUtil.isEmpty(expressionStrings)) { + return MapUtil.newHashMap(); + } + + // 第一步,构建解析的上下文 EvaluationContext + // 通过 joinPoint 获取被注解方法 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + // 使用 spring 的 ParameterNameDiscoverer 获取方法形参名数组 + String[] paramNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method); + // Spring 的表达式上下文对象 + EvaluationContext context = new StandardEvaluationContext(); + // 给上下文赋值 + if (ArrayUtil.isNotEmpty(paramNames)) { + Object[] args = joinPoint.getArgs(); + for (int i = 0; i < paramNames.length; i++) { + context.setVariable(paramNames[i], args[i]); + } + } + + // 第二步,逐个参数解析 + Map result = MapUtil.newHashMap(expressionStrings.size(), true); + expressionStrings.forEach(key -> { + Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context); + result.put(key, value); + }); + return result; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringUtils.java new file mode 100644 index 0000000..a501a71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringUtils.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.framework.common.util.spring; + +import cn.hutool.extra.spring.SpringUtil; + +import java.util.Objects; + +/** + * Spring 工具类 + * + * @author 芋道源码 + */ +public class SpringUtils extends SpringUtil { + + /** + * 是否为生产环境 + * + * @return 是否生产环境 + */ + public static boolean isProd() { + String activeProfile = getActiveProfile(); + return Objects.equals("prod", activeProfile); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java new file mode 100644 index 0000000..d236d18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.framework.common.util.string; + +import cn.hutool.core.text.StrPool; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 字符串工具类 + * + * @author 芋道源码 + */ +public class StrUtils { + + public static String maxLength(CharSequence str, int maxLength) { + return StrUtil.maxLength(str, maxLength - 3); // -3 的原因,是该方法会补充 ... 恰好 + } + + /** + * 给定字符串是否以任何一个字符串开始 + * 给定字符串和数组为空都返回 false + * + * @param str 给定字符串 + * @param prefixes 需要检测的开始字符串 + * @since 3.0.6 + */ + public static boolean startWithAny(String str, Collection prefixes) { + if (StrUtil.isEmpty(str) || ArrayUtil.isEmpty(prefixes)) { + return false; + } + + for (CharSequence suffix : prefixes) { + if (StrUtil.startWith(str, suffix, false)) { + return true; + } + } + return false; + } + + public static List splitToLong(String value, CharSequence separator) { + long[] longs = StrUtil.splitToLong(value, separator); + return Arrays.stream(longs).boxed().collect(Collectors.toList()); + } + + public static Set splitToLongSet(String value) { + return splitToLongSet(value, StrPool.COMMA); + } + + public static Set splitToLongSet(String value, CharSequence separator) { + long[] longs = StrUtil.splitToLong(value, separator); + return Arrays.stream(longs).boxed().collect(Collectors.toSet()); + } + + public static List splitToInteger(String value, CharSequence separator) { + int[] integers = StrUtil.splitToInt(value, separator); + return Arrays.stream(integers).boxed().collect(Collectors.toList()); + } + + /** + * 移除字符串中,包含指定字符串的行 + * + * @param content 字符串 + * @param sequence 包含的字符串 + * @return 移除后的字符串 + */ + public static String removeLineContains(String content, String sequence) { + if (StrUtil.isEmpty(content) || StrUtil.isEmpty(sequence)) { + return content; + } + return Arrays.stream(content.split("\n")) + .filter(line -> !line.contains(sequence)) + .collect(Collectors.joining("\n")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java new file mode 100644 index 0000000..436a9e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.framework.common.util.validation; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import org.springframework.util.StringUtils; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * 校验工具类 + * + * @author 芋道源码 + */ +public class ValidationUtils { + + private static final Pattern PATTERN_MOBILE = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[0,1,4-9])|(?:5[0-3,5-9])|(?:6[2,5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[0-3,5-9]))\\d{8}$"); + + private static final Pattern PATTERN_URL = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"); + + private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*"); + + public static boolean isMobile(String mobile) { + return StringUtils.hasText(mobile) + && PATTERN_MOBILE.matcher(mobile).matches(); + } + + public static boolean isURL(String url) { + return StringUtils.hasText(url) + && PATTERN_URL.matcher(url).matches(); + } + + public static boolean isXmlNCName(String str) { + return StringUtils.hasText(str) + && PATTERN_XML_NCNAME.matcher(str).matches(); + } + + public static void validate(Object object, Class... groups) { + Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Assert.notNull(validator); + validate(validator, object, groups); + } + + public static void validate(Validator validator, Object object, Class... groups) { + Set> constraintViolations = validator.validate(object, groups); + if (CollUtil.isNotEmpty(constraintViolations)) { + throw new ConstraintViolationException(constraintViolations); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java new file mode 100644 index 0000000..139b089 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.ANNOTATION_TYPE, + ElementType.CONSTRUCTOR, + ElementType.PARAMETER, + ElementType.TYPE_USE +}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Constraint( + validatedBy = {InEnumValidator.class, InEnumCollectionValidator.class} +) +public @interface InEnum { + + /** + * @return 实现 EnumValuable 接口的 + */ + Class value(); + + String message() default "必须在指定范围 {value}"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java new file mode 100644 index 0000000..d20a717 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class InEnumCollectionValidator implements ConstraintValidator> { + + private List values; + + @Override + public void initialize(InEnum annotation) { + IntArrayValuable[] values = annotation.value().getEnumConstants(); + if (values.length == 0) { + this.values = Collections.emptyList(); + } else { + this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList()); + } + } + + @Override + public boolean isValid(Collection list, ConstraintValidatorContext context) { + // 校验通过 + if (CollUtil.containsAll(values, list)) { + return true; + } + // 校验不通过,自定义提示语句(因为,注解上的 value 是枚举类,无法获得枚举类的实际值) + context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值 + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate() + .replaceAll("\\{value}", CollUtil.join(list, ","))).addConstraintViolation(); // 重新添加错误提示语句 + return false; + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumValidator.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumValidator.java new file mode 100644 index 0000000..6cd08ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumValidator.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class InEnumValidator implements ConstraintValidator { + + private List values; + + @Override + public void initialize(InEnum annotation) { + IntArrayValuable[] values = annotation.value().getEnumConstants(); + if (values.length == 0) { + this.values = Collections.emptyList(); + } else { + this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList()); + } + } + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + // 为空时,默认不校验,即认为通过 + if (value == null) { + return true; + } + // 校验通过 + if (values.contains(value)) { + return true; + } + // 校验不通过,自定义提示语句(因为,注解上的 value 是枚举类,无法获得枚举类的实际值) + context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值 + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate() + .replaceAll("\\{value}", values.toString())).addConstraintViolation(); // 重新添加错误提示语句 + return false; + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Mobile.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Mobile.java new file mode 100644 index 0000000..4c7cb10 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Mobile.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.common.validation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.ANNOTATION_TYPE, + ElementType.CONSTRUCTOR, + ElementType.PARAMETER, + ElementType.TYPE_USE +}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Constraint( + validatedBy = MobileValidator.class +) +public @interface Mobile { + + String message() default "手机号格式不正确"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/MobileValidator.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/MobileValidator.java new file mode 100644 index 0000000..0bddfcb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/MobileValidator.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class MobileValidator implements ConstraintValidator { + + @Override + public void initialize(Mobile annotation) { + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + // 如果手机号为空,默认不校验,即校验通过 + if (StrUtil.isEmpty(value)) { + return true; + } + // 校验手机 + return ValidationUtils.isMobile(value); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Telephone.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Telephone.java new file mode 100644 index 0000000..910601f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Telephone.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.common.validation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.ANNOTATION_TYPE, + ElementType.CONSTRUCTOR, + ElementType.PARAMETER, + ElementType.TYPE_USE +}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Constraint( + validatedBy = TelephoneValidator.class +) +public @interface Telephone { + + String message() default "电话格式不正确"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/TelephoneValidator.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/TelephoneValidator.java new file mode 100644 index 0000000..d214cfe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/TelephoneValidator.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.PhoneUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class TelephoneValidator implements ConstraintValidator { + + @Override + public void initialize(Telephone annotation) { + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + // 如果手机号为空,默认不校验,即校验通过 + if (CharSequenceUtil.isEmpty(value)) { + return true; + } + // 校验手机 + return PhoneUtil.isTel(value) || PhoneUtil.isPhone(value); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/package-info.java new file mode 100644 index 0000000..aa95c69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/package-info.java @@ -0,0 +1,4 @@ +/** + * 使用 Hibernate Validator 实现参数校验 + */ +package cn.iocoder.yudao.framework.common.validation; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java new file mode 100644 index 0000000..0e44645 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.common.util.collection; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link CollectionUtils} 的单元测试 + */ +public class CollectionUtilsTest { + + @Data + @AllArgsConstructor + private static class Dog { + + private Integer id; + private String name; + private String code; + + } + + @Test + public void testDiffList() { + // 准备参数 + Collection oldList = Arrays.asList( + new Dog(1, "花花", "hh"), + new Dog(2, "旺财", "wc") + ); + Collection newList = Arrays.asList( + new Dog(null, "花花2", "hh"), + new Dog(null, "小白", "xb") + ); + BiFunction sameFunc = (oldObj, newObj) -> { + boolean same = oldObj.getCode().equals(newObj.getCode()); + // 如果相等的情况下,需要设置下 id,后续好更新 + if (same) { + newObj.setId(oldObj.getId()); + } + return same; + }; + + // 调用 + List> result = CollectionUtils.diffList(oldList, newList, sameFunc); + // 断言 + assertEquals(result.size(), 3); + // 断言 create + assertEquals(result.get(0).size(), 1); + assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb")); + // 断言 update + assertEquals(result.get(1).size(), 1); + assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh")); + // 断言 delete + assertEquals(result.get(2).size(), 1); + assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-common/《芋道 Spring Boot 参数校验 Validation 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-common/《芋道 Spring Boot 参数校验 Validation 入门》.md new file mode 100644 index 0000000..b2c2cf8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-common/《芋道 Spring Boot 参数校验 Validation 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml new file mode 100644 index 0000000..09e8786 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml @@ -0,0 +1,52 @@ + + + + yudao-framework + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-spring-boot-starter-biz-data-permission + jar + + ${project.artifactId} + 数据权限 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + true + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java new file mode 100644 index 0000000..4453198 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDataPermissionAutoConfiguration.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.framework.datapermission.config; + +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionAnnotationAdvisor; +import cn.iocoder.yudao.framework.datapermission.core.db.DataPermissionDatabaseInterceptor; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +/** + * 数据权限的自动配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +public class YudaoDataPermissionAutoConfiguration { + + @Bean + public DataPermissionRuleFactory dataPermissionRuleFactory(List rules) { + return new DataPermissionRuleFactoryImpl(rules); + } + + @Bean + public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(MybatisPlusInterceptor interceptor, + DataPermissionRuleFactory ruleFactory) { + // 创建 DataPermissionDatabaseInterceptor 拦截器 + DataPermissionDatabaseInterceptor inner = new DataPermissionDatabaseInterceptor(ruleFactory); + // 添加到 interceptor 中 + // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定 + MyBatisUtils.addInterceptor(interceptor, inner, 0); + return inner; + } + + @Bean + public DataPermissionAnnotationAdvisor dataPermissionAnnotationAdvisor() { + return new DataPermissionAnnotationAdvisor(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java new file mode 100644 index 0000000..6016fcd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/YudaoDeptDataPermissionAutoConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.datapermission.config; + +import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +/** + * 基于部门的数据权限 AutoConfiguration + * + * @author 芋道源码 + */ +@AutoConfiguration +@ConditionalOnClass(LoginUser.class) +@ConditionalOnBean(value = {PermissionApi.class, DeptDataPermissionRuleCustomizer.class}) +public class YudaoDeptDataPermissionAutoConfiguration { + + @Bean + public DeptDataPermissionRule deptDataPermissionRule(PermissionApi permissionApi, + List customizers) { + // 创建 DeptDataPermissionRule 对象 + DeptDataPermissionRule rule = new DeptDataPermissionRule(permissionApi); + // 补全表配置 + customizers.forEach(customizer -> customizer.customize(rule)); + return rule; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/annotation/DataPermission.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/annotation/DataPermission.java new file mode 100644 index 0000000..4e8a921 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/annotation/DataPermission.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.datapermission.core.annotation; + +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; + +import java.lang.annotation.*; + +/** + * 数据权限注解 + * 可声明在类或者方法上,标识使用的数据权限规则 + * + * @author 芋道源码 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 当前类或方法是否开启数据权限 + * 即使不添加 @DataPermission 注解,默认是开启状态 + * 可通过设置 enable 为 false 禁用 + */ + boolean enable() default true; + + /** + * 生效的数据权限规则数组,优先级高于 {@link #excludeRules()} + */ + Class[] includeRules() default {}; + + /** + * 排除的数据权限规则数组,优先级最低 + */ + Class[] excludeRules() default {}; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationAdvisor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationAdvisor.java new file mode 100644 index 0000000..03d212c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationAdvisor.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.datapermission.core.aop; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.aopalliance.aop.Advice; +import org.springframework.aop.Pointcut; +import org.springframework.aop.support.AbstractPointcutAdvisor; +import org.springframework.aop.support.ComposablePointcut; +import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; + +/** + * {@link cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission} 注解的 Advisor 实现类 + * + * @author 芋道源码 + */ +@Getter +@EqualsAndHashCode(callSuper = true) +public class DataPermissionAnnotationAdvisor extends AbstractPointcutAdvisor { + + private final Advice advice; + + private final Pointcut pointcut; + + public DataPermissionAnnotationAdvisor() { + this.advice = new DataPermissionAnnotationInterceptor(); + this.pointcut = this.buildPointcut(); + } + + protected Pointcut buildPointcut() { + Pointcut classPointcut = new AnnotationMatchingPointcut(DataPermission.class, true); + Pointcut methodPointcut = new AnnotationMatchingPointcut(null, DataPermission.class, true); + return new ComposablePointcut(classPointcut).union(methodPointcut); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptor.java new file mode 100644 index 0000000..48a0354 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptor.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.framework.datapermission.core.aop; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import lombok.Getter; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.core.MethodClassKey; +import org.springframework.core.annotation.AnnotationUtils; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * {@link DataPermission} 注解的拦截器 + * 1. 在执行方法前,将 @DataPermission 注解入栈 + * 2. 在执行方法后,将 @DataPermission 注解出栈 + * + * @author 芋道源码 + */ +@DataPermission // 该注解,用于 {@link DATA_PERMISSION_NULL} 的空对象 +public class DataPermissionAnnotationInterceptor implements MethodInterceptor { + + /** + * DataPermission 空对象,用于方法无 {@link DataPermission} 注解时,使用 DATA_PERMISSION_NULL 进行占位 + */ + static final DataPermission DATA_PERMISSION_NULL = DataPermissionAnnotationInterceptor.class.getAnnotation(DataPermission.class); + + @Getter + private final Map dataPermissionCache = new ConcurrentHashMap<>(); + + @Override + public Object invoke(MethodInvocation methodInvocation) throws Throwable { + // 入栈 + DataPermission dataPermission = this.findAnnotation(methodInvocation); + if (dataPermission != null) { + DataPermissionContextHolder.add(dataPermission); + } + try { + // 执行逻辑 + return methodInvocation.proceed(); + } finally { + // 出栈 + if (dataPermission != null) { + DataPermissionContextHolder.remove(); + } + } + } + + private DataPermission findAnnotation(MethodInvocation methodInvocation) { + // 1. 从缓存中获取 + Method method = methodInvocation.getMethod(); + Object targetObject = methodInvocation.getThis(); + Class clazz = targetObject != null ? targetObject.getClass() : method.getDeclaringClass(); + MethodClassKey methodClassKey = new MethodClassKey(method, clazz); + DataPermission dataPermission = dataPermissionCache.get(methodClassKey); + if (dataPermission != null) { + return dataPermission != DATA_PERMISSION_NULL ? dataPermission : null; + } + + // 2.1 从方法中获取 + dataPermission = AnnotationUtils.findAnnotation(method, DataPermission.class); + // 2.2 从类上获取 + if (dataPermission == null) { + dataPermission = AnnotationUtils.findAnnotation(clazz, DataPermission.class); + } + // 2.3 添加到缓存中 + dataPermissionCache.put(methodClassKey, dataPermission != null ? dataPermission : DATA_PERMISSION_NULL); + return dataPermission; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolder.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolder.java new file mode 100644 index 0000000..9705d88 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolder.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.framework.datapermission.core.aop; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import com.alibaba.ttl.TransmittableThreadLocal; + +import java.util.LinkedList; +import java.util.List; + +/** + * {@link DataPermission} 注解的 Context 上下文 + * + * @author 芋道源码 + */ +public class DataPermissionContextHolder { + + /** + * 使用 List 的原因,可能存在方法的嵌套调用 + */ + private static final ThreadLocal> DATA_PERMISSIONS = + TransmittableThreadLocal.withInitial(LinkedList::new); + + /** + * 获得当前的 DataPermission 注解 + * + * @return DataPermission 注解 + */ + public static DataPermission get() { + return DATA_PERMISSIONS.get().peekLast(); + } + + /** + * 入栈 DataPermission 注解 + * + * @param dataPermission DataPermission 注解 + */ + public static void add(DataPermission dataPermission) { + DATA_PERMISSIONS.get().addLast(dataPermission); + } + + /** + * 出栈 DataPermission 注解 + * + * @return DataPermission 注解 + */ + public static DataPermission remove() { + DataPermission dataPermission = DATA_PERMISSIONS.get().removeLast(); + // 无元素时,清空 ThreadLocal + if (DATA_PERMISSIONS.get().isEmpty()) { + DATA_PERMISSIONS.remove(); + } + return dataPermission; + } + + /** + * 获得所有 DataPermission + * + * @return DataPermission 队列 + */ + public static List getAll() { + return DATA_PERMISSIONS.get(); + } + + /** + * 清空上下文 + * + * 目前仅仅用于单测 + */ + public static void clear() { + DATA_PERMISSIONS.remove(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java new file mode 100644 index 0000000..cbeedee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java @@ -0,0 +1,641 @@ +package cn.iocoder.yudao.framework.datapermission.core.db; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.*; +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 java.sql.Connection; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 数据权限拦截器,通过 {@link DataPermissionRule} 数据权限规则,重写 SQL 的方式来实现 + * 主要的 SQL 重写方法,可见 {@link #builderExpression(Expression, List)} 方法 + * + * 整体的代码实现上,参考 {@link com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor} 实现。 + * 所以每次 MyBatis Plus 升级时,需要 Review 下其具体的实现是否有变更! + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class DataPermissionDatabaseInterceptor extends JsqlParserSupport implements InnerInterceptor { + + private final DataPermissionRuleFactory ruleFactory; + + @Getter + private final MappedStatementCache mappedStatementCache = new MappedStatementCache(); + + @Override // SELECT 场景 + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { + // 获得 Mapper 对应的数据权限的规则 + List rules = ruleFactory.getDataPermissionRule(ms.getId()); + if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 + return; + } + + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + try { + // 初始化上下文 + ContextHolder.init(rules); + // 处理 SQL + mpBs.sql(parserSingle(mpBs.sql(), null)); + } finally { + // 添加是否需要重写的缓存 + addMappedStatementCache(ms); + // 清空上下文 + ContextHolder.clear(); + } + } + + @Override // 只处理 UPDATE / DELETE 场景,不处理 INSERT 场景(因为 INSERT 不需要数据权限) + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + SqlCommandType sct = ms.getSqlCommandType(); + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + // 获得 Mapper 对应的数据权限的规则 + List rules = ruleFactory.getDataPermissionRule(ms.getId()); + if (mappedStatementCache.noRewritable(ms, rules)) { // 如果无需重写,则跳过 + return; + } + + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + try { + // 初始化上下文 + ContextHolder.init(rules); + // 处理 SQL + mpBs.sql(parserMulti(mpBs.sql(), null)); + } finally { + // 添加是否需要重写的缓存 + addMappedStatementCache(ms); + // 清空上下文 + ContextHolder.clear(); + } + } + } + + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + processSelectBody(select.getSelectBody()); + List withItemsList = select.getWithItemsList(); + if (!CollectionUtils.isEmpty(withItemsList)) { + withItemsList.forEach(this::processSelectBody); + } + } + + /** + * update 语句处理 + */ + @Override + protected void processUpdate(Update update, int index, String sql, Object obj) { + final Table table = update.getTable(); + update.setWhere(this.builderExpression(update.getWhere(), table)); + } + + /** + * delete 语句处理 + */ + @Override + protected void processDelete(Delete delete, int index, String sql, Object obj) { + delete.setWhere(this.builderExpression(delete.getWhere(), delete.getTable())); + } + + // ========== 和 TenantLineInnerInterceptor 一致的逻辑 ========== + + protected void processSelectBody(SelectBody selectBody) { + if (selectBody == null) { + return; + } + if (selectBody instanceof PlainSelect) { + processPlainSelect((PlainSelect) selectBody); + } else if (selectBody instanceof WithItem) { + WithItem withItem = (WithItem) selectBody; + processSelectBody(withItem.getSubSelect().getSelectBody()); + } else { + SetOperationList operationList = (SetOperationList) selectBody; + List selectBodyList = operationList.getSelects(); + if (CollectionUtils.isNotEmpty(selectBodyList)) { + selectBodyList.forEach(this::processSelectBody); + } + } + } + + /** + * 处理 PlainSelect + */ + protected void processPlainSelect(PlainSelect plainSelect) { + //#3087 github + List selectItems = plainSelect.getSelectItems(); + if (CollectionUtils.isNotEmpty(selectItems)) { + selectItems.forEach(this::processSelectItem); + } + + // 处理 where 中的子查询 + Expression where = plainSelect.getWhere(); + processWhereSubSelect(where); + + // 处理 fromItem + FromItem fromItem = plainSelect.getFromItem(); + List list = processFromItem(fromItem); + List
mainTables = new ArrayList<>(list); + + // 处理 join + List joins = plainSelect.getJoins(); + if (CollectionUtils.isNotEmpty(joins)) { + mainTables = processJoins(mainTables, joins); + } + + // 当有 mainTable 时,进行 where 条件追加 + if (CollectionUtils.isNotEmpty(mainTables)) { + plainSelect.setWhere(builderExpression(where, mainTables)); + } + } + + private List
processFromItem(FromItem fromItem) { + // 处理括号括起来的表达式 + while (fromItem instanceof ParenthesisFromItem) { + fromItem = ((ParenthesisFromItem) fromItem).getFromItem(); + } + + List
mainTables = new ArrayList<>(); + // 无 join 时的处理逻辑 + if (fromItem instanceof Table) { + Table fromTable = (Table) fromItem; + mainTables.add(fromTable); + } else if (fromItem instanceof SubJoin) { + // SubJoin 类型则还需要添加上 where 条件 + List
tables = processSubJoin((SubJoin) fromItem); + mainTables.addAll(tables); + } else { + // 处理下 fromItem + processOtherFromItem(fromItem); + } + return mainTables; + } + + /** + * 处理where条件内的子查询 + *

+ * 支持如下: + * 1. in + * 2. = + * 3. > + * 4. < + * 5. >= + * 6. <= + * 7. <> + * 8. EXISTS + * 9. NOT EXISTS + *

+ * 前提条件: + * 1. 子查询必须放在小括号中 + * 2. 子查询一般放在比较操作符的右边 + * + * @param where where 条件 + */ + protected void processWhereSubSelect(Expression where) { + if (where == null) { + return; + } + if (where instanceof FromItem) { + processOtherFromItem((FromItem) where); + return; + } + if (where.toString().indexOf("SELECT") > 0) { + // 有子查询 + if (where instanceof BinaryExpression) { + // 比较符号 , and , or , 等等 + BinaryExpression expression = (BinaryExpression) where; + processWhereSubSelect(expression.getLeftExpression()); + processWhereSubSelect(expression.getRightExpression()); + } else if (where instanceof InExpression) { + // in + InExpression expression = (InExpression) where; + Expression inExpression = expression.getRightExpression(); + if (inExpression instanceof SubSelect) { + processSelectBody(((SubSelect) inExpression).getSelectBody()); + } + } else if (where instanceof ExistsExpression) { + // exists + ExistsExpression expression = (ExistsExpression) where; + processWhereSubSelect(expression.getRightExpression()); + } else if (where instanceof NotExpression) { + // not exists + NotExpression expression = (NotExpression) where; + processWhereSubSelect(expression.getExpression()); + } else if (where instanceof Parenthesis) { + Parenthesis expression = (Parenthesis) where; + processWhereSubSelect(expression.getExpression()); + } + } + } + + protected void processSelectItem(SelectItem selectItem) { + if (selectItem instanceof SelectExpressionItem) { + SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; + if (selectExpressionItem.getExpression() instanceof SubSelect) { + processSelectBody(((SubSelect) selectExpressionItem.getExpression()).getSelectBody()); + } else if (selectExpressionItem.getExpression() instanceof Function) { + processFunction((Function) selectExpressionItem.getExpression()); + } + } + } + + /** + * 处理函数 + *

支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)

+ *

fixed gitee pulls/141

+ * + * @param function + */ + protected void processFunction(Function function) { + ExpressionList parameters = function.getParameters(); + if (parameters != null) { + parameters.getExpressions().forEach(expression -> { + if (expression instanceof SubSelect) { + processSelectBody(((SubSelect) expression).getSelectBody()); + } else if (expression instanceof Function) { + processFunction((Function) expression); + } + }); + } + } + + /** + * 处理子查询等 + */ + protected void processOtherFromItem(FromItem fromItem) { + // 去除括号 + while (fromItem instanceof ParenthesisFromItem) { + fromItem = ((ParenthesisFromItem) fromItem).getFromItem(); + } + + if (fromItem instanceof SubSelect) { + SubSelect subSelect = (SubSelect) fromItem; + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } else if (fromItem instanceof ValuesList) { + logger.debug("Perform a subQuery, if you do not give us feedback"); + } else if (fromItem instanceof LateralSubSelect) { + LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; + if (lateralSubSelect.getSubSelect() != null) { + SubSelect subSelect = lateralSubSelect.getSubSelect(); + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } + } + } + + /** + * 处理 sub join + * + * @param subJoin subJoin + * @return Table subJoin 中的主表 + */ + private List
processSubJoin(SubJoin subJoin) { + List
mainTables = new ArrayList<>(); + if (subJoin.getJoinList() != null) { + List
list = processFromItem(subJoin.getLeft()); + mainTables.addAll(list); + mainTables = processJoins(mainTables, subJoin.getJoinList()); + } + return mainTables; + } + + /** + * 处理 joins + * + * @param mainTables 可以为 null + * @param joins join 集合 + * @return List
右连接查询的 Table 列表 + */ + private List
processJoins(List
mainTables, List joins) { + // join 表达式中最终的主表 + Table mainTable = null; + // 当前 join 的左表 + Table leftTable = null; + + if (mainTables == null) { + mainTables = new ArrayList<>(); + } else if (mainTables.size() == 1) { + mainTable = mainTables.get(0); + leftTable = mainTable; + } + + //对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名 + Deque> onTableDeque = new LinkedList<>(); + for (Join join : joins) { + // 处理 on 表达式 + FromItem joinItem = join.getRightItem(); + + // 获取当前 join 的表,subJoint 可以看作是一张表 + List
joinTables = null; + if (joinItem instanceof Table) { + joinTables = new ArrayList<>(); + joinTables.add((Table) joinItem); + } else if (joinItem instanceof SubJoin) { + joinTables = processSubJoin((SubJoin) joinItem); + } + + if (joinTables != null) { + + // 如果是隐式内连接 + if (join.isSimple()) { + mainTables.addAll(joinTables); + continue; + } + + // 当前表是否忽略 + Table joinTable = joinTables.get(0); + + List
onTables = null; + // 如果不要忽略,且是右连接,则记录下当前表 + if (join.isRight()) { + mainTable = joinTable; + if (leftTable != null) { + onTables = Collections.singletonList(leftTable); + } + } else if (join.isLeft()) { + onTables = Collections.singletonList(joinTable); + } else if (join.isInner()) { + if (mainTable == null) { + onTables = Collections.singletonList(joinTable); + } else { + onTables = Arrays.asList(mainTable, joinTable); + } + mainTable = null; + } + + mainTables = new ArrayList<>(); + if (mainTable != null) { + mainTables.add(mainTable); + } + + // 获取 join 尾缀的 on 表达式列表 + Collection originOnExpressions = join.getOnExpressions(); + // 正常 join on 表达式只有一个,立刻处理 + if (originOnExpressions.size() == 1 && onTables != null) { + List onExpressions = new LinkedList<>(); + onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables)); + join.setOnExpressions(onExpressions); + leftTable = joinTable; + continue; + } + // 表名压栈,忽略的表压入 null,以便后续不处理 + onTableDeque.push(onTables); + // 尾缀多个 on 表达式的时候统一处理 + if (originOnExpressions.size() > 1) { + Collection onExpressions = new LinkedList<>(); + for (Expression originOnExpression : originOnExpressions) { + List
currentTableList = onTableDeque.poll(); + if (CollectionUtils.isEmpty(currentTableList)) { + onExpressions.add(originOnExpression); + } else { + onExpressions.add(builderExpression(originOnExpression, currentTableList)); + } + } + join.setOnExpressions(onExpressions); + } + leftTable = joinTable; + } else { + processOtherFromItem(joinItem); + leftTable = null; + } + } + + return mainTables; + } + + // ========== 和 TenantLineInnerInterceptor 存在差异的逻辑:关键,实现权限条件的拼接 ========== + + /** + * 处理条件 + * + * @param currentExpression 当前 where 条件 + * @param table 单个表 + */ + protected Expression builderExpression(Expression currentExpression, Table table) { + return this.builderExpression(currentExpression, Collections.singletonList(table)); + } + + /** + * 处理条件 + * + * @param currentExpression 当前 where 条件 + * @param tables 多个表 + */ + protected Expression builderExpression(Expression currentExpression, List
tables) { + // 没有表需要处理直接返回 + if (CollectionUtils.isEmpty(tables)) { + return currentExpression; + } + + // 第一步,获得 Table 对应的数据权限条件 + Expression dataPermissionExpression = null; + for (Table table : tables) { + // 构建每个表的权限 Expression 条件 + Expression expression = buildDataPermissionExpression(table); + if (expression == null) { + continue; + } + // 合并到 dataPermissionExpression 中 + dataPermissionExpression = dataPermissionExpression == null ? expression + : new AndExpression(dataPermissionExpression, expression); + } + + // 第二步,合并多个 Expression 条件 + if (dataPermissionExpression == null) { + return currentExpression; + } + if (currentExpression == null) { + return dataPermissionExpression; + } + // ① 如果表达式为 Or,则需要 (currentExpression) AND dataPermissionExpression + if (currentExpression instanceof OrExpression) { + return new AndExpression(new Parenthesis(currentExpression), dataPermissionExpression); + } + // ② 如果表达式为 And,则直接返回 where AND dataPermissionExpression + return new AndExpression(currentExpression, dataPermissionExpression); + } + + /** + * 构建指定表的数据权限的 Expression 过滤条件 + * + * @param table 表 + * @return Expression 过滤条件 + */ + private Expression buildDataPermissionExpression(Table table) { + // 生成条件 + Expression allExpression = null; + for (DataPermissionRule rule : ContextHolder.getRules()) { + // 判断表名是否匹配 + String tableName = MyBatisUtils.getTableName(table); + if (!rule.getTableNames().contains(tableName)) { + continue; + } + // 如果有匹配的规则,说明可重写。 + // 为什么不是有 allExpression 非空才重写呢?在生成 column = value 过滤条件时,会因为 value 不存在,导致未重写。 + // 这样导致第一次无 value,被标记成无需重写;但是第二次有 value,此时会需要重写。 + ContextHolder.setRewrite(true); + + // 单条规则的条件 + Expression oneExpress = rule.getExpression(tableName, table.getAlias()); + if (oneExpress == null){ + continue; + } + // 拼接到 allExpression 中 + allExpression = allExpression == null ? oneExpress + : new AndExpression(allExpression, oneExpress); + } + + return allExpression; + } + + /** + * 判断 SQL 是否重写。如果没有重写,则添加到 {@link MappedStatementCache} 中 + * + * @param ms MappedStatement + */ + private void addMappedStatementCache(MappedStatement ms) { + if (ContextHolder.getRewrite()) { + return; + } + // 无重写,进行添加 + mappedStatementCache.addNoRewritable(ms, ContextHolder.getRules()); + } + + /** + * SQL 解析上下文,方便透传 {@link DataPermissionRule} 规则 + * + * @author 芋道源码 + */ + static final class ContextHolder { + + /** + * 该 {@link MappedStatement} 对应的规则 + */ + private static final ThreadLocal> RULES = ThreadLocal.withInitial(Collections::emptyList); + /** + * SQL 是否进行重写 + */ + private static final ThreadLocal REWRITE = ThreadLocal.withInitial(() -> Boolean.FALSE); + + public static void init(List rules) { + RULES.set(rules); + REWRITE.set(false); + } + + public static void clear() { + RULES.remove(); + REWRITE.remove(); + } + + public static boolean getRewrite() { + return REWRITE.get(); + } + + public static void setRewrite(boolean rewrite) { + REWRITE.set(rewrite); + } + + public static List getRules() { + return RULES.get(); + } + + } + + /** + * {@link MappedStatement} 缓存 + * 目前主要用于,记录 {@link DataPermissionRule} 是否对指定 {@link MappedStatement} 无效 + * 如果无效,则可以避免 SQL 的解析,加快速度 + * + * @author 芋道源码 + */ + static final class MappedStatementCache { + + /** + * 指定数据权限规则,对指定 MappedStatement 无需重写(不生效)的缓存 + * + * value:{@link MappedStatement#getId()} 编号 + */ + @Getter + private final Map, Set> noRewritableMappedStatements = new ConcurrentHashMap<>(); + + /** + * 判断是否无需重写 + * ps:虽然有点中文式英语,但是容易读懂即可 + * + * @param ms MappedStatement + * @param rules 数据权限规则数组 + * @return 是否无需重写 + */ + public boolean noRewritable(MappedStatement ms, List rules) { + // 如果规则为空,说明无需重写 + if (CollUtil.isEmpty(rules)) { + return true; + } + // 任一规则不在 noRewritableMap 中,则说明可能需要重写 + for (DataPermissionRule rule : rules) { + Set mappedStatementIds = noRewritableMappedStatements.get(rule.getClass()); + if (!CollUtil.contains(mappedStatementIds, ms.getId())) { + return false; + } + } + return true; + } + + /** + * 添加无需重写的 MappedStatement + * + * @param ms MappedStatement + * @param rules 数据权限规则数组 + */ + public void addNoRewritable(MappedStatement ms, List rules) { + for (DataPermissionRule rule : rules) { + Set mappedStatementIds = noRewritableMappedStatements.get(rule.getClass()); + if (CollUtil.isNotEmpty(mappedStatementIds)) { + mappedStatementIds.add(ms.getId()); + } else { + noRewritableMappedStatements.put(rule.getClass(), SetUtils.asSet(ms.getId())); + } + } + } + + /** + * 清空缓存 + * 目前主要提供给单元测试 + */ + public void clear() { + noRewritableMappedStatements.clear(); + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRule.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRule.java new file mode 100644 index 0000000..2bccde8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRule.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule; + +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; + +import java.util.Set; + +/** + * 数据权限规则接口 + * 通过实现接口,自定义数据规则。例如说, + * + * @author 芋道源码 + */ +public interface DataPermissionRule { + + /** + * 返回需要生效的表名数组 + * 为什么需要该方法?Data Permission 数组基于 SQL 重写,通过 Where 返回只有权限的数据 + * + * 如果需要基于实体名获得表名,可调用 {@link TableInfoHelper#getTableInfo(Class)} 获得 + * + * @return 表名数组 + */ + Set getTableNames(); + + /** + * 根据表名和别名,生成对应的 WHERE / OR 过滤条件 + * + * @param tableName 表名 + * @param tableAlias 别名,可能为空 + * @return 过滤条件 Expression 表达式 + */ + Expression getExpression(String tableName, Alias tableAlias); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactory.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactory.java new file mode 100644 index 0000000..166dfea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactory.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule; + +import java.util.List; + +/** + * {@link DataPermissionRule} 工厂接口 + * 作为 {@link DataPermissionRule} 的容器,提供管理能力 + * + * @author 芋道源码 + */ +public interface DataPermissionRuleFactory { + + /** + * 获得所有数据权限规则数组 + * + * @return 数据权限规则数组 + */ + List getDataPermissionRules(); + + /** + * 获得指定 Mapper 的数据权限规则数组 + * + * @param mappedStatementId 指定 Mapper 的编号 + * @return 数据权限规则数组 + */ + List getDataPermissionRule(String mappedStatementId); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java new file mode 100644 index 0000000..eaa6e6a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; +import lombok.RequiredArgsConstructor; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 默认的 DataPermissionRuleFactoryImpl 实现类 + * 支持通过 {@link DataPermissionContextHolder} 过滤数据权限 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory { + + /** + * 数据权限规则数组 + */ + private final List rules; + + @Override + public List getDataPermissionRules() { + return rules; + } + + @Override // mappedStatementId 参数,暂时没有用。以后,可以基于 mappedStatementId + DataPermission 进行缓存 + public List getDataPermissionRule(String mappedStatementId) { + // 1. 无数据权限 + if (CollUtil.isEmpty(rules)) { + return Collections.emptyList(); + } + // 2. 未配置,则默认开启 + DataPermission dataPermission = DataPermissionContextHolder.get(); + if (dataPermission == null) { + return rules; + } + // 3. 已配置,但禁用 + if (!dataPermission.enable()) { + return Collections.emptyList(); + } + + // 4. 已配置,只选择部分规则 + if (ArrayUtil.isNotEmpty(dataPermission.includeRules())) { + return rules.stream().filter(rule -> ArrayUtil.contains(dataPermission.includeRules(), rule.getClass())) + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 + } + // 5. 已配置,只排除部分规则 + if (ArrayUtil.isNotEmpty(dataPermission.excludeRules())) { + return rules.stream().filter(rule -> !ArrayUtil.contains(dataPermission.excludeRules(), rule.getClass())) + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 + } + // 6. 已配置,全部规则 + return rules; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java new file mode 100644 index 0000000..bc54314 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java @@ -0,0 +1,205 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 基于部门的 {@link DataPermissionRule} 数据权限规则实现 + * + * 注意,使用 DeptDataPermissionRule 时,需要保证表中有 dept_id 部门编号的字段,可自定义。 + * + * 实际业务场景下,会存在一个经典的问题?当用户修改部门时,冗余的 dept_id 是否需要修改? + * 1. 一般情况下,dept_id 不进行修改,则会导致用户看不到之前的数据。【yudao-server 采用该方案】 + * 2. 部分情况下,希望该用户还是能看到之前的数据,则有两种方式解决:【需要你改造该 DeptDataPermissionRule 的实现代码】 + * 1)编写洗数据的脚本,将 dept_id 修改成新部门的编号;【建议】 + * 最终过滤条件是 WHERE dept_id = ? + * 2)洗数据的话,可能涉及的数据量较大,也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号; + * 最终过滤条件是 WHERE user_id IN (?, ?, ? ...) + * 3)想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤; + * 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...) + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Slf4j +public class DeptDataPermissionRule implements DataPermissionRule { + + /** + * LoginUser 的 Context 缓存 Key + */ + protected static final String CONTEXT_KEY = DeptDataPermissionRule.class.getSimpleName(); + + private static final String DEPT_COLUMN_NAME = "dept_id"; + private static final String USER_COLUMN_NAME = "user_id"; + + static final Expression EXPRESSION_NULL = new NullValue(); + + private final PermissionApi permissionApi; + + /** + * 基于部门的表字段配置 + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 + * + * key:表名 + * value:字段名 + */ + private final Map deptColumns = new HashMap<>(); + /** + * 基于用户的表字段配置 + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 + * + * key:表名 + * value:字段名 + */ + private final Map userColumns = new HashMap<>(); + /** + * 所有表名,是 {@link #deptColumns} 和 {@link #userColumns} 的合集 + */ + private final Set TABLE_NAMES = new HashSet<>(); + + @Override + public Set getTableNames() { + return TABLE_NAMES; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + // 只有有登陆用户的情况下,才进行数据权限的处理 + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + return null; + } + // 只有管理员类型的用户,才进行数据权限的处理 + if (ObjectUtil.notEqual(loginUser.getUserType(), UserTypeEnum.ADMIN.getValue())) { + return null; + } + + // 获得数据权限 + DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); + // 从上下文中拿不到,则调用逻辑进行获取 + if (deptDataPermission == null) { + deptDataPermission = permissionApi.getDeptDataPermission(loginUser.getId()); + if (deptDataPermission == null) { + log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); + throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限", + loginUser.getId(), tableName, tableAlias.getName())); + } + // 添加到上下文中,避免重复计算 + loginUser.setContext(CONTEXT_KEY, deptDataPermission); + } + + // 情况一,如果是 ALL 可查看全部,则无需拼接条件 + if (deptDataPermission.getAll()) { + return null; + } + + // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 + if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) + && Boolean.FALSE.equals(deptDataPermission.getSelf())) { + return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 + } + + // 情况三,拼接 Dept 和 User 的条件,最后组合 + Expression deptExpression = buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); + Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); + if (deptExpression == null && userExpression == null) { + // TODO 芋艿:获得不到条件的时候,暂时不抛出异常,而是不返回数据 + log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", + JsonUtils.toJsonString(loginUser), tableName, tableAlias, JsonUtils.toJsonString(deptDataPermission)); +// throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 构建的条件为空", +// loginUser.getId(), tableName, tableAlias.getName())); + return EXPRESSION_NULL; + } + if (deptExpression == null) { + return userExpression; + } + if (userExpression == null) { + return deptExpression; + } + // 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE (dept_id IN ? OR user_id = ?) + return new Parenthesis(new OrExpression(deptExpression, userExpression)); + } + + private Expression buildDeptExpression(String tableName, Alias tableAlias, Set deptIds) { + // 如果不存在配置,则无需作为条件 + String columnName = deptColumns.get(tableName); + if (StrUtil.isEmpty(columnName)) { + return null; + } + // 如果为空,则无条件 + if (CollUtil.isEmpty(deptIds)) { + return null; + } + // 拼接条件 + return new InExpression(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), + new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new))); + } + + private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) { + // 如果不查看自己,则无需作为条件 + if (Boolean.FALSE.equals(self)) { + return null; + } + String columnName = userColumns.get(tableName); + if (StrUtil.isEmpty(columnName)) { + return null; + } + // 拼接条件 + return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId)); + } + + // ==================== 添加配置 ==================== + + public void addDeptColumn(Class entityClass) { + addDeptColumn(entityClass, DEPT_COLUMN_NAME); + } + + public void addDeptColumn(Class entityClass, String columnName) { + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); + addDeptColumn(tableName, columnName); + } + + public void addDeptColumn(String tableName, String columnName) { + deptColumns.put(tableName, columnName); + TABLE_NAMES.add(tableName); + } + + public void addUserColumn(Class entityClass) { + addUserColumn(entityClass, USER_COLUMN_NAME); + } + + public void addUserColumn(Class entityClass, String columnName) { + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); + addUserColumn(tableName, columnName); + } + + public void addUserColumn(String tableName, String columnName) { + userColumns.put(tableName, columnName); + TABLE_NAMES.add(tableName); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java new file mode 100644 index 0000000..e5e4f57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleCustomizer.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule.dept; + +/** + * {@link DeptDataPermissionRule} 的自定义配置接口 + * + * @author 芋道源码 + */ +@FunctionalInterface +public interface DeptDataPermissionRuleCustomizer { + + /** + * 自定义该权限规则 + * 1. 调用 {@link DeptDataPermissionRule#addDeptColumn(Class, String)} 方法,配置基于 dept_id 的过滤规则 + * 2. 调用 {@link DeptDataPermissionRule#addUserColumn(Class, String)} 方法,配置基于 user_id 的过滤规则 + * + * @param rule 权限规则 + */ + void customize(DeptDataPermissionRule rule); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/package-info.java new file mode 100644 index 0000000..66e9326 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/package-info.java @@ -0,0 +1,6 @@ +/** + * 基于部门的数据权限规则 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.datapermission.core.rule.dept; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtils.java new file mode 100644 index 0000000..583c482 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtils.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.datapermission.core.util; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; +import lombok.SneakyThrows; + +import java.util.concurrent.Callable; + +/** + * 数据权限 Util + * + * @author 芋道源码 + */ +public class DataPermissionUtils { + + private static DataPermission DATA_PERMISSION_DISABLE; + + @DataPermission(enable = false) + @SneakyThrows + private static DataPermission getDisableDataPermissionDisable() { + if (DATA_PERMISSION_DISABLE == null) { + DATA_PERMISSION_DISABLE = DataPermissionUtils.class + .getDeclaredMethod("getDisableDataPermissionDisable") + .getAnnotation(DataPermission.class); + } + return DATA_PERMISSION_DISABLE; + } + + /** + * 忽略数据权限,执行对应的逻辑 + * + * @param runnable 逻辑 + */ + public static void executeIgnore(Runnable runnable) { + DataPermission dataPermission = getDisableDataPermissionDisable(); + DataPermissionContextHolder.add(dataPermission); + try { + // 执行 runnable + runnable.run(); + } finally { + DataPermissionContextHolder.remove(); + } + } + + /** + * 忽略数据权限,执行对应的逻辑 + * + * @param callable 逻辑 + * @return 执行结果 + */ + @SneakyThrows + public static T executeIgnore(Callable callable) { + DataPermission dataPermission = getDisableDataPermissionDisable(); + DataPermissionContextHolder.add(dataPermission); + try { + // 执行 callable + return callable.call(); + } finally { + DataPermissionContextHolder.remove(); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/package-info.java new file mode 100644 index 0000000..831aa7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/package-info.java @@ -0,0 +1,4 @@ +/** + * 基于 JSqlParser 解析 SQL,增加数据权限的 WHERE 条件 + */ +package cn.iocoder.yudao.framework.datapermission; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..c5d0cd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +cn.iocoder.yudao.framework.datapermission.config.YudaoDataPermissionAutoConfiguration +cn.iocoder.yudao.framework.datapermission.config.YudaoDeptDataPermissionAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptorTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptorTest.java new file mode 100644 index 0000000..ba97ede --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptorTest.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.framework.datapermission.core.aop; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.aopalliance.intercept.MethodInvocation; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +/** + * {@link DataPermissionAnnotationInterceptor} 的单元测试 + * + * @author 芋道源码 + */ +public class DataPermissionAnnotationInterceptorTest extends BaseMockitoUnitTest { + + @InjectMocks + private DataPermissionAnnotationInterceptor interceptor; + + @Mock + private MethodInvocation methodInvocation; + + @BeforeEach + public void setUp() { + interceptor.getDataPermissionCache().clear(); + } + + @Test // 无 @DataPermission 注解 + public void testInvoke_none() throws Throwable { + // 参数 + mockMethodInvocation(TestNone.class); + + // 调用 + Object result = interceptor.invoke(methodInvocation); + // 断言 + assertEquals("none", result); + assertEquals(1, interceptor.getDataPermissionCache().size()); + assertTrue(CollUtil.getFirst(interceptor.getDataPermissionCache().values()).enable()); + } + + @Test // 在 Method 上有 @DataPermission 注解 + public void testInvoke_method() throws Throwable { + // 参数 + mockMethodInvocation(TestMethod.class); + + // 调用 + Object result = interceptor.invoke(methodInvocation); + // 断言 + assertEquals("method", result); + assertEquals(1, interceptor.getDataPermissionCache().size()); + assertFalse(CollUtil.getFirst(interceptor.getDataPermissionCache().values()).enable()); + } + + @Test // 在 Class 上有 @DataPermission 注解 + public void testInvoke_class() throws Throwable { + // 参数 + mockMethodInvocation(TestClass.class); + + // 调用 + Object result = interceptor.invoke(methodInvocation); + // 断言 + assertEquals("class", result); + assertEquals(1, interceptor.getDataPermissionCache().size()); + assertFalse(CollUtil.getFirst(interceptor.getDataPermissionCache().values()).enable()); + } + + private void mockMethodInvocation(Class clazz) throws Throwable { + Object targetObject = clazz.newInstance(); + Method method = targetObject.getClass().getMethod("echo"); + when(methodInvocation.getThis()).thenReturn(targetObject); + when(methodInvocation.getMethod()).thenReturn(method); + when(methodInvocation.proceed()).then(invocationOnMock -> method.invoke(targetObject)); + } + + static class TestMethod { + + @DataPermission(enable = false) + public String echo() { + return "method"; + } + + } + + @DataPermission(enable = false) + static class TestClass { + + public String echo() { + return "class"; + } + + } + + static class TestNone { + + public String echo() { + return "none"; + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolderTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolderTest.java new file mode 100644 index 0000000..688b92d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolderTest.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.framework.datapermission.core.aop; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.mock; + +/** + * {@link DataPermissionContextHolder} 的单元测试 + * + * @author 芋道源码 + */ +class DataPermissionContextHolderTest { + + @BeforeEach + public void setUp() { + DataPermissionContextHolder.clear(); + } + + @Test + public void testGet() { + // mock 方法 + DataPermission dataPermission01 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission01); + DataPermission dataPermission02 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission02); + + // 调用 + DataPermission result = DataPermissionContextHolder.get(); + // 断言 + assertSame(result, dataPermission02); + } + + @Test + public void testPush() { + // 调用 + DataPermission dataPermission01 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission01); + DataPermission dataPermission02 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission02); + // 断言 + DataPermission first = DataPermissionContextHolder.getAll().get(0); + DataPermission second = DataPermissionContextHolder.getAll().get(1); + assertSame(dataPermission01, first); + assertSame(dataPermission02, second); + } + + @Test + public void testRemove() { + // mock 方法 + DataPermission dataPermission01 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission01); + DataPermission dataPermission02 = mock(DataPermission.class); + DataPermissionContextHolder.add(dataPermission02); + + // 调用 + DataPermission result = DataPermissionContextHolder.remove(); + // 断言 + assertSame(result, dataPermission02); + assertEquals(1, DataPermissionContextHolder.getAll().size()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest.java new file mode 100644 index 0000000..1453607 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.framework.datapermission.core.db; + +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.schema.Column; +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.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; + +import java.sql.Connection; +import java.util.*; + +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link DataPermissionDatabaseInterceptor} 的单元测试 + * 主要测试 {@link DataPermissionDatabaseInterceptor#beforePrepare(StatementHandler, Connection, Integer)} + * 和 {@link DataPermissionDatabaseInterceptor#beforeUpdate(Executor, MappedStatement, Object)} + * 以及在这个过程中,ContextHolder 和 MappedStatementCache + * + * @author 芋道源码 + */ +public class DataPermissionDatabaseInterceptorTest extends BaseMockitoUnitTest { + + @InjectMocks + private DataPermissionDatabaseInterceptor interceptor; + + @Mock + private DataPermissionRuleFactory ruleFactory; + + @BeforeEach + public void setUp() { + // 清理上下文 + DataPermissionDatabaseInterceptor.ContextHolder.clear(); + // 清空缓存 + interceptor.getMappedStatementCache().clear(); + } + + @Test // 不存在规则,且不匹配 + public void testBeforeQuery_withoutRule() { + try (MockedStatic pluginUtilsMock = mockStatic(PluginUtils.class)) { + // 准备参数 + MappedStatement mappedStatement = mock(MappedStatement.class); + BoundSql boundSql = mock(BoundSql.class); + + // 调用 + interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql); + // 断言 + pluginUtilsMock.verify(() -> PluginUtils.mpBoundSql(boundSql), never()); + } + } + + @Test // 存在规则,且不匹配 + public void testBeforeQuery_withMatchRule() { + try (MockedStatic pluginUtilsMock = mockStatic(PluginUtils.class)) { + // 准备参数 + MappedStatement mappedStatement = mock(MappedStatement.class); + BoundSql boundSql = mock(BoundSql.class); + // mock 方法(数据权限) + when(ruleFactory.getDataPermissionRule(same(mappedStatement.getId()))) + .thenReturn(singletonList(new DeptDataPermissionRule())); + // mock 方法(MPBoundSql) + PluginUtils.MPBoundSql mpBs = mock(PluginUtils.MPBoundSql.class); + pluginUtilsMock.when(() -> PluginUtils.mpBoundSql(same(boundSql))).thenReturn(mpBs); + // mock 方法(SQL) + String sql = "select * from t_user where id = 1"; + when(mpBs.sql()).thenReturn(sql); + // 针对 ContextHolder 和 MappedStatementCache 暂时不 mock,主要想校验过程中,数据是否正确 + + // 调用 + interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql); + // 断言 + verify(mpBs, times(1)).sql( + eq("SELECT * FROM t_user WHERE id = 1 AND t_user.dept_id = 100")); + // 断言缓存 + assertTrue(interceptor.getMappedStatementCache().getNoRewritableMappedStatements().isEmpty()); + } + } + + @Test // 存在规则,但不匹配 + public void testBeforeQuery_withoutMatchRule() { + try (MockedStatic pluginUtilsMock = mockStatic(PluginUtils.class)) { + // 准备参数 + MappedStatement mappedStatement = mock(MappedStatement.class); + BoundSql boundSql = mock(BoundSql.class); + // mock 方法(数据权限) + when(ruleFactory.getDataPermissionRule(same(mappedStatement.getId()))) + .thenReturn(singletonList(new DeptDataPermissionRule())); + // mock 方法(MPBoundSql) + PluginUtils.MPBoundSql mpBs = mock(PluginUtils.MPBoundSql.class); + pluginUtilsMock.when(() -> PluginUtils.mpBoundSql(same(boundSql))).thenReturn(mpBs); + // mock 方法(SQL) + String sql = "select * from t_role where id = 1"; + when(mpBs.sql()).thenReturn(sql); + // 针对 ContextHolder 和 MappedStatementCache 暂时不 mock,主要想校验过程中,数据是否正确 + + // 调用 + interceptor.beforeQuery(null, mappedStatement, null, null, null, boundSql); + // 断言 + verify(mpBs, times(1)).sql( + eq("SELECT * FROM t_role WHERE id = 1")); + // 断言缓存 + assertFalse(interceptor.getMappedStatementCache().getNoRewritableMappedStatements().isEmpty()); + } + } + + @Test + public void testAddNoRewritable() { + // 准备参数 + MappedStatement ms = mock(MappedStatement.class); + List rules = singletonList(new DeptDataPermissionRule()); + // mock 方法 + when(ms.getId()).thenReturn("selectById"); + + // 调用 + interceptor.getMappedStatementCache().addNoRewritable(ms, rules); + // 断言 + Map, Set> noRewritableMappedStatements = + interceptor.getMappedStatementCache().getNoRewritableMappedStatements(); + assertEquals(1, noRewritableMappedStatements.size()); + assertEquals(SetUtils.asSet("selectById"), noRewritableMappedStatements.get(DeptDataPermissionRule.class)); + } + + @Test + public void testNoRewritable() { + // 准备参数 + MappedStatement ms = mock(MappedStatement.class); + // mock 方法 + when(ms.getId()).thenReturn("selectById"); + // mock 数据 + List rules = singletonList(new DeptDataPermissionRule()); + interceptor.getMappedStatementCache().addNoRewritable(ms, rules); + + // 场景一,rules 为空 + assertTrue(interceptor.getMappedStatementCache().noRewritable(ms, null)); + // 场景二,rules 非空,可重写 + assertFalse(interceptor.getMappedStatementCache().noRewritable(ms, singletonList(new EmptyDataPermissionRule()))); + // 场景三,rule 非空,不可重写 + assertTrue(interceptor.getMappedStatementCache().noRewritable(ms, rules)); + } + + private static class DeptDataPermissionRule implements DataPermissionRule { + + private static final String COLUMN = "dept_id"; + + @Override + public Set getTableNames() { + return SetUtils.asSet("t_user"); + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + Column column = MyBatisUtils.buildColumn(tableName, tableAlias, COLUMN); + LongValue value = new LongValue(100L); + return new EqualsTo(column, value); + } + + } + + private static class EmptyDataPermissionRule implements DataPermissionRule { + + @Override + public Set getTableNames() { + return Collections.emptySet(); + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + return null; + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest2.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest2.java new file mode 100644 index 0000000..b8cad13 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptorTest2.java @@ -0,0 +1,533 @@ +package cn.iocoder.yudao.framework.datapermission.core.db; + +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.schema.Column; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Arrays; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link DataPermissionDatabaseInterceptor} 的单元测试 + * 主要复用了 MyBatis Plus 的 TenantLineInnerInterceptorTest 的单元测试 + * 不过它的单元测试不是很规范,考虑到是复用的,所以暂时不进行修改~ + * + * @author 芋道源码 + */ +public class DataPermissionDatabaseInterceptorTest2 extends BaseMockitoUnitTest { + + @InjectMocks + private DataPermissionDatabaseInterceptor interceptor; + + @Mock + private DataPermissionRuleFactory ruleFactory; + + @BeforeEach + public void setUp() { + // 租户的数据权限规则 + DataPermissionRule tenantRule = new DataPermissionRule() { + + private static final String COLUMN = "tenant_id"; + + @Override + public Set getTableNames() { + return asSet("entity", "entity1", "entity2", "entity3", "t1", "t2", "sys_dict_item", // 支持 MyBatis Plus 的单元测试 + "t_user", "t_role"); // 满足自己的单元测试 + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + Column column = MyBatisUtils.buildColumn(tableName, tableAlias, COLUMN); + LongValue value = new LongValue(1L); + return new EqualsTo(column, value); + } + + }; + // 部门的数据权限规则 + DataPermissionRule deptRule = new DataPermissionRule() { + + private static final String COLUMN = "dept_id"; + + @Override + public Set getTableNames() { + return asSet("t_user"); // 满足自己的单元测试 + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + Column column = MyBatisUtils.buildColumn(tableName, tableAlias, COLUMN); + ExpressionList values = new ExpressionList(new LongValue(10L), + new LongValue(20L)); + return new InExpression(column, values); + } + + }; + // 设置到上下文,保证 + DataPermissionDatabaseInterceptor.ContextHolder.init(Arrays.asList(tenantRule, deptRule)); + } + + @Test + void delete() { + assertSql("delete from entity where id = ?", + "DELETE FROM entity WHERE id = ? AND entity.tenant_id = 1"); + } + + @Test + void update() { + assertSql("update entity set name = ? where id = ?", + "UPDATE entity SET name = ? WHERE id = ? AND entity.tenant_id = 1"); + } + + @Test + void selectSingle() { + // 单表 + assertSql("select * from entity where id = ?", + "SELECT * FROM entity WHERE id = ? AND entity.tenant_id = 1"); + + assertSql("select * from entity where id = ? or name = ?", + "SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1"); + + assertSql("SELECT * FROM entity WHERE (id = ? OR name = ?)", + "SELECT * FROM entity WHERE (id = ? OR name = ?) AND entity.tenant_id = 1"); + + /* not */ + assertSql("SELECT * FROM entity WHERE not (id = ? OR name = ?)", + "SELECT * FROM entity WHERE NOT (id = ? OR name = ?) AND entity.tenant_id = 1"); + } + + @Test + void selectSubSelectIn() { + /* in */ + assertSql("SELECT * FROM entity e WHERE e.id IN (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id IN (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + // 在最前 + assertSql("SELECT * FROM entity e WHERE e.id IN " + + "(select e1.id from entity1 e1 where e1.id = ?) and e.id = ?", + "SELECT * FROM entity e WHERE e.id IN " + + "(SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.id = ? AND e.tenant_id = 1"); + // 在最后 + assertSql("SELECT * FROM entity e WHERE e.id = ? and e.id IN " + + "(select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id = ? AND e.id IN " + + "(SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + // 在中间 + assertSql("SELECT * FROM entity e WHERE e.id = ? and e.id IN " + + "(select e1.id from entity1 e1 where e1.id = ?) and e.id = ?", + "SELECT * FROM entity e WHERE e.id = ? AND e.id IN " + + "(SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.id = ? AND e.tenant_id = 1"); + } + + @Test + void selectSubSelectEq() { + /* = */ + assertSql("SELECT * FROM entity e WHERE e.id = (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id = (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + } + + @Test + void selectSubSelectInnerNotEq() { + /* inner not = */ + assertSql("SELECT * FROM entity e WHERE not (e.id = (select e1.id from entity1 e1 where e1.id = ?))", + "SELECT * FROM entity e WHERE NOT (e.id = (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1)) AND e.tenant_id = 1"); + + assertSql("SELECT * FROM entity e WHERE not (e.id = (select e1.id from entity1 e1 where e1.id = ?) and e.id = ?)", + "SELECT * FROM entity e WHERE NOT (e.id = (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.id = ?) AND e.tenant_id = 1"); + } + + @Test + void selectSubSelectExists() { + /* EXISTS */ + assertSql("SELECT * FROM entity e WHERE EXISTS (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE EXISTS (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + + + /* NOT EXISTS */ + assertSql("SELECT * FROM entity e WHERE NOT EXISTS (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE NOT EXISTS (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + } + + @Test + void selectSubSelect() { + /* >= */ + assertSql("SELECT * FROM entity e WHERE e.id >= (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id >= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + + + /* <= */ + assertSql("SELECT * FROM entity e WHERE e.id <= (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id <= (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + + + /* <> */ + assertSql("SELECT * FROM entity e WHERE e.id <> (select e1.id from entity1 e1 where e1.id = ?)", + "SELECT * FROM entity e WHERE e.id <> (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1"); + } + + @Test + void selectFromSelect() { + assertSql("SELECT * FROM (select e.id from entity e WHERE e.id = (select e1.id from entity1 e1 where e1.id = ?))", + "SELECT * FROM (SELECT e.id FROM entity e WHERE e.id = (SELECT e1.id FROM entity1 e1 WHERE e1.id = ? AND e1.tenant_id = 1) AND e.tenant_id = 1)"); + } + + @Test + void selectBodySubSelect() { + assertSql("select t1.col1,(select t2.col2 from t2 t2 where t1.col1=t2.col1) from t1 t1", + "SELECT t1.col1, (SELECT t2.col2 FROM t2 t2 WHERE t1.col1 = t2.col1 AND t2.tenant_id = 1) FROM t1 t1 WHERE t1.tenant_id = 1"); + } + + @Test + void selectLeftJoin() { + // left join + assertSql("SELECT * FROM entity e " + + "left join entity1 e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "left join entity1 e1 on e1.id = e.id " + + "WHERE (e.id = ? OR e.name = ?)", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "left join entity1 e1 on e1.id = e.id " + + "left join entity2 e2 on e1.id = e2.id", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " + + "WHERE e.tenant_id = 1"); + } + + @Test + void selectRightJoin() { + // right join + assertSql("SELECT * FROM entity e " + + "right join entity1 e1 on e1.id = e.id", + "SELECT * FROM entity e " + + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + + "WHERE e1.tenant_id = 1"); + + assertSql("SELECT * FROM with_as_1 e " + + "right join entity1 e1 on e1.id = e.id", + "SELECT * FROM with_as_1 e " + + "RIGHT JOIN entity1 e1 ON e1.id = e.id " + + "WHERE e1.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "right join entity1 e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM entity e " + + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "right join entity1 e1 on e1.id = e.id " + + "right join entity2 e2 on e1.id = e2.id ", + "SELECT * FROM entity e " + + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + + "RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " + + "WHERE e2.tenant_id = 1"); + } + + @Test + void selectMixJoin() { + assertSql("SELECT * FROM entity e " + + "right join entity1 e1 on e1.id = e.id " + + "left join entity2 e2 on e1.id = e2.id", + "SELECT * FROM entity e " + + "RIGHT JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 " + + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1 " + + "WHERE e1.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "left join entity1 e1 on e1.id = e.id " + + "right join entity2 e2 on e1.id = e2.id", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1 " + + "WHERE e2.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "left join entity1 e1 on e1.id = e.id " + + "inner join entity2 e2 on e1.id = e2.id", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "INNER JOIN entity2 e2 ON e1.id = e2.id AND e.tenant_id = 1 AND e2.tenant_id = 1"); + } + + + @Test + void selectJoinSubSelect() { + assertSql("select * from (select * from entity) e1 " + + "left join entity2 e2 on e1.id = e2.id", + "SELECT * FROM (SELECT * FROM entity WHERE entity.tenant_id = 1) e1 " + + "LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1"); + + assertSql("select * from entity1 e1 " + + "left join (select * from entity2) e2 " + + "on e1.id = e2.id", + "SELECT * FROM entity1 e1 " + + "LEFT JOIN (SELECT * FROM entity2 WHERE entity2.tenant_id = 1) e2 " + + "ON e1.id = e2.id " + + "WHERE e1.tenant_id = 1"); + } + + @Test + void selectSubJoin() { + + assertSql("select * FROM " + + "(entity1 e1 right JOIN entity2 e2 ON e1.id = e2.id)", + "SELECT * FROM " + + "(entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " + + "WHERE e2.tenant_id = 1"); + + assertSql("select * FROM " + + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id)", + "SELECT * FROM " + + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + + "WHERE e1.tenant_id = 1"); + + + assertSql("select * FROM " + + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id) " + + "right join entity3 e3 on e1.id = e3.id", + "SELECT * FROM " + + "(entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + + "RIGHT JOIN entity3 e3 ON e1.id = e3.id AND e1.tenant_id = 1 " + + "WHERE e3.tenant_id = 1"); + + + assertSql("select * FROM entity e " + + "LEFT JOIN (entity1 e1 right join entity2 e2 ON e1.id = e2.id) " + + "on e.id = e2.id", + "SELECT * FROM entity e " + + "LEFT JOIN (entity1 e1 RIGHT JOIN entity2 e2 ON e1.id = e2.id AND e1.tenant_id = 1) " + + "ON e.id = e2.id AND e2.tenant_id = 1 " + + "WHERE e.tenant_id = 1"); + + assertSql("select * FROM entity e " + + "LEFT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " + + "on e.id = e2.id", + "SELECT * FROM entity e " + + "LEFT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + + "ON e.id = e2.id AND e1.tenant_id = 1 " + + "WHERE e.tenant_id = 1"); + + assertSql("select * FROM entity e " + + "RIGHT JOIN (entity1 e1 left join entity2 e2 ON e1.id = e2.id) " + + "on e.id = e2.id", + "SELECT * FROM entity e " + + "RIGHT JOIN (entity1 e1 LEFT JOIN entity2 e2 ON e1.id = e2.id AND e2.tenant_id = 1) " + + "ON e.id = e2.id AND e.tenant_id = 1 " + + "WHERE e1.tenant_id = 1"); + } + + + @Test + void selectLeftJoinMultipleTrailingOn() { + // 多个 on 尾缀的 + assertSql("SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 " + + "LEFT JOIN entity2 e2 ON e2.id = e1.id " + + "ON e1.id = e.id " + + "WHERE (e.id = ? OR e.NAME = ?)", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 " + + "LEFT JOIN entity2 e2 ON e2.id = e1.id AND e2.tenant_id = 1 " + + "ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.NAME = ?) AND e.tenant_id = 1"); + + assertSql("SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 " + + "LEFT JOIN with_as_A e2 ON e2.id = e1.id " + + "ON e1.id = e.id " + + "WHERE (e.id = ? OR e.NAME = ?)", + "SELECT * FROM entity e " + + "LEFT JOIN entity1 e1 " + + "LEFT JOIN with_as_A e2 ON e2.id = e1.id " + + "ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.NAME = ?) AND e.tenant_id = 1"); + } + + @Test + void selectInnerJoin() { + // inner join + assertSql("SELECT * FROM entity e " + + "inner join entity1 e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM entity e " + + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " + + "WHERE e.id = ? OR e.name = ?"); + + assertSql("SELECT * FROM entity e " + + "inner join entity1 e1 on e1.id = e.id " + + "WHERE (e.id = ? OR e.name = ?)", + "SELECT * FROM entity e " + + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?)"); + + // 隐式内连接 + assertSql("SELECT * FROM entity,entity1 " + + "WHERE entity.id = entity1.id", + "SELECT * FROM entity, entity1 " + + "WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); + + // 隐式内连接 + assertSql("SELECT * FROM entity a, with_as_entity1 b " + + "WHERE a.id = b.id", + "SELECT * FROM entity a, with_as_entity1 b " + + "WHERE a.id = b.id AND a.tenant_id = 1"); + + assertSql("SELECT * FROM with_as_entity a, with_as_entity1 b " + + "WHERE a.id = b.id", + "SELECT * FROM with_as_entity a, with_as_entity1 b " + + "WHERE a.id = b.id"); + + // SubJoin with 隐式内连接 + assertSql("SELECT * FROM (entity,entity1) " + + "WHERE entity.id = entity1.id", + "SELECT * FROM (entity, entity1) " + + "WHERE entity.id = entity1.id " + + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); + + assertSql("SELECT * FROM ((entity,entity1),entity2) " + + "WHERE entity.id = entity1.id and entity.id = entity2.id", + "SELECT * FROM ((entity, entity1), entity2) " + + "WHERE entity.id = entity1.id AND entity.id = entity2.id " + + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1"); + + assertSql("SELECT * FROM (entity,(entity1,entity2)) " + + "WHERE entity.id = entity1.id and entity.id = entity2.id", + "SELECT * FROM (entity, (entity1, entity2)) " + + "WHERE entity.id = entity1.id AND entity.id = entity2.id " + + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1 AND entity2.tenant_id = 1"); + + // 沙雕的括号写法 + assertSql("SELECT * FROM (((entity,entity1))) " + + "WHERE entity.id = entity1.id", + "SELECT * FROM (((entity, entity1))) " + + "WHERE entity.id = entity1.id " + + "AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); + + } + + + @Test + void selectWithAs() { + assertSql("with with_as_A as (select * from entity) select * from with_as_A", + "WITH with_as_A AS (SELECT * FROM entity WHERE entity.tenant_id = 1) SELECT * FROM with_as_A"); + } + + + @Test + void selectIgnoreTable() { + assertSql(" SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)", + "SELECT dict.dict_code, item.item_text AS \"text\", item.item_value AS \"value\" FROM sys_dict_item item INNER JOIN sys_dict dict ON dict.id = item.dict_id AND item.tenant_id = 1 WHERE dict.dict_code IN (1, 2, 3) AND item.item_value IN (1, 2, 3)"); + } + + private void assertSql(String sql, String targetSql) { + assertEquals(targetSql, interceptor.parserSingle(sql, null)); + } + + + // ========== 额外的测试 ========== + + @Test + public void testSelectSingle() { + // 单表 + assertSql("select * from t_user where id = ?", + "SELECT * FROM t_user WHERE id = ? AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); + + assertSql("select * from t_user where id = ? or name = ?", + "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); + + assertSql("SELECT * FROM t_user WHERE (id = ? OR name = ?)", + "SELECT * FROM t_user WHERE (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); + + /* not */ + assertSql("SELECT * FROM t_user WHERE not (id = ? OR name = ?)", + "SELECT * FROM t_user WHERE NOT (id = ? OR name = ?) AND t_user.tenant_id = 1 AND t_user.dept_id IN (10, 20)"); + } + + @Test + public void testSelectLeftJoin() { + // left join + assertSql("SELECT * FROM t_user e " + + "left join t_role e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM t_user e " + + "LEFT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); + + // 条件 e.id = ? OR e.name = ? 带括号 + assertSql("SELECT * FROM t_user e " + + "left join t_role e1 on e1.id = e.id " + + "WHERE (e.id = ? OR e.name = ?)", + "SELECT * FROM t_user e " + + "LEFT JOIN t_role e1 ON e1.id = e.id AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1 AND e.dept_id IN (10, 20)"); + } + + @Test + public void testSelectRightJoin() { + // right join + assertSql("SELECT * FROM t_user e " + + "right join t_role e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM t_user e " + + "RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " + + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); + + // 条件 e.id = ? OR e.name = ? 带括号 + assertSql("SELECT * FROM t_user e " + + "right join t_role e1 on e1.id = e.id " + + "WHERE (e.id = ? OR e.name = ?)", + "SELECT * FROM t_user e " + + "RIGHT JOIN t_role e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) " + + "WHERE (e.id = ? OR e.name = ?) AND e1.tenant_id = 1"); + } + + @Test + public void testSelectInnerJoin() { + // inner join + assertSql("SELECT * FROM t_user e " + + "inner join entity1 e1 on e1.id = e.id " + + "WHERE e.id = ? OR e.name = ?", + "SELECT * FROM t_user e " + + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " + + "WHERE e.id = ? OR e.name = ?"); + + // 条件 e.id = ? OR e.name = ? 带括号 + assertSql("SELECT * FROM t_user e " + + "inner join entity1 e1 on e1.id = e.id " + + "WHERE (e.id = ? OR e.name = ?)", + "SELECT * FROM t_user e " + + "INNER JOIN entity1 e1 ON e1.id = e.id AND e.tenant_id = 1 AND e.dept_id IN (10, 20) AND e1.tenant_id = 1 " + + "WHERE (e.id = ? OR e.name = ?)"); + + // 没有 On 的 inner join + assertSql("SELECT * FROM entity,entity1 " + + "WHERE entity.id = entity1.id", + "SELECT * FROM entity, entity1 " + + "WHERE entity.id = entity1.id AND entity.tenant_id = 1 AND entity1.tenant_id = 1"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImplTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImplTest.java new file mode 100644 index 0000000..17dddc9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImplTest.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule; + +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.springframework.core.annotation.AnnotationUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link DataPermissionRuleFactoryImpl} 单元测试 + * + * @author 芋道源码 + */ +class DataPermissionRuleFactoryImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private DataPermissionRuleFactoryImpl dataPermissionRuleFactory; + + @Spy + private List rules = Arrays.asList(new DataPermissionRule01(), + new DataPermissionRule02()); + + @BeforeEach + public void setUp() { + DataPermissionContextHolder.clear(); + } + + @Test + public void testGetDataPermissionRule_02() { + // 准备参数 + String mappedStatementId = randomString(); + + // 调用 + List result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); + // 断言 + assertSame(rules, result); + } + + @Test + public void testGetDataPermissionRule_03() { + // 准备参数 + String mappedStatementId = randomString(); + // mock 方法 + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass03.class, DataPermission.class)); + + // 调用 + List result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); + // 断言 + assertTrue(result.isEmpty()); + } + + @Test + public void testGetDataPermissionRule_04() { + // 准备参数 + String mappedStatementId = randomString(); + // mock 方法 + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass04.class, DataPermission.class)); + + // 调用 + List result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); + // 断言 + assertEquals(1, result.size()); + assertEquals(DataPermissionRule01.class, result.get(0).getClass()); + } + + @Test + public void testGetDataPermissionRule_05() { + // 准备参数 + String mappedStatementId = randomString(); + // mock 方法 + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass05.class, DataPermission.class)); + + // 调用 + List result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); + // 断言 + assertEquals(1, result.size()); + assertEquals(DataPermissionRule02.class, result.get(0).getClass()); + } + + @Test + public void testGetDataPermissionRule_06() { + // 准备参数 + String mappedStatementId = randomString(); + // mock 方法 + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass06.class, DataPermission.class)); + + // 调用 + List result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); + // 断言 + assertSame(rules, result); + } + + @DataPermission(enable = false) + static class TestClass03 {} + + @DataPermission(includeRules = DataPermissionRule01.class) + static class TestClass04 {} + + @DataPermission(excludeRules = DataPermissionRule01.class) + static class TestClass05 {} + + @DataPermission + static class TestClass06 {} + + static class DataPermissionRule01 implements DataPermissionRule { + + @Override + public Set getTableNames() { + return null; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + return null; + } + + } + + static class DataPermissionRule02 implements DataPermissionRule { + + @Override + public Set getTableNames() { + return null; + } + + @Override + public Expression getExpression(String tableName, Alias tableAlias) { + return null; + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java new file mode 100644 index 0000000..d0fe496 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java @@ -0,0 +1,238 @@ +package cn.iocoder.yudao.framework.datapermission.core.rule.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule.EXPRESSION_NULL; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +/** + * {@link DeptDataPermissionRule} 的单元测试 + * + * @author 芋道源码 + */ +class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { + + @InjectMocks + private DeptDataPermissionRule rule; + + @Mock + private PermissionApi permissionApi; + + @BeforeEach + @SuppressWarnings("unchecked") + public void setUp() { + // 清空 rule + rule.getTableNames().clear(); + ((Map) ReflectUtil.getFieldValue(rule, "deptColumns")).clear(); + ((Map) ReflectUtil.getFieldValue(rule, "deptColumns")).clear(); + } + + @Test // 无 LoginUser + public void testGetExpression_noLoginUser() { + // 准备参数 + String tableName = randomString(); + Alias tableAlias = new Alias(randomString()); + // mock 方法 + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertNull(expression); + } + + @Test // 无数据权限时 + public void testGetExpression_noDeptDataPermission() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(permissionApi 返回 null) + when(permissionApi.getDeptDataPermission(eq(loginUser.getId()))).thenReturn(null); + + // 调用 + NullPointerException exception = assertThrows(NullPointerException.class, + () -> rule.getExpression(tableName, tableAlias)); + // 断言 + assertEquals("LoginUser(1) Table(t_user/u) 未返回数据权限", exception.getMessage()); + } + } + + @Test // 全部数据权限 + public void testGetExpression_allDeptDataPermission() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertNull(expression); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + + @Test // 即不能查看部门,又不能查看自己,则说明 100% 无权限 + public void testGetExpression_noDept_noSelf() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO(); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertEquals("null = null", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + + @Test // 拼接 Dept 和 User 的条件(字段都不符合) + public void testGetExpression_noDeptColumn_noSelfColumn() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertSame(EXPRESSION_NULL, expression); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + + @Test // 拼接 Dept 和 User 的条件(self 符合) + public void testGetExpression_noDeptColumn_yesSelfColumn() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setSelf(true); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + // 添加 user 字段配置 + rule.addUserColumn("t_user", "id"); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertEquals("u.id = 1", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + + @Test // 拼接 Dept 和 User 的条件(dept 符合) + public void testGetExpression_yesDeptColumn_noSelfColumn() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + // 添加 dept 字段配置 + rule.addDeptColumn("t_user", "dept_id"); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertEquals("u.dept_id IN (10, 20)", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + + @Test // 拼接 Dept 和 User 的条件(dept + self 符合) + public void testGetExpression_yesDeptColumn_yesSelfColumn() { + try (MockedStatic securityFrameworkUtilsMock + = mockStatic(SecurityFrameworkUtils.class)) { + // 准备参数 + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + // mock 方法(LoginUser) + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + // mock 方法(DeptDataPermissionRespDTO) + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); + // 添加 user 字段配置 + rule.addUserColumn("t_user", "id"); + // 添加 dept 字段配置 + rule.addDeptColumn("t_user", "dept_id"); + + // 调用 + Expression expression = rule.getExpression(tableName, tableAlias); + // 断言 + assertEquals("(u.dept_id IN (10, 20) OR u.id = 1)", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java new file mode 100644 index 0000000..1cc57c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtilsTest.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.framework.datapermission.core.util; + +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class DataPermissionUtilsTest { + + @Test + public void testExecuteIgnore() { + DataPermissionUtils.executeIgnore(() -> assertFalse(DataPermissionContextHolder.get().enable())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/pom.xml new file mode 100644 index 0000000..bc800c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/pom.xml @@ -0,0 +1,54 @@ + + + + yudao-framework + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-spring-boot-starter-biz-ip + jar + + ${project.artifactId} + IP 拓展,支持如下功能: + 1. IP 功能:查询 IP 对应的城市信息 + 基于 https://gitee.com/lionsoul/ip2region 实现 + 2. 城市功能:查询城市编码对应的城市信息 + 基于 https://github.com/modood/Administrative-divisions-of-China 实现 + + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.lionsoul + ip2region + + + + org.projectlombok + lombok + + + + org.slf4j + slf4j-api + provided + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java new file mode 100644 index 0000000..dcc9442 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.framework.ip.core; + +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 区域节点,包括国家、省份、城市、地区等信息 + * + * 数据可见 resources/area.csv 文件 + * + * @author 芋道源码 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Area { + + /** + * 编号 - 全球,即根目录 + */ + public static final Integer ID_GLOBAL = 0; + /** + * 编号 - 中国 + */ + public static final Integer ID_CHINA = 1; + + /** + * 编号 + */ + private Integer id; + /** + * 名字 + */ + private String name; + /** + * 类型 + * + * 枚举 {@link AreaTypeEnum} + */ + private Integer type; + + /** + * 父节点 + */ + private Area parent; + /** + * 子节点 + */ + private List children; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java new file mode 100644 index 0000000..916d885 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/enums/AreaTypeEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.framework.ip.core.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 区域类型枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum AreaTypeEnum implements IntArrayValuable { + + COUNTRY(1, "国家"), + PROVINCE(2, "省份"), + CITY(3, "城市"), + DISTRICT(4, "地区"), // 县、镇、区等 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AreaTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java new file mode 100644 index 0000000..8e27a31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java @@ -0,0 +1,214 @@ +package cn.iocoder.yudao.framework.ip.core.utils; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.text.csv.CsvRow; +import cn.hutool.core.text.csv.CsvUtil; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; + +/** + * 区域工具类 + * + * @author 芋道源码 + */ +@Slf4j +public class AreaUtils { + + /** + * 初始化 SEARCHER + */ + @SuppressWarnings("InstantiationOfUtilityClass") + private final static AreaUtils INSTANCE = new AreaUtils(); + + /** + * Area 内存缓存,提升访问速度 + */ + private static Map areas; + + private AreaUtils() { + long now = System.currentTimeMillis(); + areas = new HashMap<>(); + areas.put(Area.ID_GLOBAL, new Area(Area.ID_GLOBAL, "全球", 0, + null, new ArrayList<>())); + // 从 csv 中加载数据 + List rows = CsvUtil.getReader().read(ResourceUtil.getUtf8Reader("area.csv")).getRows(); + rows.remove(0); // 删除 header + for (CsvRow row : rows) { + // 创建 Area 对象 + Area area = new Area(Integer.valueOf(row.get(0)), row.get(1), Integer.valueOf(row.get(2)), + null, new ArrayList<>()); + // 添加到 areas 中 + areas.put(area.getId(), area); + } + + // 构建父子关系:因为 Area 中没有 parentId 字段,所以需要重复读取 + for (CsvRow row : rows) { + Area area = areas.get(Integer.valueOf(row.get(0))); // 自己 + Area parent = areas.get(Integer.valueOf(row.get(3))); // 父 + Assert.isTrue(area != parent, "{}:父子节点相同", area.getName()); + area.setParent(parent); + parent.getChildren().add(area); + } + log.info("启动加载 AreaUtils 成功,耗时 ({}) 毫秒", System.currentTimeMillis() - now); + } + + /** + * 获得指定编号对应的区域 + * + * @param id 区域编号 + * @return 区域 + */ + public static Area getArea(Integer id) { + return areas.get(id); + } + + /** + * 获得指定区域对应的编号 + * + * @param pathStr 区域路径,例如说:河南省/石家庄市/新华区 + * @return 区域 + */ + public static Area parseArea(String pathStr) { + String[] paths = pathStr.split("/"); + Area area = null; + for (String path : paths) { + if (area == null) { + area = findFirst(areas.values(), item -> item.getName().equals(path)); + } else { + area = findFirst(area.getChildren(), item -> item.getName().equals(path)); + } + } + return area; + } + + /** + * 获取所有节点的全路径名称如:河南省/石家庄市/新华区 + * + * @param areas 地区树 + * @return 所有节点的全路径名称 + */ + public static List getAreaNodePathList(List areas) { + List paths = new ArrayList<>(); + areas.forEach(area -> getAreaNodePathList(area, "", paths)); + return paths; + } + + /** + * 构建一棵树的所有节点的全路径名称,并将其存储为 "祖先/父级/子级" 的形式 + * + * @param node 父节点 + * @param path 全路径名称 + * @param paths 全路径名称列表,省份/城市/地区 + */ + private static void getAreaNodePathList(Area node, String path, List paths) { + if (node == null) { + return; + } + // 构建当前节点的路径 + String currentPath = path.isEmpty() ? node.getName() : path + "/" + node.getName(); + paths.add(currentPath); + // 递归遍历子节点 + for (Area child : node.getChildren()) { + getAreaNodePathList(child, currentPath, paths); + } + } + + /** + * 格式化区域 + * + * @param id 区域编号 + * @return 格式化后的区域 + */ + public static String format(Integer id) { + return format(id, " "); + } + + /** + * 格式化区域 + * + * 例如说: + * 1. id = “静安区”时:上海 上海市 静安区 + * 2. id = “上海市”时:上海 上海市 + * 3. id = “上海”时:上海 + * 4. id = “美国”时:美国 + * 当区域在中国时,默认不显示中国 + * + * @param id 区域编号 + * @param separator 分隔符 + * @return 格式化后的区域 + */ + public static String format(Integer id, String separator) { + // 获得区域 + Area area = areas.get(id); + if (area == null) { + return null; + } + + // 格式化 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < AreaTypeEnum.values().length; i++) { // 避免死循环 + sb.insert(0, area.getName()); + // “递归”父节点 + area = area.getParent(); + if (area == null + || ObjectUtils.equalsAny(area.getId(), Area.ID_GLOBAL, Area.ID_CHINA)) { // 跳过父节点为中国的情况 + break; + } + sb.insert(0, separator); + } + return sb.toString(); + } + + /** + * 获取指定类型的区域列表 + * + * @param type 区域类型 + * @param func 转换函数 + * @param 结果类型 + * @return 区域列表 + */ + public static List getByType(AreaTypeEnum type, Function func) { + return convertList(areas.values(), func, area -> type.getType().equals(area.getType())); + } + + /** + * 根据区域编号、上级区域类型,获取上级区域编号 + * + * @param id 区域编号 + * @param type 区域类型 + * @return 上级区域编号 + */ + public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { + for (int i = 0; i < Byte.MAX_VALUE; i++) { + Area area = AreaUtils.getArea(id); + if (area == null) { + return null; + } + // 情况一:匹配到,返回它 + if (type.getType().equals(area.getType())) { + return area.getId(); + } + // 情况二:找到根节点,返回空 + if (area.getParent() == null || area.getParent().getId() == null) { + return null; + } + // 其它:继续向上查找 + id = area.getParent().getId(); + } + return null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java new file mode 100644 index 0000000..f74f848 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.framework.ip.core.utils; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.iocoder.yudao.framework.ip.core.Area; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.lionsoul.ip2region.xdb.Searcher; + +import java.io.IOException; + +/** + * IP 工具类 + * + * IP 数据源来自 ip2region.xdb 精简版,基于 项目 + * + * @author wanglhup + */ +@Slf4j +public class IPUtils { + + /** + * 初始化 SEARCHER + */ + @SuppressWarnings("InstantiationOfUtilityClass") + private final static IPUtils INSTANCE = new IPUtils(); + + /** + * IP 查询器,启动加载到内存中 + */ + private static Searcher SEARCHER; + + /** + * 私有化构造 + */ + private IPUtils() { + try { + long now = System.currentTimeMillis(); + byte[] bytes = ResourceUtil.readBytes("ip2region.xdb"); + SEARCHER = Searcher.newWithBuffer(bytes); + log.info("启动加载 IPUtils 成功,耗时 ({}) 毫秒", System.currentTimeMillis() - now); + } catch (IOException e) { + log.error("启动加载 IPUtils 失败", e); + } + } + + /** + * 查询 IP 对应的地区编号 + * + * @param ip IP 地址,格式为 127.0.0.1 + * @return 地区id + */ + @SneakyThrows + public static Integer getAreaId(String ip) { + return Integer.parseInt(SEARCHER.search(ip.trim())); + } + + /** + * 查询 IP 对应的地区编号 + * + * @param ip IP 地址的时间戳,格式参考{@link Searcher#checkIP(String)} 的返回 + * @return 地区编号 + */ + @SneakyThrows + public static Integer getAreaId(long ip) { + return Integer.parseInt(SEARCHER.search(ip)); + } + + /** + * 查询 IP 对应的地区 + * + * @param ip IP 地址,格式为 127.0.0.1 + * @return 地区 + */ + public static Area getArea(String ip) { + return AreaUtils.getArea(getAreaId(ip)); + } + + /** + * 查询 IP 对应的地区 + * + * @param ip IP 地址的时间戳,格式参考{@link Searcher#checkIP(String)} 的返回 + * @return 地区 + */ + public static Area getArea(long ip) { + return AreaUtils.getArea(getAreaId(ip)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java new file mode 100644 index 0000000..9d422f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/package-info.java @@ -0,0 +1,11 @@ +/** + * IP 拓展,支持如下功能: + * + * 1. IP 功能:查询 IP 对应的城市信息 + * 基于 https://gitee.com/lionsoul/ip2region 实现 + * 2. 城市功能:查询城市编码对应的城市信息 + * 基于 https://github.com/modood/Administrative-divisions-of-China 实现 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.ip; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv new file mode 100644 index 0000000..0dd830e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv @@ -0,0 +1,3662 @@ +id,name,type,parentId +1,中国,1,0 +2,蒙古,1,0 +3,朝鲜,1,0 +4,韩国,1,0 +5,日本,1,0 +6,菲律宾,1,0 +7,越南,1,0 +8,老挝,1,0 +9,柬埔寨,1,0 +10,缅甸,1,0 +11,泰国,1,0 +12,马来西亚,1,0 +13,文莱,1,0 +14,新加坡,1,0 +15,印度尼西亚,1,0 +16,东帝汶,1,0 +17,尼泊尔,1,0 +18,不丹,1,0 +19,孟加拉国,1,0 +20,印度,1,0 +21,巴基斯坦,1,0 +22,斯里兰卡,1,0 +23,马尔代夫,1,0 +24,哈萨克斯坦,1,0 +25,吉尔吉斯斯坦,1,0 +26,塔吉克斯坦,1,0 +27,乌兹别克斯坦,1,0 +28,土库曼斯坦,1,0 +29,阿富汗,1,0 +30,伊拉克,1,0 +31,伊朗,1,0 +32,叙利亚,1,0 +33,约旦,1,0 +34,黎巴嫩,1,0 +35,以色列,1,0 +36,巴勒斯坦,1,0 +37,沙特阿拉伯,1,0 +38,巴林,1,0 +39,卡塔尔,1,0 +40,科威特,1,0 +41,阿拉伯联合酋长国,1,0 +42,阿曼,1,0 +43,也门,1,0 +44,格鲁吉亚,1,0 +45,亚美尼亚,1,0 +46,阿塞拜疆,1,0 +47,土耳其,1,0 +48,塞浦路斯,1,0 +49,芬兰,1,0 +50,瑞典,1,0 +51,挪威,1,0 +52,冰岛,1,0 +53,丹麦,1,0 +54,爱沙尼亚,1,0 +55,拉脱维亚,1,0 +56,立陶宛,1,0 +57,白俄罗斯,1,0 +58,俄罗斯,1,0 +59,乌克兰,1,0 +60,摩尔多瓦,1,0 +61,波兰,1,0 +62,捷克,1,0 +63,斯洛伐克,1,0 +64,匈牙利,1,0 +65,德国,1,0 +66,奥地利,1,0 +67,瑞士,1,0 +68,列支敦士登,1,0 +69,英国,1,0 +70,爱尔兰,1,0 +71,荷兰,1,0 +72,比利时,1,0 +73,卢森堡,1,0 +74,法国,1,0 +75,摩纳哥,1,0 +76,罗马尼亚,1,0 +77,保加利亚,1,0 +78,塞尔维亚,1,0 +79,马其顿,1,0 +80,阿尔巴尼亚,1,0 +81,希腊,1,0 +82,斯洛文尼亚,1,0 +83,克罗地亚,1,0 +84,波斯尼亚和墨塞哥维那,1,0 +85,意大利,1,0 +86,梵蒂冈,1,0 +87,圣马力诺,1,0 +88,马耳他,1,0 +89,西班牙,1,0 +90,葡萄牙,1,0 +91,安道尔共和国,1,0 +92,埃及,1,0 +93,利比亚,1,0 +94,苏丹,1,0 +95,突尼斯,1,0 +96,阿尔及利亚,1,0 +97,摩洛哥,1,0 +98,亚速尔群岛,1,0 +99,马德拉群岛,1,0 +100,埃塞俄比亚,1,0 +101,厄立特里亚,1,0 +102,索马里,1,0 +103,吉布提,1,0 +104,肯尼亚,1,0 +105,坦桑尼亚,1,0 +106,乌干达,1,0 +107,卢旺达,1,0 +108,布隆迪,1,0 +109,塞舌尔,1,0 +110,圣多美及普林西比,1,0 +111,塞内加尔,1,0 +112,冈比亚,1,0 +113,马里,1,0 +114,布基纳法索,1,0 +115,几内亚,1,0 +116,几内亚比绍,1,0 +117,佛得角,1,0 +118,塞拉利昂,1,0 +119,利比里亚,1,0 +120,科特迪瓦,1,0 +121,加纳,1,0 +122,多哥,1,0 +123,贝宁,1,0 +124,尼日尔,1,0 +125,加那利群岛,1,0 +126,赞比亚,1,0 +127,安哥拉,1,0 +128,津巴布韦,1,0 +129,马拉维,1,0 +130,莫桑比克,1,0 +131,博茨瓦纳,1,0 +132,纳米比亚,1,0 +133,南非,1,0 +134,斯威士兰,1,0 +135,莱索托,1,0 +136,马达加斯加,1,0 +137,科摩罗,1,0 +138,毛里求斯,1,0 +139,留尼旺,1,0 +140,圣赫勒拿,1,0 +141,澳大利亚,1,0 +142,新西兰,1,0 +143,巴布亚新几内亚,1,0 +144,所罗门群岛,1,0 +145,瓦努阿图共和国,1,0 +146,密克罗尼西亚,1,0 +147,马绍尔群岛,1,0 +148,帕劳,1,0 +149,瑙鲁,1,0 +150,基里巴斯,1,0 +151,图瓦卢,1,0 +152,萨摩亚,1,0 +153,斐济,1,0 +154,汤加,1,0 +155,库克群岛,1,0 +156,关岛,1,0 +157,新喀里多尼亚,1,0 +158,法属波利尼西亚,1,0 +159,皮特凯恩岛,1,0 +160,瓦利斯与富图纳,1,0 +161,纽埃,1,0 +162,托克劳,1,0 +163,美属萨摩亚,1,0 +164,北马里亚纳,1,0 +165,加拿大,1,0 +166,美国,1,0 +167,墨西哥,1,0 +168,格陵兰,1,0 +169,危地马拉,1,0 +170,伯利兹,1,0 +171,萨尔瓦多,1,0 +172,洪都拉斯,1,0 +173,尼加拉瓜,1,0 +174,哥斯达黎加,1,0 +175,巴拿马,1,0 +176,巴哈马,1,0 +177,古巴,1,0 +178,牙买加,1,0 +179,海地,1,0 +180,多米尼加共和国,1,0 +181,安提瓜和巴布达,1,0 +182,圣基茨和尼维斯,1,0 +183,多米尼克,1,0 +184,圣卢西亚,1,0 +185,圣文森特和格林纳丁斯,1,0 +186,格林纳达,1,0 +187,巴巴多斯,1,0 +188,特立尼达和多巴哥,1,0 +189,波多黎各,1,0 +190,英属维尔京群岛,1,0 +191,美属维尔京群岛,1,0 +192,安圭拉,1,0 +193,蒙特塞拉特岛,1,0 +194,瓜德罗普,1,0 +195,马提尼克,1,0 +196,荷属安的列斯,1,0 +197,阿鲁巴,1,0 +198,特克斯和凯科斯群岛,1,0 +199,开曼群岛,1,0 +200,百慕大,1,0 +201,哥伦比亚,1,0 +202,委内瑞拉,1,0 +203,圭亚那,1,0 +204,法属圭亚那,1,0 +205,苏里南,1,0 +206,厄瓜多尔,1,0 +207,秘鲁,1,0 +208,玻利维亚,1,0 +209,巴西,1,0 +210,智利,1,0 +211,阿根廷,1,0 +212,乌拉圭,1,0 +213,巴拉圭,1,0 +214,波黑,1,0 +215,直布罗陀,1,0 +216,新喀里多尼亚群岛,1,0 +217,瓦利斯和富图纳群岛,1,0 +218,泽西岛,1,0 +219,黑山,1,0 +220,英属马恩岛,1,0 +221,尼日利亚,1,0 +222,喀麦隆,1,0 +223,加蓬,1,0 +224,乍得,1,0 +225,刚果共和国,1,0 +226,中非共和国,1,0 +227,南苏丹,1,0 +228,赤道几内亚,1,0 +229,毛里塔尼亚,1,0 +230,刚果民主共和国,1,0 +231,留尼汪岛,1,0 +232,格陵兰岛,1,0 +233,法罗群岛,1,0 +234,根西岛,1,0 +235,百慕大群岛,1,0 +236,圣皮埃尔和密克隆群岛,1,0 +237,法属圣马丁,1,0 +238,奥兰群岛,1,0 +239,北马里亚纳群岛,1,0 +240,库拉索,1,0 +241,博内尔岛,1,0 +242,圣马丁岛,1,0 +243,圣巴泰勒米岛,1,0 +244,福克兰群岛,1,0 +245,圣多美和普林西比,1,0 +246,英属印度洋领地,1,0 +247,东萨摩亚,1,0 +248,诺福克岛,1,0 +110000,北京市,2,1 +120000,天津市,2,1 +130000,河北省,2,1 +140000,山西省,2,1 +150000,内蒙古自治区,2,1 +210000,辽宁省,2,1 +220000,吉林省,2,1 +230000,黑龙江省,2,1 +310000,上海市,2,1 +320000,江苏省,2,1 +330000,浙江省,2,1 +340000,安徽省,2,1 +350000,福建省,2,1 +360000,江西省,2,1 +370000,山东省,2,1 +410000,河南省,2,1 +420000,湖北省,2,1 +430000,湖南省,2,1 +440000,广东省,2,1 +450000,广西壮族自治区,2,1 +460000,海南省,2,1 +500000,重庆市,2,1 +510000,四川省,2,1 +520000,贵州省,2,1 +530000,云南省,2,1 +540000,西藏自治区,2,1 +610000,陕西省,2,1 +620000,甘肃省,2,1 +630000,青海省,2,1 +640000,宁夏回族自治区,2,1 +650000,新疆维吾尔自治区,2,1 +110100,北京市,3,110000 +120100,天津市,3,120000 +130100,石家庄市,3,130000 +130200,唐山市,3,130000 +130300,秦皇岛市,3,130000 +130400,邯郸市,3,130000 +130500,邢台市,3,130000 +130600,保定市,3,130000 +130700,张家口市,3,130000 +130800,承德市,3,130000 +130900,沧州市,3,130000 +131000,廊坊市,3,130000 +131100,衡水市,3,130000 +140100,太原市,3,140000 +140200,大同市,3,140000 +140300,阳泉市,3,140000 +140400,长治市,3,140000 +140500,晋城市,3,140000 +140600,朔州市,3,140000 +140700,晋中市,3,140000 +140800,运城市,3,140000 +140900,忻州市,3,140000 +141000,临汾市,3,140000 +141100,吕梁市,3,140000 +150100,呼和浩特市,3,150000 +150200,包头市,3,150000 +150300,乌海市,3,150000 +150400,赤峰市,3,150000 +150500,通辽市,3,150000 +150600,鄂尔多斯市,3,150000 +150700,呼伦贝尔市,3,150000 +150800,巴彦淖尔市,3,150000 +150900,乌兰察布市,3,150000 +152200,兴安盟,3,150000 +152500,锡林郭勒盟,3,150000 +152900,阿拉善盟,3,150000 +210100,沈阳市,3,210000 +210200,大连市,3,210000 +210300,鞍山市,3,210000 +210400,抚顺市,3,210000 +210500,本溪市,3,210000 +210600,丹东市,3,210000 +210700,锦州市,3,210000 +210800,营口市,3,210000 +210900,阜新市,3,210000 +211000,辽阳市,3,210000 +211100,盘锦市,3,210000 +211200,铁岭市,3,210000 +211300,朝阳市,3,210000 +211400,葫芦岛市,3,210000 +220100,长春市,3,220000 +220200,吉林市,3,220000 +220300,四平市,3,220000 +220400,辽源市,3,220000 +220500,通化市,3,220000 +220600,白山市,3,220000 +220700,松原市,3,220000 +220800,白城市,3,220000 +222400,延边朝鲜族自治州,3,220000 +230100,哈尔滨市,3,230000 +230200,齐齐哈尔市,3,230000 +230300,鸡西市,3,230000 +230400,鹤岗市,3,230000 +230500,双鸭山市,3,230000 +230600,大庆市,3,230000 +230700,伊春市,3,230000 +230800,佳木斯市,3,230000 +230900,七台河市,3,230000 +231000,牡丹江市,3,230000 +231100,黑河市,3,230000 +231200,绥化市,3,230000 +232700,大兴安岭地区,3,230000 +310100,上海市,3,310000 +320100,南京市,3,320000 +320200,无锡市,3,320000 +320300,徐州市,3,320000 +320400,常州市,3,320000 +320500,苏州市,3,320000 +320600,南通市,3,320000 +320700,连云港市,3,320000 +320800,淮安市,3,320000 +320900,盐城市,3,320000 +321000,扬州市,3,320000 +321100,镇江市,3,320000 +321200,泰州市,3,320000 +321300,宿迁市,3,320000 +330100,杭州市,3,330000 +330200,宁波市,3,330000 +330300,温州市,3,330000 +330400,嘉兴市,3,330000 +330500,湖州市,3,330000 +330600,绍兴市,3,330000 +330700,金华市,3,330000 +330800,衢州市,3,330000 +330900,舟山市,3,330000 +331000,台州市,3,330000 +331100,丽水市,3,330000 +340100,合肥市,3,340000 +340200,芜湖市,3,340000 +340300,蚌埠市,3,340000 +340400,淮南市,3,340000 +340500,马鞍山市,3,340000 +340600,淮北市,3,340000 +340700,铜陵市,3,340000 +340800,安庆市,3,340000 +341000,黄山市,3,340000 +341100,滁州市,3,340000 +341200,阜阳市,3,340000 +341300,宿州市,3,340000 +341500,六安市,3,340000 +341600,亳州市,3,340000 +341700,池州市,3,340000 +341800,宣城市,3,340000 +350100,福州市,3,350000 +350200,厦门市,3,350000 +350300,莆田市,3,350000 +350400,三明市,3,350000 +350500,泉州市,3,350000 +350600,漳州市,3,350000 +350700,南平市,3,350000 +350800,龙岩市,3,350000 +350900,宁德市,3,350000 +360100,南昌市,3,360000 +360200,景德镇市,3,360000 +360300,萍乡市,3,360000 +360400,九江市,3,360000 +360500,新余市,3,360000 +360600,鹰潭市,3,360000 +360700,赣州市,3,360000 +360800,吉安市,3,360000 +360900,宜春市,3,360000 +361000,抚州市,3,360000 +361100,上饶市,3,360000 +370100,济南市,3,370000 +370200,青岛市,3,370000 +370300,淄博市,3,370000 +370400,枣庄市,3,370000 +370500,东营市,3,370000 +370600,烟台市,3,370000 +370700,潍坊市,3,370000 +370800,济宁市,3,370000 +370900,泰安市,3,370000 +371000,威海市,3,370000 +371100,日照市,3,370000 +371300,临沂市,3,370000 +371400,德州市,3,370000 +371500,聊城市,3,370000 +371600,滨州市,3,370000 +371700,菏泽市,3,370000 +410100,郑州市,3,410000 +410200,开封市,3,410000 +410300,洛阳市,3,410000 +410400,平顶山市,3,410000 +410500,安阳市,3,410000 +410600,鹤壁市,3,410000 +410700,新乡市,3,410000 +410800,焦作市,3,410000 +410900,濮阳市,3,410000 +411000,许昌市,3,410000 +411100,漯河市,3,410000 +411200,三门峡市,3,410000 +411300,南阳市,3,410000 +411400,商丘市,3,410000 +411500,信阳市,3,410000 +411600,周口市,3,410000 +411700,驻马店市,3,410000 +419000,省直辖县级行政区划,3,410000 +420100,武汉市,3,420000 +420200,黄石市,3,420000 +420300,十堰市,3,420000 +420500,宜昌市,3,420000 +420600,襄阳市,3,420000 +420700,鄂州市,3,420000 +420800,荆门市,3,420000 +420900,孝感市,3,420000 +421000,荆州市,3,420000 +421100,黄冈市,3,420000 +421200,咸宁市,3,420000 +421300,随州市,3,420000 +422800,恩施土家族苗族自治州,3,420000 +429000,省直辖县级行政区划,3,420000 +430100,长沙市,3,430000 +430200,株洲市,3,430000 +430300,湘潭市,3,430000 +430400,衡阳市,3,430000 +430500,邵阳市,3,430000 +430600,岳阳市,3,430000 +430700,常德市,3,430000 +430800,张家界市,3,430000 +430900,益阳市,3,430000 +431000,郴州市,3,430000 +431100,永州市,3,430000 +431200,怀化市,3,430000 +431300,娄底市,3,430000 +433100,湘西土家族苗族自治州,3,430000 +440100,广州市,3,440000 +440200,韶关市,3,440000 +440300,深圳市,3,440000 +440400,珠海市,3,440000 +440500,汕头市,3,440000 +440600,佛山市,3,440000 +440700,江门市,3,440000 +440800,湛江市,3,440000 +440900,茂名市,3,440000 +441200,肇庆市,3,440000 +441300,惠州市,3,440000 +441400,梅州市,3,440000 +441500,汕尾市,3,440000 +441600,河源市,3,440000 +441700,阳江市,3,440000 +441800,清远市,3,440000 +441900,东莞市,3,440000 +441901,莞城区,4,441900 +441902,南城区,4,441900 +441904,万江区,4,441900 +441905,石碣镇,4,441900 +441906,石龙镇,4,441900 +441907,茶山镇,4,441900 +441908,石排镇,4,441900 +441909,企石镇,4,441900 +441910,横沥镇,4,441900 +441911,桥头镇,4,441900 +441912,谢岗镇,4,441900 +441913,东坑镇,4,441900 +441914,常平镇,4,441900 +441915,寮步镇,4,441900 +441916,大朗镇,4,441900 +441917,麻涌镇,4,441900 +441918,中堂镇,4,441900 +441919,高埗镇,4,441900 +441920,樟木头镇,4,441900 +441921,大岭山镇,4,441900 +441922,望牛墩镇,4,441900 +441923,黄江镇,4,441900 +441924,洪梅镇,4,441900 +441925,清溪镇,4,441900 +441926,沙田镇,4,441900 +441927,道滘镇,4,441900 +441928,塘厦镇,4,441900 +441929,虎门镇,4,441900 +441930,厚街镇,4,441900 +441931,凤岗镇,4,441900 +441932,长安镇,4,441900 +442000,中山市,3,440000 +442001,石岐街道,4,442000 +442002,东区街道,4,442000 +442003,中山港街道,4,442000 +442004,西区街道,4,442000 +442005,南区街道,4,442000 +442006,五桂山街道,4,442000 +442007,民众街道,4,442000 +442008,南朗街道,4,442000 +442009,黄圃镇,4,442000 +442010,东凤镇,4,442000 +442011,古镇镇,4,442000 +442012,沙溪镇,4,442000 +442013,坦洲镇,4,442000 +442014,港口镇,4,442000 +442015,三角镇,4,442000 +442016,横栏镇,4,442000 +442017,南头镇,4,442000 +442018,阜沙镇,4,442000 +442019,三乡镇,4,442000 +442020,板芙镇,4,442000 +442021,大涌镇,4,442000 +442022,神湾镇,4,442000 +442023,小榄镇,4,442000 +445100,潮州市,3,440000 +445200,揭阳市,3,440000 +445300,云浮市,3,440000 +450100,南宁市,3,450000 +450200,柳州市,3,450000 +450300,桂林市,3,450000 +450400,梧州市,3,450000 +450500,北海市,3,450000 +450600,防城港市,3,450000 +450700,钦州市,3,450000 +450800,贵港市,3,450000 +450900,玉林市,3,450000 +451000,百色市,3,450000 +451100,贺州市,3,450000 +451200,河池市,3,450000 +451300,来宾市,3,450000 +451400,崇左市,3,450000 +460100,海口市,3,460000 +460200,三亚市,3,460000 +460300,三沙市,3,460000 +460400,儋州市,3,460000 +469000,省直辖县级行政区划,3,460000 +500100,重庆市,3,500000 +510100,成都市,3,510000 +510300,自贡市,3,510000 +510400,攀枝花市,3,510000 +510500,泸州市,3,510000 +510600,德阳市,3,510000 +510700,绵阳市,3,510000 +510800,广元市,3,510000 +510900,遂宁市,3,510000 +511000,内江市,3,510000 +511100,乐山市,3,510000 +511300,南充市,3,510000 +511400,眉山市,3,510000 +511500,宜宾市,3,510000 +511600,广安市,3,510000 +511700,达州市,3,510000 +511800,雅安市,3,510000 +511900,巴中市,3,510000 +512000,资阳市,3,510000 +513200,阿坝藏族羌族自治州,3,510000 +513300,甘孜藏族自治州,3,510000 +513400,凉山彝族自治州,3,510000 +520100,贵阳市,3,520000 +520200,六盘水市,3,520000 +520300,遵义市,3,520000 +520400,安顺市,3,520000 +520500,毕节市,3,520000 +520600,铜仁市,3,520000 +522300,黔西南布依族苗族自治州,3,520000 +522600,黔东南苗族侗族自治州,3,520000 +522700,黔南布依族苗族自治州,3,520000 +530100,昆明市,3,530000 +530300,曲靖市,3,530000 +530400,玉溪市,3,530000 +530500,保山市,3,530000 +530600,昭通市,3,530000 +530700,丽江市,3,530000 +530800,普洱市,3,530000 +530900,临沧市,3,530000 +532300,楚雄彝族自治州,3,530000 +532500,红河哈尼族彝族自治州,3,530000 +532600,文山壮族苗族自治州,3,530000 +532800,西双版纳傣族自治州,3,530000 +532900,大理白族自治州,3,530000 +533100,德宏傣族景颇族自治州,3,530000 +533300,怒江傈僳族自治州,3,530000 +533400,迪庆藏族自治州,3,530000 +540100,拉萨市,3,540000 +540200,日喀则市,3,540000 +540300,昌都市,3,540000 +540400,林芝市,3,540000 +540500,山南市,3,540000 +540600,那曲市,3,540000 +542500,阿里地区,3,540000 +610100,西安市,3,610000 +610200,铜川市,3,610000 +610300,宝鸡市,3,610000 +610400,咸阳市,3,610000 +610500,渭南市,3,610000 +610600,延安市,3,610000 +610700,汉中市,3,610000 +610800,榆林市,3,610000 +610900,安康市,3,610000 +611000,商洛市,3,610000 +620100,兰州市,3,620000 +620200,嘉峪关市,3,620000 +620300,金昌市,3,620000 +620400,白银市,3,620000 +620500,天水市,3,620000 +620600,武威市,3,620000 +620700,张掖市,3,620000 +620800,平凉市,3,620000 +620900,酒泉市,3,620000 +621000,庆阳市,3,620000 +621100,定西市,3,620000 +621200,陇南市,3,620000 +622900,临夏回族自治州,3,620000 +623000,甘南藏族自治州,3,620000 +630100,西宁市,3,630000 +630200,海东市,3,630000 +632200,海北藏族自治州,3,630000 +632300,黄南藏族自治州,3,630000 +632500,海南藏族自治州,3,630000 +632600,果洛藏族自治州,3,630000 +632700,玉树藏族自治州,3,630000 +632800,海西蒙古族藏族自治州,3,630000 +640100,银川市,3,640000 +640200,石嘴山市,3,640000 +640300,吴忠市,3,640000 +640400,固原市,3,640000 +640500,中卫市,3,640000 +650100,乌鲁木齐市,3,650000 +650200,克拉玛依市,3,650000 +650400,吐鲁番市,3,650000 +650500,哈密市,3,650000 +652300,昌吉回族自治州,3,650000 +652700,博尔塔拉蒙古自治州,3,650000 +652800,巴音郭楞蒙古自治州,3,650000 +652900,阿克苏地区,3,650000 +653000,克孜勒苏柯尔克孜自治州,3,650000 +653100,喀什地区,3,650000 +653200,和田地区,3,650000 +654000,伊犁哈萨克自治州,3,650000 +654200,塔城地区,3,650000 +654300,阿勒泰地区,3,650000 +659000,自治区直辖县级行政区划,3,650000 +110101,东城区,4,110100 +110102,西城区,4,110100 +110105,朝阳区,4,110100 +110106,丰台区,4,110100 +110107,石景山区,4,110100 +110108,海淀区,4,110100 +110109,门头沟区,4,110100 +110111,房山区,4,110100 +110112,通州区,4,110100 +110113,顺义区,4,110100 +110114,昌平区,4,110100 +110115,大兴区,4,110100 +110116,怀柔区,4,110100 +110117,平谷区,4,110100 +110118,密云区,4,110100 +110119,延庆区,4,110100 +120101,和平区,4,120100 +120102,河东区,4,120100 +120103,河西区,4,120100 +120104,南开区,4,120100 +120105,河北区,4,120100 +120106,红桥区,4,120100 +120110,东丽区,4,120100 +120111,西青区,4,120100 +120112,津南区,4,120100 +120113,北辰区,4,120100 +120114,武清区,4,120100 +120115,宝坻区,4,120100 +120116,滨海新区,4,120100 +120117,宁河区,4,120100 +120118,静海区,4,120100 +120119,蓟州区,4,120100 +130102,长安区,4,130100 +130104,桥西区,4,130100 +130105,新华区,4,130100 +130107,井陉矿区,4,130100 +130108,裕华区,4,130100 +130109,藁城区,4,130100 +130110,鹿泉区,4,130100 +130111,栾城区,4,130100 +130121,井陉县,4,130100 +130123,正定县,4,130100 +130125,行唐县,4,130100 +130126,灵寿县,4,130100 +130127,高邑县,4,130100 +130128,深泽县,4,130100 +130129,赞皇县,4,130100 +130130,无极县,4,130100 +130131,平山县,4,130100 +130132,元氏县,4,130100 +130133,赵县,4,130100 +130171,石家庄高新技术产业开发区,4,130100 +130172,石家庄循环化工园区,4,130100 +130181,辛集市,4,130100 +130183,晋州市,4,130100 +130184,新乐市,4,130100 +130202,路南区,4,130200 +130203,路北区,4,130200 +130204,古冶区,4,130200 +130205,开平区,4,130200 +130207,丰南区,4,130200 +130208,丰润区,4,130200 +130209,曹妃甸区,4,130200 +130224,滦南县,4,130200 +130225,乐亭县,4,130200 +130227,迁西县,4,130200 +130229,玉田县,4,130200 +130271,河北唐山芦台经济开发区,4,130200 +130272,唐山市汉沽管理区,4,130200 +130273,唐山高新技术产业开发区,4,130200 +130274,河北唐山海港经济开发区,4,130200 +130281,遵化市,4,130200 +130283,迁安市,4,130200 +130284,滦州市,4,130200 +130302,海港区,4,130300 +130303,山海关区,4,130300 +130304,北戴河区,4,130300 +130306,抚宁区,4,130300 +130321,青龙满族自治县,4,130300 +130322,昌黎县,4,130300 +130324,卢龙县,4,130300 +130371,秦皇岛市经济技术开发区,4,130300 +130372,北戴河新区,4,130300 +130402,邯山区,4,130400 +130403,丛台区,4,130400 +130404,复兴区,4,130400 +130406,峰峰矿区,4,130400 +130407,肥乡区,4,130400 +130408,永年区,4,130400 +130423,临漳县,4,130400 +130424,成安县,4,130400 +130425,大名县,4,130400 +130426,涉县,4,130400 +130427,磁县,4,130400 +130430,邱县,4,130400 +130431,鸡泽县,4,130400 +130432,广平县,4,130400 +130433,馆陶县,4,130400 +130434,魏县,4,130400 +130435,曲周县,4,130400 +130471,邯郸经济技术开发区,4,130400 +130473,邯郸冀南新区,4,130400 +130481,武安市,4,130400 +130502,襄都区,4,130500 +130503,信都区,4,130500 +130505,任泽区,4,130500 +130506,南和区,4,130500 +130522,临城县,4,130500 +130523,内丘县,4,130500 +130524,柏乡县,4,130500 +130525,隆尧县,4,130500 +130528,宁晋县,4,130500 +130529,巨鹿县,4,130500 +130530,新河县,4,130500 +130531,广宗县,4,130500 +130532,平乡县,4,130500 +130533,威县,4,130500 +130534,清河县,4,130500 +130535,临西县,4,130500 +130571,河北邢台经济开发区,4,130500 +130581,南宫市,4,130500 +130582,沙河市,4,130500 +130602,竞秀区,4,130600 +130606,莲池区,4,130600 +130607,满城区,4,130600 +130608,清苑区,4,130600 +130609,徐水区,4,130600 +130623,涞水县,4,130600 +130624,阜平县,4,130600 +130626,定兴县,4,130600 +130627,唐县,4,130600 +130628,高阳县,4,130600 +130629,容城县,4,130600 +130630,涞源县,4,130600 +130631,望都县,4,130600 +130632,安新县,4,130600 +130633,易县,4,130600 +130634,曲阳县,4,130600 +130635,蠡县,4,130600 +130636,顺平县,4,130600 +130637,博野县,4,130600 +130638,雄县,4,130600 +130671,保定高新技术产业开发区,4,130600 +130672,保定白沟新城,4,130600 +130681,涿州市,4,130600 +130682,定州市,4,130600 +130683,安国市,4,130600 +130684,高碑店市,4,130600 +130702,桥东区,4,130700 +130703,桥西区,4,130700 +130705,宣化区,4,130700 +130706,下花园区,4,130700 +130708,万全区,4,130700 +130709,崇礼区,4,130700 +130722,张北县,4,130700 +130723,康保县,4,130700 +130724,沽源县,4,130700 +130725,尚义县,4,130700 +130726,蔚县,4,130700 +130727,阳原县,4,130700 +130728,怀安县,4,130700 +130730,怀来县,4,130700 +130731,涿鹿县,4,130700 +130732,赤城县,4,130700 +130771,张家口经济开发区,4,130700 +130772,张家口市察北管理区,4,130700 +130773,张家口市塞北管理区,4,130700 +130802,双桥区,4,130800 +130803,双滦区,4,130800 +130804,鹰手营子矿区,4,130800 +130821,承德县,4,130800 +130822,兴隆县,4,130800 +130824,滦平县,4,130800 +130825,隆化县,4,130800 +130826,丰宁满族自治县,4,130800 +130827,宽城满族自治县,4,130800 +130828,围场满族蒙古族自治县,4,130800 +130871,承德高新技术产业开发区,4,130800 +130881,平泉市,4,130800 +130902,新华区,4,130900 +130903,运河区,4,130900 +130921,沧县,4,130900 +130922,青县,4,130900 +130923,东光县,4,130900 +130924,海兴县,4,130900 +130925,盐山县,4,130900 +130926,肃宁县,4,130900 +130927,南皮县,4,130900 +130928,吴桥县,4,130900 +130929,献县,4,130900 +130930,孟村回族自治县,4,130900 +130971,河北沧州经济开发区,4,130900 +130972,沧州高新技术产业开发区,4,130900 +130973,沧州渤海新区,4,130900 +130981,泊头市,4,130900 +130982,任丘市,4,130900 +130983,黄骅市,4,130900 +130984,河间市,4,130900 +131002,安次区,4,131000 +131003,广阳区,4,131000 +131022,固安县,4,131000 +131023,永清县,4,131000 +131024,香河县,4,131000 +131025,大城县,4,131000 +131026,文安县,4,131000 +131028,大厂回族自治县,4,131000 +131071,廊坊经济技术开发区,4,131000 +131081,霸州市,4,131000 +131082,三河市,4,131000 +131102,桃城区,4,131100 +131103,冀州区,4,131100 +131121,枣强县,4,131100 +131122,武邑县,4,131100 +131123,武强县,4,131100 +131124,饶阳县,4,131100 +131125,安平县,4,131100 +131126,故城县,4,131100 +131127,景县,4,131100 +131128,阜城县,4,131100 +131171,河北衡水高新技术产业开发区,4,131100 +131172,衡水滨湖新区,4,131100 +131182,深州市,4,131100 +140105,小店区,4,140100 +140106,迎泽区,4,140100 +140107,杏花岭区,4,140100 +140108,尖草坪区,4,140100 +140109,万柏林区,4,140100 +140110,晋源区,4,140100 +140121,清徐县,4,140100 +140122,阳曲县,4,140100 +140123,娄烦县,4,140100 +140171,山西转型综合改革示范区,4,140100 +140181,古交市,4,140100 +140212,新荣区,4,140200 +140213,平城区,4,140200 +140214,云冈区,4,140200 +140215,云州区,4,140200 +140221,阳高县,4,140200 +140222,天镇县,4,140200 +140223,广灵县,4,140200 +140224,灵丘县,4,140200 +140225,浑源县,4,140200 +140226,左云县,4,140200 +140271,山西大同经济开发区,4,140200 +140302,城区,4,140300 +140303,矿区,4,140300 +140311,郊区,4,140300 +140321,平定县,4,140300 +140322,盂县,4,140300 +140403,潞州区,4,140400 +140404,上党区,4,140400 +140405,屯留区,4,140400 +140406,潞城区,4,140400 +140423,襄垣县,4,140400 +140425,平顺县,4,140400 +140426,黎城县,4,140400 +140427,壶关县,4,140400 +140428,长子县,4,140400 +140429,武乡县,4,140400 +140430,沁县,4,140400 +140431,沁源县,4,140400 +140471,山西长治高新技术产业园区,4,140400 +140502,城区,4,140500 +140521,沁水县,4,140500 +140522,阳城县,4,140500 +140524,陵川县,4,140500 +140525,泽州县,4,140500 +140581,高平市,4,140500 +140602,朔城区,4,140600 +140603,平鲁区,4,140600 +140621,山阴县,4,140600 +140622,应县,4,140600 +140623,右玉县,4,140600 +140671,山西朔州经济开发区,4,140600 +140681,怀仁市,4,140600 +140702,榆次区,4,140700 +140703,太谷区,4,140700 +140721,榆社县,4,140700 +140722,左权县,4,140700 +140723,和顺县,4,140700 +140724,昔阳县,4,140700 +140725,寿阳县,4,140700 +140727,祁县,4,140700 +140728,平遥县,4,140700 +140729,灵石县,4,140700 +140781,介休市,4,140700 +140802,盐湖区,4,140800 +140821,临猗县,4,140800 +140822,万荣县,4,140800 +140823,闻喜县,4,140800 +140824,稷山县,4,140800 +140825,新绛县,4,140800 +140826,绛县,4,140800 +140827,垣曲县,4,140800 +140828,夏县,4,140800 +140829,平陆县,4,140800 +140830,芮城县,4,140800 +140881,永济市,4,140800 +140882,河津市,4,140800 +140902,忻府区,4,140900 +140921,定襄县,4,140900 +140922,五台县,4,140900 +140923,代县,4,140900 +140924,繁峙县,4,140900 +140925,宁武县,4,140900 +140926,静乐县,4,140900 +140927,神池县,4,140900 +140928,五寨县,4,140900 +140929,岢岚县,4,140900 +140930,河曲县,4,140900 +140931,保德县,4,140900 +140932,偏关县,4,140900 +140971,五台山风景名胜区,4,140900 +140981,原平市,4,140900 +141002,尧都区,4,141000 +141021,曲沃县,4,141000 +141022,翼城县,4,141000 +141023,襄汾县,4,141000 +141024,洪洞县,4,141000 +141025,古县,4,141000 +141026,安泽县,4,141000 +141027,浮山县,4,141000 +141028,吉县,4,141000 +141029,乡宁县,4,141000 +141030,大宁县,4,141000 +141031,隰县,4,141000 +141032,永和县,4,141000 +141033,蒲县,4,141000 +141034,汾西县,4,141000 +141081,侯马市,4,141000 +141082,霍州市,4,141000 +141102,离石区,4,141100 +141121,文水县,4,141100 +141122,交城县,4,141100 +141123,兴县,4,141100 +141124,临县,4,141100 +141125,柳林县,4,141100 +141126,石楼县,4,141100 +141127,岚县,4,141100 +141128,方山县,4,141100 +141129,中阳县,4,141100 +141130,交口县,4,141100 +141181,孝义市,4,141100 +141182,汾阳市,4,141100 +150102,新城区,4,150100 +150103,回民区,4,150100 +150104,玉泉区,4,150100 +150105,赛罕区,4,150100 +150121,土默特左旗,4,150100 +150122,托克托县,4,150100 +150123,和林格尔县,4,150100 +150124,清水河县,4,150100 +150125,武川县,4,150100 +150172,呼和浩特经济技术开发区,4,150100 +150202,东河区,4,150200 +150203,昆都仑区,4,150200 +150204,青山区,4,150200 +150205,石拐区,4,150200 +150206,白云鄂博矿区,4,150200 +150207,九原区,4,150200 +150221,土默特右旗,4,150200 +150222,固阳县,4,150200 +150223,达尔罕茂明安联合旗,4,150200 +150271,包头稀土高新技术产业开发区,4,150200 +150302,海勃湾区,4,150300 +150303,海南区,4,150300 +150304,乌达区,4,150300 +150402,红山区,4,150400 +150403,元宝山区,4,150400 +150404,松山区,4,150400 +150421,阿鲁科尔沁旗,4,150400 +150422,巴林左旗,4,150400 +150423,巴林右旗,4,150400 +150424,林西县,4,150400 +150425,克什克腾旗,4,150400 +150426,翁牛特旗,4,150400 +150428,喀喇沁旗,4,150400 +150429,宁城县,4,150400 +150430,敖汉旗,4,150400 +150502,科尔沁区,4,150500 +150521,科尔沁左翼中旗,4,150500 +150522,科尔沁左翼后旗,4,150500 +150523,开鲁县,4,150500 +150524,库伦旗,4,150500 +150525,奈曼旗,4,150500 +150526,扎鲁特旗,4,150500 +150571,通辽经济技术开发区,4,150500 +150581,霍林郭勒市,4,150500 +150602,东胜区,4,150600 +150603,康巴什区,4,150600 +150621,达拉特旗,4,150600 +150622,准格尔旗,4,150600 +150623,鄂托克前旗,4,150600 +150624,鄂托克旗,4,150600 +150625,杭锦旗,4,150600 +150626,乌审旗,4,150600 +150627,伊金霍洛旗,4,150600 +150702,海拉尔区,4,150700 +150703,扎赉诺尔区,4,150700 +150721,阿荣旗,4,150700 +150722,莫力达瓦达斡尔族自治旗,4,150700 +150723,鄂伦春自治旗,4,150700 +150724,鄂温克族自治旗,4,150700 +150725,陈巴尔虎旗,4,150700 +150726,新巴尔虎左旗,4,150700 +150727,新巴尔虎右旗,4,150700 +150781,满洲里市,4,150700 +150782,牙克石市,4,150700 +150783,扎兰屯市,4,150700 +150784,额尔古纳市,4,150700 +150785,根河市,4,150700 +150802,临河区,4,150800 +150821,五原县,4,150800 +150822,磴口县,4,150800 +150823,乌拉特前旗,4,150800 +150824,乌拉特中旗,4,150800 +150825,乌拉特后旗,4,150800 +150826,杭锦后旗,4,150800 +150902,集宁区,4,150900 +150921,卓资县,4,150900 +150922,化德县,4,150900 +150923,商都县,4,150900 +150924,兴和县,4,150900 +150925,凉城县,4,150900 +150926,察哈尔右翼前旗,4,150900 +150927,察哈尔右翼中旗,4,150900 +150928,察哈尔右翼后旗,4,150900 +150929,四子王旗,4,150900 +150981,丰镇市,4,150900 +152201,乌兰浩特市,4,152200 +152202,阿尔山市,4,152200 +152221,科尔沁右翼前旗,4,152200 +152222,科尔沁右翼中旗,4,152200 +152223,扎赉特旗,4,152200 +152224,突泉县,4,152200 +152501,二连浩特市,4,152500 +152502,锡林浩特市,4,152500 +152522,阿巴嘎旗,4,152500 +152523,苏尼特左旗,4,152500 +152524,苏尼特右旗,4,152500 +152525,东乌珠穆沁旗,4,152500 +152526,西乌珠穆沁旗,4,152500 +152527,太仆寺旗,4,152500 +152528,镶黄旗,4,152500 +152529,正镶白旗,4,152500 +152530,正蓝旗,4,152500 +152531,多伦县,4,152500 +152571,乌拉盖管委会,4,152500 +152921,阿拉善左旗,4,152900 +152922,阿拉善右旗,4,152900 +152923,额济纳旗,4,152900 +152971,内蒙古阿拉善高新技术产业开发区,4,152900 +210102,和平区,4,210100 +210103,沈河区,4,210100 +210104,大东区,4,210100 +210105,皇姑区,4,210100 +210106,铁西区,4,210100 +210111,苏家屯区,4,210100 +210112,浑南区,4,210100 +210113,沈北新区,4,210100 +210114,于洪区,4,210100 +210115,辽中区,4,210100 +210123,康平县,4,210100 +210124,法库县,4,210100 +210181,新民市,4,210100 +210202,中山区,4,210200 +210203,西岗区,4,210200 +210204,沙河口区,4,210200 +210211,甘井子区,4,210200 +210212,旅顺口区,4,210200 +210213,金州区,4,210200 +210214,普兰店区,4,210200 +210224,长海县,4,210200 +210281,瓦房店市,4,210200 +210283,庄河市,4,210200 +210302,铁东区,4,210300 +210303,铁西区,4,210300 +210304,立山区,4,210300 +210311,千山区,4,210300 +210321,台安县,4,210300 +210323,岫岩满族自治县,4,210300 +210381,海城市,4,210300 +210402,新抚区,4,210400 +210403,东洲区,4,210400 +210404,望花区,4,210400 +210411,顺城区,4,210400 +210421,抚顺县,4,210400 +210422,新宾满族自治县,4,210400 +210423,清原满族自治县,4,210400 +210502,平山区,4,210500 +210503,溪湖区,4,210500 +210504,明山区,4,210500 +210505,南芬区,4,210500 +210521,本溪满族自治县,4,210500 +210522,桓仁满族自治县,4,210500 +210602,元宝区,4,210600 +210603,振兴区,4,210600 +210604,振安区,4,210600 +210624,宽甸满族自治县,4,210600 +210681,东港市,4,210600 +210682,凤城市,4,210600 +210702,古塔区,4,210700 +210703,凌河区,4,210700 +210711,太和区,4,210700 +210726,黑山县,4,210700 +210727,义县,4,210700 +210781,凌海市,4,210700 +210782,北镇市,4,210700 +210802,站前区,4,210800 +210803,西市区,4,210800 +210804,鲅鱼圈区,4,210800 +210811,老边区,4,210800 +210881,盖州市,4,210800 +210882,大石桥市,4,210800 +210902,海州区,4,210900 +210903,新邱区,4,210900 +210904,太平区,4,210900 +210905,清河门区,4,210900 +210911,细河区,4,210900 +210921,阜新蒙古族自治县,4,210900 +210922,彰武县,4,210900 +211002,白塔区,4,211000 +211003,文圣区,4,211000 +211004,宏伟区,4,211000 +211005,弓长岭区,4,211000 +211011,太子河区,4,211000 +211021,辽阳县,4,211000 +211081,灯塔市,4,211000 +211102,双台子区,4,211100 +211103,兴隆台区,4,211100 +211104,大洼区,4,211100 +211122,盘山县,4,211100 +211202,银州区,4,211200 +211204,清河区,4,211200 +211221,铁岭县,4,211200 +211223,西丰县,4,211200 +211224,昌图县,4,211200 +211281,调兵山市,4,211200 +211282,开原市,4,211200 +211302,双塔区,4,211300 +211303,龙城区,4,211300 +211321,朝阳县,4,211300 +211322,建平县,4,211300 +211324,喀喇沁左翼蒙古族自治县,4,211300 +211381,北票市,4,211300 +211382,凌源市,4,211300 +211402,连山区,4,211400 +211403,龙港区,4,211400 +211404,南票区,4,211400 +211421,绥中县,4,211400 +211422,建昌县,4,211400 +211481,兴城市,4,211400 +220102,南关区,4,220100 +220103,宽城区,4,220100 +220104,朝阳区,4,220100 +220105,二道区,4,220100 +220106,绿园区,4,220100 +220112,双阳区,4,220100 +220113,九台区,4,220100 +220122,农安县,4,220100 +220171,长春经济技术开发区,4,220100 +220172,长春净月高新技术产业开发区,4,220100 +220173,长春高新技术产业开发区,4,220100 +220174,长春汽车经济技术开发区,4,220100 +220182,榆树市,4,220100 +220183,德惠市,4,220100 +220184,公主岭市,4,220100 +220202,昌邑区,4,220200 +220203,龙潭区,4,220200 +220204,船营区,4,220200 +220211,丰满区,4,220200 +220221,永吉县,4,220200 +220271,吉林经济开发区,4,220200 +220272,吉林高新技术产业开发区,4,220200 +220273,吉林中国新加坡食品区,4,220200 +220281,蛟河市,4,220200 +220282,桦甸市,4,220200 +220283,舒兰市,4,220200 +220284,磐石市,4,220200 +220302,铁西区,4,220300 +220303,铁东区,4,220300 +220322,梨树县,4,220300 +220323,伊通满族自治县,4,220300 +220382,双辽市,4,220300 +220402,龙山区,4,220400 +220403,西安区,4,220400 +220421,东丰县,4,220400 +220422,东辽县,4,220400 +220502,东昌区,4,220500 +220503,二道江区,4,220500 +220521,通化县,4,220500 +220523,辉南县,4,220500 +220524,柳河县,4,220500 +220581,梅河口市,4,220500 +220582,集安市,4,220500 +220602,浑江区,4,220600 +220605,江源区,4,220600 +220621,抚松县,4,220600 +220622,靖宇县,4,220600 +220623,长白朝鲜族自治县,4,220600 +220681,临江市,4,220600 +220702,宁江区,4,220700 +220721,前郭尔罗斯蒙古族自治县,4,220700 +220722,长岭县,4,220700 +220723,乾安县,4,220700 +220771,吉林松原经济开发区,4,220700 +220781,扶余市,4,220700 +220802,洮北区,4,220800 +220821,镇赉县,4,220800 +220822,通榆县,4,220800 +220871,吉林白城经济开发区,4,220800 +220881,洮南市,4,220800 +220882,大安市,4,220800 +222401,延吉市,4,222400 +222402,图们市,4,222400 +222403,敦化市,4,222400 +222404,珲春市,4,222400 +222405,龙井市,4,222400 +222406,和龙市,4,222400 +222424,汪清县,4,222400 +222426,安图县,4,222400 +230102,道里区,4,230100 +230103,南岗区,4,230100 +230104,道外区,4,230100 +230108,平房区,4,230100 +230109,松北区,4,230100 +230110,香坊区,4,230100 +230111,呼兰区,4,230100 +230112,阿城区,4,230100 +230113,双城区,4,230100 +230123,依兰县,4,230100 +230124,方正县,4,230100 +230125,宾县,4,230100 +230126,巴彦县,4,230100 +230127,木兰县,4,230100 +230128,通河县,4,230100 +230129,延寿县,4,230100 +230183,尚志市,4,230100 +230184,五常市,4,230100 +230202,龙沙区,4,230200 +230203,建华区,4,230200 +230204,铁锋区,4,230200 +230205,昂昂溪区,4,230200 +230206,富拉尔基区,4,230200 +230207,碾子山区,4,230200 +230208,梅里斯达斡尔族区,4,230200 +230221,龙江县,4,230200 +230223,依安县,4,230200 +230224,泰来县,4,230200 +230225,甘南县,4,230200 +230227,富裕县,4,230200 +230229,克山县,4,230200 +230230,克东县,4,230200 +230231,拜泉县,4,230200 +230281,讷河市,4,230200 +230302,鸡冠区,4,230300 +230303,恒山区,4,230300 +230304,滴道区,4,230300 +230305,梨树区,4,230300 +230306,城子河区,4,230300 +230307,麻山区,4,230300 +230321,鸡东县,4,230300 +230381,虎林市,4,230300 +230382,密山市,4,230300 +230402,向阳区,4,230400 +230403,工农区,4,230400 +230404,南山区,4,230400 +230405,兴安区,4,230400 +230406,东山区,4,230400 +230407,兴山区,4,230400 +230421,萝北县,4,230400 +230422,绥滨县,4,230400 +230502,尖山区,4,230500 +230503,岭东区,4,230500 +230505,四方台区,4,230500 +230506,宝山区,4,230500 +230521,集贤县,4,230500 +230522,友谊县,4,230500 +230523,宝清县,4,230500 +230524,饶河县,4,230500 +230602,萨尔图区,4,230600 +230603,龙凤区,4,230600 +230604,让胡路区,4,230600 +230605,红岗区,4,230600 +230606,大同区,4,230600 +230621,肇州县,4,230600 +230622,肇源县,4,230600 +230623,林甸县,4,230600 +230624,杜尔伯特蒙古族自治县,4,230600 +230671,大庆高新技术产业开发区,4,230600 +230717,伊美区,4,230700 +230718,乌翠区,4,230700 +230719,友好区,4,230700 +230722,嘉荫县,4,230700 +230723,汤旺县,4,230700 +230724,丰林县,4,230700 +230725,大箐山县,4,230700 +230726,南岔县,4,230700 +230751,金林区,4,230700 +230781,铁力市,4,230700 +230803,向阳区,4,230800 +230804,前进区,4,230800 +230805,东风区,4,230800 +230811,郊区,4,230800 +230822,桦南县,4,230800 +230826,桦川县,4,230800 +230828,汤原县,4,230800 +230881,同江市,4,230800 +230882,富锦市,4,230800 +230883,抚远市,4,230800 +230902,新兴区,4,230900 +230903,桃山区,4,230900 +230904,茄子河区,4,230900 +230921,勃利县,4,230900 +231002,东安区,4,231000 +231003,阳明区,4,231000 +231004,爱民区,4,231000 +231005,西安区,4,231000 +231025,林口县,4,231000 +231071,牡丹江经济技术开发区,4,231000 +231081,绥芬河市,4,231000 +231083,海林市,4,231000 +231084,宁安市,4,231000 +231085,穆棱市,4,231000 +231086,东宁市,4,231000 +231102,爱辉区,4,231100 +231123,逊克县,4,231100 +231124,孙吴县,4,231100 +231181,北安市,4,231100 +231182,五大连池市,4,231100 +231183,嫩江市,4,231100 +231202,北林区,4,231200 +231221,望奎县,4,231200 +231222,兰西县,4,231200 +231223,青冈县,4,231200 +231224,庆安县,4,231200 +231225,明水县,4,231200 +231226,绥棱县,4,231200 +231281,安达市,4,231200 +231282,肇东市,4,231200 +231283,海伦市,4,231200 +232701,漠河市,4,232700 +232721,呼玛县,4,232700 +232722,塔河县,4,232700 +232761,加格达奇区,4,232700 +232762,松岭区,4,232700 +232763,新林区,4,232700 +232764,呼中区,4,232700 +310101,黄浦区,4,310100 +310104,徐汇区,4,310100 +310105,长宁区,4,310100 +310106,静安区,4,310100 +310107,普陀区,4,310100 +310109,虹口区,4,310100 +310110,杨浦区,4,310100 +310112,闵行区,4,310100 +310113,宝山区,4,310100 +310114,嘉定区,4,310100 +310115,浦东新区,4,310100 +310116,金山区,4,310100 +310117,松江区,4,310100 +310118,青浦区,4,310100 +310120,奉贤区,4,310100 +310151,崇明区,4,310100 +320102,玄武区,4,320100 +320104,秦淮区,4,320100 +320105,建邺区,4,320100 +320106,鼓楼区,4,320100 +320111,浦口区,4,320100 +320113,栖霞区,4,320100 +320114,雨花台区,4,320100 +320115,江宁区,4,320100 +320116,六合区,4,320100 +320117,溧水区,4,320100 +320118,高淳区,4,320100 +320205,锡山区,4,320200 +320206,惠山区,4,320200 +320211,滨湖区,4,320200 +320213,梁溪区,4,320200 +320214,新吴区,4,320200 +320281,江阴市,4,320200 +320282,宜兴市,4,320200 +320302,鼓楼区,4,320300 +320303,云龙区,4,320300 +320305,贾汪区,4,320300 +320311,泉山区,4,320300 +320312,铜山区,4,320300 +320321,丰县,4,320300 +320322,沛县,4,320300 +320324,睢宁县,4,320300 +320371,徐州经济技术开发区,4,320300 +320381,新沂市,4,320300 +320382,邳州市,4,320300 +320402,天宁区,4,320400 +320404,钟楼区,4,320400 +320411,新北区,4,320400 +320412,武进区,4,320400 +320413,金坛区,4,320400 +320481,溧阳市,4,320400 +320505,虎丘区,4,320500 +320506,吴中区,4,320500 +320507,相城区,4,320500 +320508,姑苏区,4,320500 +320509,吴江区,4,320500 +320571,苏州工业园区,4,320500 +320581,常熟市,4,320500 +320582,张家港市,4,320500 +320583,昆山市,4,320500 +320585,太仓市,4,320500 +320612,通州区,4,320600 +320613,崇川区,4,320600 +320614,海门区,4,320600 +320623,如东县,4,320600 +320671,南通经济技术开发区,4,320600 +320681,启东市,4,320600 +320682,如皋市,4,320600 +320685,海安市,4,320600 +320703,连云区,4,320700 +320706,海州区,4,320700 +320707,赣榆区,4,320700 +320722,东海县,4,320700 +320723,灌云县,4,320700 +320724,灌南县,4,320700 +320771,连云港经济技术开发区,4,320700 +320772,连云港高新技术产业开发区,4,320700 +320803,淮安区,4,320800 +320804,淮阴区,4,320800 +320812,清江浦区,4,320800 +320813,洪泽区,4,320800 +320826,涟水县,4,320800 +320830,盱眙县,4,320800 +320831,金湖县,4,320800 +320871,淮安经济技术开发区,4,320800 +320902,亭湖区,4,320900 +320903,盐都区,4,320900 +320904,大丰区,4,320900 +320921,响水县,4,320900 +320922,滨海县,4,320900 +320923,阜宁县,4,320900 +320924,射阳县,4,320900 +320925,建湖县,4,320900 +320971,盐城经济技术开发区,4,320900 +320981,东台市,4,320900 +321002,广陵区,4,321000 +321003,邗江区,4,321000 +321012,江都区,4,321000 +321023,宝应县,4,321000 +321071,扬州经济技术开发区,4,321000 +321081,仪征市,4,321000 +321084,高邮市,4,321000 +321102,京口区,4,321100 +321111,润州区,4,321100 +321112,丹徒区,4,321100 +321171,镇江新区,4,321100 +321181,丹阳市,4,321100 +321182,扬中市,4,321100 +321183,句容市,4,321100 +321202,海陵区,4,321200 +321203,高港区,4,321200 +321204,姜堰区,4,321200 +321271,泰州医药高新技术产业开发区,4,321200 +321281,兴化市,4,321200 +321282,靖江市,4,321200 +321283,泰兴市,4,321200 +321302,宿城区,4,321300 +321311,宿豫区,4,321300 +321322,沭阳县,4,321300 +321323,泗阳县,4,321300 +321324,泗洪县,4,321300 +321371,宿迁经济技术开发区,4,321300 +330102,上城区,4,330100 +330105,拱墅区,4,330100 +330106,西湖区,4,330100 +330108,滨江区,4,330100 +330109,萧山区,4,330100 +330110,余杭区,4,330100 +330111,富阳区,4,330100 +330112,临安区,4,330100 +330113,临平区,4,330100 +330114,钱塘区,4,330100 +330122,桐庐县,4,330100 +330127,淳安县,4,330100 +330182,建德市,4,330100 +330203,海曙区,4,330200 +330205,江北区,4,330200 +330206,北仑区,4,330200 +330211,镇海区,4,330200 +330212,鄞州区,4,330200 +330213,奉化区,4,330200 +330225,象山县,4,330200 +330226,宁海县,4,330200 +330281,余姚市,4,330200 +330282,慈溪市,4,330200 +330302,鹿城区,4,330300 +330303,龙湾区,4,330300 +330304,瓯海区,4,330300 +330305,洞头区,4,330300 +330324,永嘉县,4,330300 +330326,平阳县,4,330300 +330327,苍南县,4,330300 +330328,文成县,4,330300 +330329,泰顺县,4,330300 +330371,温州经济技术开发区,4,330300 +330381,瑞安市,4,330300 +330382,乐清市,4,330300 +330383,龙港市,4,330300 +330402,南湖区,4,330400 +330411,秀洲区,4,330400 +330421,嘉善县,4,330400 +330424,海盐县,4,330400 +330481,海宁市,4,330400 +330482,平湖市,4,330400 +330483,桐乡市,4,330400 +330502,吴兴区,4,330500 +330503,南浔区,4,330500 +330521,德清县,4,330500 +330522,长兴县,4,330500 +330523,安吉县,4,330500 +330602,越城区,4,330600 +330603,柯桥区,4,330600 +330604,上虞区,4,330600 +330624,新昌县,4,330600 +330681,诸暨市,4,330600 +330683,嵊州市,4,330600 +330702,婺城区,4,330700 +330703,金东区,4,330700 +330723,武义县,4,330700 +330726,浦江县,4,330700 +330727,磐安县,4,330700 +330781,兰溪市,4,330700 +330782,义乌市,4,330700 +330783,东阳市,4,330700 +330784,永康市,4,330700 +330802,柯城区,4,330800 +330803,衢江区,4,330800 +330822,常山县,4,330800 +330824,开化县,4,330800 +330825,龙游县,4,330800 +330881,江山市,4,330800 +330902,定海区,4,330900 +330903,普陀区,4,330900 +330921,岱山县,4,330900 +330922,嵊泗县,4,330900 +331002,椒江区,4,331000 +331003,黄岩区,4,331000 +331004,路桥区,4,331000 +331022,三门县,4,331000 +331023,天台县,4,331000 +331024,仙居县,4,331000 +331081,温岭市,4,331000 +331082,临海市,4,331000 +331083,玉环市,4,331000 +331102,莲都区,4,331100 +331121,青田县,4,331100 +331122,缙云县,4,331100 +331123,遂昌县,4,331100 +331124,松阳县,4,331100 +331125,云和县,4,331100 +331126,庆元县,4,331100 +331127,景宁畲族自治县,4,331100 +331181,龙泉市,4,331100 +340102,瑶海区,4,340100 +340103,庐阳区,4,340100 +340104,蜀山区,4,340100 +340111,包河区,4,340100 +340121,长丰县,4,340100 +340122,肥东县,4,340100 +340123,肥西县,4,340100 +340124,庐江县,4,340100 +340171,合肥高新技术产业开发区,4,340100 +340172,合肥经济技术开发区,4,340100 +340173,合肥新站高新技术产业开发区,4,340100 +340181,巢湖市,4,340100 +340202,镜湖区,4,340200 +340207,鸠江区,4,340200 +340209,弋江区,4,340200 +340210,湾沚区,4,340200 +340212,繁昌区,4,340200 +340223,南陵县,4,340200 +340271,芜湖经济技术开发区,4,340200 +340272,安徽芜湖三山经济开发区,4,340200 +340281,无为市,4,340200 +340302,龙子湖区,4,340300 +340303,蚌山区,4,340300 +340304,禹会区,4,340300 +340311,淮上区,4,340300 +340321,怀远县,4,340300 +340322,五河县,4,340300 +340323,固镇县,4,340300 +340371,蚌埠市高新技术开发区,4,340300 +340372,蚌埠市经济开发区,4,340300 +340402,大通区,4,340400 +340403,田家庵区,4,340400 +340404,谢家集区,4,340400 +340405,八公山区,4,340400 +340406,潘集区,4,340400 +340421,凤台县,4,340400 +340422,寿县,4,340400 +340503,花山区,4,340500 +340504,雨山区,4,340500 +340506,博望区,4,340500 +340521,当涂县,4,340500 +340522,含山县,4,340500 +340523,和县,4,340500 +340602,杜集区,4,340600 +340603,相山区,4,340600 +340604,烈山区,4,340600 +340621,濉溪县,4,340600 +340705,铜官区,4,340700 +340706,义安区,4,340700 +340711,郊区,4,340700 +340722,枞阳县,4,340700 +340802,迎江区,4,340800 +340803,大观区,4,340800 +340811,宜秀区,4,340800 +340822,怀宁县,4,340800 +340825,太湖县,4,340800 +340826,宿松县,4,340800 +340827,望江县,4,340800 +340828,岳西县,4,340800 +340871,安徽安庆经济开发区,4,340800 +340881,桐城市,4,340800 +340882,潜山市,4,340800 +341002,屯溪区,4,341000 +341003,黄山区,4,341000 +341004,徽州区,4,341000 +341021,歙县,4,341000 +341022,休宁县,4,341000 +341023,黟县,4,341000 +341024,祁门县,4,341000 +341102,琅琊区,4,341100 +341103,南谯区,4,341100 +341122,来安县,4,341100 +341124,全椒县,4,341100 +341125,定远县,4,341100 +341126,凤阳县,4,341100 +341171,中新苏滁高新技术产业开发区,4,341100 +341172,滁州经济技术开发区,4,341100 +341181,天长市,4,341100 +341182,明光市,4,341100 +341202,颍州区,4,341200 +341203,颍东区,4,341200 +341204,颍泉区,4,341200 +341221,临泉县,4,341200 +341222,太和县,4,341200 +341225,阜南县,4,341200 +341226,颍上县,4,341200 +341271,阜阳合肥现代产业园区,4,341200 +341272,阜阳经济技术开发区,4,341200 +341282,界首市,4,341200 +341302,埇桥区,4,341300 +341321,砀山县,4,341300 +341322,萧县,4,341300 +341323,灵璧县,4,341300 +341324,泗县,4,341300 +341371,宿州马鞍山现代产业园区,4,341300 +341372,宿州经济技术开发区,4,341300 +341502,金安区,4,341500 +341503,裕安区,4,341500 +341504,叶集区,4,341500 +341522,霍邱县,4,341500 +341523,舒城县,4,341500 +341524,金寨县,4,341500 +341525,霍山县,4,341500 +341602,谯城区,4,341600 +341621,涡阳县,4,341600 +341622,蒙城县,4,341600 +341623,利辛县,4,341600 +341702,贵池区,4,341700 +341721,东至县,4,341700 +341722,石台县,4,341700 +341723,青阳县,4,341700 +341802,宣州区,4,341800 +341821,郎溪县,4,341800 +341823,泾县,4,341800 +341824,绩溪县,4,341800 +341825,旌德县,4,341800 +341871,宣城市经济开发区,4,341800 +341881,宁国市,4,341800 +341882,广德市,4,341800 +350102,鼓楼区,4,350100 +350103,台江区,4,350100 +350104,仓山区,4,350100 +350105,马尾区,4,350100 +350111,晋安区,4,350100 +350112,长乐区,4,350100 +350121,闽侯县,4,350100 +350122,连江县,4,350100 +350123,罗源县,4,350100 +350124,闽清县,4,350100 +350125,永泰县,4,350100 +350128,平潭县,4,350100 +350181,福清市,4,350100 +350203,思明区,4,350200 +350205,海沧区,4,350200 +350206,湖里区,4,350200 +350211,集美区,4,350200 +350212,同安区,4,350200 +350213,翔安区,4,350200 +350302,城厢区,4,350300 +350303,涵江区,4,350300 +350304,荔城区,4,350300 +350305,秀屿区,4,350300 +350322,仙游县,4,350300 +350404,三元区,4,350400 +350405,沙县区,4,350400 +350421,明溪县,4,350400 +350423,清流县,4,350400 +350424,宁化县,4,350400 +350425,大田县,4,350400 +350426,尤溪县,4,350400 +350428,将乐县,4,350400 +350429,泰宁县,4,350400 +350430,建宁县,4,350400 +350481,永安市,4,350400 +350502,鲤城区,4,350500 +350503,丰泽区,4,350500 +350504,洛江区,4,350500 +350505,泉港区,4,350500 +350521,惠安县,4,350500 +350524,安溪县,4,350500 +350525,永春县,4,350500 +350526,德化县,4,350500 +350527,金门县,4,350500 +350581,石狮市,4,350500 +350582,晋江市,4,350500 +350583,南安市,4,350500 +350602,芗城区,4,350600 +350603,龙文区,4,350600 +350604,龙海区,4,350600 +350605,长泰区,4,350600 +350622,云霄县,4,350600 +350623,漳浦县,4,350600 +350624,诏安县,4,350600 +350626,东山县,4,350600 +350627,南靖县,4,350600 +350628,平和县,4,350600 +350629,华安县,4,350600 +350702,延平区,4,350700 +350703,建阳区,4,350700 +350721,顺昌县,4,350700 +350722,浦城县,4,350700 +350723,光泽县,4,350700 +350724,松溪县,4,350700 +350725,政和县,4,350700 +350781,邵武市,4,350700 +350782,武夷山市,4,350700 +350783,建瓯市,4,350700 +350802,新罗区,4,350800 +350803,永定区,4,350800 +350821,长汀县,4,350800 +350823,上杭县,4,350800 +350824,武平县,4,350800 +350825,连城县,4,350800 +350881,漳平市,4,350800 +350902,蕉城区,4,350900 +350921,霞浦县,4,350900 +350922,古田县,4,350900 +350923,屏南县,4,350900 +350924,寿宁县,4,350900 +350925,周宁县,4,350900 +350926,柘荣县,4,350900 +350981,福安市,4,350900 +350982,福鼎市,4,350900 +360102,东湖区,4,360100 +360103,西湖区,4,360100 +360104,青云谱区,4,360100 +360111,青山湖区,4,360100 +360112,新建区,4,360100 +360113,红谷滩区,4,360100 +360121,南昌县,4,360100 +360123,安义县,4,360100 +360124,进贤县,4,360100 +360202,昌江区,4,360200 +360203,珠山区,4,360200 +360222,浮梁县,4,360200 +360281,乐平市,4,360200 +360302,安源区,4,360300 +360313,湘东区,4,360300 +360321,莲花县,4,360300 +360322,上栗县,4,360300 +360323,芦溪县,4,360300 +360402,濂溪区,4,360400 +360403,浔阳区,4,360400 +360404,柴桑区,4,360400 +360423,武宁县,4,360400 +360424,修水县,4,360400 +360425,永修县,4,360400 +360426,德安县,4,360400 +360428,都昌县,4,360400 +360429,湖口县,4,360400 +360430,彭泽县,4,360400 +360481,瑞昌市,4,360400 +360482,共青城市,4,360400 +360483,庐山市,4,360400 +360502,渝水区,4,360500 +360521,分宜县,4,360500 +360602,月湖区,4,360600 +360603,余江区,4,360600 +360681,贵溪市,4,360600 +360702,章贡区,4,360700 +360703,南康区,4,360700 +360704,赣县区,4,360700 +360722,信丰县,4,360700 +360723,大余县,4,360700 +360724,上犹县,4,360700 +360725,崇义县,4,360700 +360726,安远县,4,360700 +360728,定南县,4,360700 +360729,全南县,4,360700 +360730,宁都县,4,360700 +360731,于都县,4,360700 +360732,兴国县,4,360700 +360733,会昌县,4,360700 +360734,寻乌县,4,360700 +360735,石城县,4,360700 +360781,瑞金市,4,360700 +360783,龙南市,4,360700 +360802,吉州区,4,360800 +360803,青原区,4,360800 +360821,吉安县,4,360800 +360822,吉水县,4,360800 +360823,峡江县,4,360800 +360824,新干县,4,360800 +360825,永丰县,4,360800 +360826,泰和县,4,360800 +360827,遂川县,4,360800 +360828,万安县,4,360800 +360829,安福县,4,360800 +360830,永新县,4,360800 +360881,井冈山市,4,360800 +360902,袁州区,4,360900 +360921,奉新县,4,360900 +360922,万载县,4,360900 +360923,上高县,4,360900 +360924,宜丰县,4,360900 +360925,靖安县,4,360900 +360926,铜鼓县,4,360900 +360981,丰城市,4,360900 +360982,樟树市,4,360900 +360983,高安市,4,360900 +361002,临川区,4,361000 +361003,东乡区,4,361000 +361021,南城县,4,361000 +361022,黎川县,4,361000 +361023,南丰县,4,361000 +361024,崇仁县,4,361000 +361025,乐安县,4,361000 +361026,宜黄县,4,361000 +361027,金溪县,4,361000 +361028,资溪县,4,361000 +361030,广昌县,4,361000 +361102,信州区,4,361100 +361103,广丰区,4,361100 +361104,广信区,4,361100 +361123,玉山县,4,361100 +361124,铅山县,4,361100 +361125,横峰县,4,361100 +361126,弋阳县,4,361100 +361127,余干县,4,361100 +361128,鄱阳县,4,361100 +361129,万年县,4,361100 +361130,婺源县,4,361100 +361181,德兴市,4,361100 +370102,历下区,4,370100 +370103,市中区,4,370100 +370104,槐荫区,4,370100 +370105,天桥区,4,370100 +370112,历城区,4,370100 +370113,长清区,4,370100 +370114,章丘区,4,370100 +370115,济阳区,4,370100 +370116,莱芜区,4,370100 +370117,钢城区,4,370100 +370124,平阴县,4,370100 +370126,商河县,4,370100 +370171,济南高新技术产业开发区,4,370100 +370202,市南区,4,370200 +370203,市北区,4,370200 +370211,黄岛区,4,370200 +370212,崂山区,4,370200 +370213,李沧区,4,370200 +370214,城阳区,4,370200 +370215,即墨区,4,370200 +370271,青岛高新技术产业开发区,4,370200 +370281,胶州市,4,370200 +370283,平度市,4,370200 +370285,莱西市,4,370200 +370302,淄川区,4,370300 +370303,张店区,4,370300 +370304,博山区,4,370300 +370305,临淄区,4,370300 +370306,周村区,4,370300 +370321,桓台县,4,370300 +370322,高青县,4,370300 +370323,沂源县,4,370300 +370402,市中区,4,370400 +370403,薛城区,4,370400 +370404,峄城区,4,370400 +370405,台儿庄区,4,370400 +370406,山亭区,4,370400 +370481,滕州市,4,370400 +370502,东营区,4,370500 +370503,河口区,4,370500 +370505,垦利区,4,370500 +370522,利津县,4,370500 +370523,广饶县,4,370500 +370571,东营经济技术开发区,4,370500 +370572,东营港经济开发区,4,370500 +370602,芝罘区,4,370600 +370611,福山区,4,370600 +370612,牟平区,4,370600 +370613,莱山区,4,370600 +370614,蓬莱区,4,370600 +370671,烟台高新技术产业开发区,4,370600 +370672,烟台经济技术开发区,4,370600 +370681,龙口市,4,370600 +370682,莱阳市,4,370600 +370683,莱州市,4,370600 +370685,招远市,4,370600 +370686,栖霞市,4,370600 +370687,海阳市,4,370600 +370702,潍城区,4,370700 +370703,寒亭区,4,370700 +370704,坊子区,4,370700 +370705,奎文区,4,370700 +370724,临朐县,4,370700 +370725,昌乐县,4,370700 +370772,潍坊滨海经济技术开发区,4,370700 +370781,青州市,4,370700 +370782,诸城市,4,370700 +370783,寿光市,4,370700 +370784,安丘市,4,370700 +370785,高密市,4,370700 +370786,昌邑市,4,370700 +370811,任城区,4,370800 +370812,兖州区,4,370800 +370826,微山县,4,370800 +370827,鱼台县,4,370800 +370828,金乡县,4,370800 +370829,嘉祥县,4,370800 +370830,汶上县,4,370800 +370831,泗水县,4,370800 +370832,梁山县,4,370800 +370871,济宁高新技术产业开发区,4,370800 +370881,曲阜市,4,370800 +370883,邹城市,4,370800 +370902,泰山区,4,370900 +370911,岱岳区,4,370900 +370921,宁阳县,4,370900 +370923,东平县,4,370900 +370982,新泰市,4,370900 +370983,肥城市,4,370900 +371002,环翠区,4,371000 +371003,文登区,4,371000 +371071,威海火炬高技术产业开发区,4,371000 +371072,威海经济技术开发区,4,371000 +371073,威海临港经济技术开发区,4,371000 +371082,荣成市,4,371000 +371083,乳山市,4,371000 +371102,东港区,4,371100 +371103,岚山区,4,371100 +371121,五莲县,4,371100 +371122,莒县,4,371100 +371171,日照经济技术开发区,4,371100 +371302,兰山区,4,371300 +371311,罗庄区,4,371300 +371312,河东区,4,371300 +371321,沂南县,4,371300 +371322,郯城县,4,371300 +371323,沂水县,4,371300 +371324,兰陵县,4,371300 +371325,费县,4,371300 +371326,平邑县,4,371300 +371327,莒南县,4,371300 +371328,蒙阴县,4,371300 +371329,临沭县,4,371300 +371371,临沂高新技术产业开发区,4,371300 +371402,德城区,4,371400 +371403,陵城区,4,371400 +371422,宁津县,4,371400 +371423,庆云县,4,371400 +371424,临邑县,4,371400 +371425,齐河县,4,371400 +371426,平原县,4,371400 +371427,夏津县,4,371400 +371428,武城县,4,371400 +371471,德州经济技术开发区,4,371400 +371472,德州运河经济开发区,4,371400 +371481,乐陵市,4,371400 +371482,禹城市,4,371400 +371502,东昌府区,4,371500 +371503,茌平区,4,371500 +371521,阳谷县,4,371500 +371522,莘县,4,371500 +371524,东阿县,4,371500 +371525,冠县,4,371500 +371526,高唐县,4,371500 +371581,临清市,4,371500 +371602,滨城区,4,371600 +371603,沾化区,4,371600 +371621,惠民县,4,371600 +371622,阳信县,4,371600 +371623,无棣县,4,371600 +371625,博兴县,4,371600 +371681,邹平市,4,371600 +371702,牡丹区,4,371700 +371703,定陶区,4,371700 +371721,曹县,4,371700 +371722,单县,4,371700 +371723,成武县,4,371700 +371724,巨野县,4,371700 +371725,郓城县,4,371700 +371726,鄄城县,4,371700 +371728,东明县,4,371700 +371771,菏泽经济技术开发区,4,371700 +371772,菏泽高新技术开发区,4,371700 +410102,中原区,4,410100 +410103,二七区,4,410100 +410104,管城回族区,4,410100 +410105,金水区,4,410100 +410106,上街区,4,410100 +410108,惠济区,4,410100 +410122,中牟县,4,410100 +410171,郑州经济技术开发区,4,410100 +410172,郑州高新技术产业开发区,4,410100 +410173,郑州航空港经济综合实验区,4,410100 +410181,巩义市,4,410100 +410182,荥阳市,4,410100 +410183,新密市,4,410100 +410184,新郑市,4,410100 +410185,登封市,4,410100 +410202,龙亭区,4,410200 +410203,顺河回族区,4,410200 +410204,鼓楼区,4,410200 +410205,禹王台区,4,410200 +410212,祥符区,4,410200 +410221,杞县,4,410200 +410222,通许县,4,410200 +410223,尉氏县,4,410200 +410225,兰考县,4,410200 +410302,老城区,4,410300 +410303,西工区,4,410300 +410304,瀍河回族区,4,410300 +410305,涧西区,4,410300 +410307,偃师区,4,410300 +410308,孟津区,4,410300 +410311,洛龙区,4,410300 +410323,新安县,4,410300 +410324,栾川县,4,410300 +410325,嵩县,4,410300 +410326,汝阳县,4,410300 +410327,宜阳县,4,410300 +410328,洛宁县,4,410300 +410329,伊川县,4,410300 +410371,洛阳高新技术产业开发区,4,410300 +410402,新华区,4,410400 +410403,卫东区,4,410400 +410404,石龙区,4,410400 +410411,湛河区,4,410400 +410421,宝丰县,4,410400 +410422,叶县,4,410400 +410423,鲁山县,4,410400 +410425,郏县,4,410400 +410471,平顶山高新技术产业开发区,4,410400 +410472,平顶山市城乡一体化示范区,4,410400 +410481,舞钢市,4,410400 +410482,汝州市,4,410400 +410502,文峰区,4,410500 +410503,北关区,4,410500 +410505,殷都区,4,410500 +410506,龙安区,4,410500 +410522,安阳县,4,410500 +410523,汤阴县,4,410500 +410526,滑县,4,410500 +410527,内黄县,4,410500 +410571,安阳高新技术产业开发区,4,410500 +410581,林州市,4,410500 +410602,鹤山区,4,410600 +410603,山城区,4,410600 +410611,淇滨区,4,410600 +410621,浚县,4,410600 +410622,淇县,4,410600 +410671,鹤壁经济技术开发区,4,410600 +410702,红旗区,4,410700 +410703,卫滨区,4,410700 +410704,凤泉区,4,410700 +410711,牧野区,4,410700 +410721,新乡县,4,410700 +410724,获嘉县,4,410700 +410725,原阳县,4,410700 +410726,延津县,4,410700 +410727,封丘县,4,410700 +410771,新乡高新技术产业开发区,4,410700 +410772,新乡经济技术开发区,4,410700 +410773,新乡市平原城乡一体化示范区,4,410700 +410781,卫辉市,4,410700 +410782,辉县市,4,410700 +410783,长垣市,4,410700 +410802,解放区,4,410800 +410803,中站区,4,410800 +410804,马村区,4,410800 +410811,山阳区,4,410800 +410821,修武县,4,410800 +410822,博爱县,4,410800 +410823,武陟县,4,410800 +410825,温县,4,410800 +410871,焦作城乡一体化示范区,4,410800 +410882,沁阳市,4,410800 +410883,孟州市,4,410800 +410902,华龙区,4,410900 +410922,清丰县,4,410900 +410923,南乐县,4,410900 +410926,范县,4,410900 +410927,台前县,4,410900 +410928,濮阳县,4,410900 +410971,河南濮阳工业园区,4,410900 +410972,濮阳经济技术开发区,4,410900 +411002,魏都区,4,411000 +411003,建安区,4,411000 +411024,鄢陵县,4,411000 +411025,襄城县,4,411000 +411071,许昌经济技术开发区,4,411000 +411081,禹州市,4,411000 +411082,长葛市,4,411000 +411102,源汇区,4,411100 +411103,郾城区,4,411100 +411104,召陵区,4,411100 +411121,舞阳县,4,411100 +411122,临颍县,4,411100 +411171,漯河经济技术开发区,4,411100 +411202,湖滨区,4,411200 +411203,陕州区,4,411200 +411221,渑池县,4,411200 +411224,卢氏县,4,411200 +411271,河南三门峡经济开发区,4,411200 +411281,义马市,4,411200 +411282,灵宝市,4,411200 +411302,宛城区,4,411300 +411303,卧龙区,4,411300 +411321,南召县,4,411300 +411322,方城县,4,411300 +411323,西峡县,4,411300 +411324,镇平县,4,411300 +411325,内乡县,4,411300 +411326,淅川县,4,411300 +411327,社旗县,4,411300 +411328,唐河县,4,411300 +411329,新野县,4,411300 +411330,桐柏县,4,411300 +411371,南阳高新技术产业开发区,4,411300 +411372,南阳市城乡一体化示范区,4,411300 +411381,邓州市,4,411300 +411402,梁园区,4,411400 +411403,睢阳区,4,411400 +411421,民权县,4,411400 +411422,睢县,4,411400 +411423,宁陵县,4,411400 +411424,柘城县,4,411400 +411425,虞城县,4,411400 +411426,夏邑县,4,411400 +411471,豫东综合物流产业聚集区,4,411400 +411472,河南商丘经济开发区,4,411400 +411481,永城市,4,411400 +411502,浉河区,4,411500 +411503,平桥区,4,411500 +411521,罗山县,4,411500 +411522,光山县,4,411500 +411523,新县,4,411500 +411524,商城县,4,411500 +411525,固始县,4,411500 +411526,潢川县,4,411500 +411527,淮滨县,4,411500 +411528,息县,4,411500 +411571,信阳高新技术产业开发区,4,411500 +411602,川汇区,4,411600 +411603,淮阳区,4,411600 +411621,扶沟县,4,411600 +411622,西华县,4,411600 +411623,商水县,4,411600 +411624,沈丘县,4,411600 +411625,郸城县,4,411600 +411627,太康县,4,411600 +411628,鹿邑县,4,411600 +411671,河南周口经济开发区,4,411600 +411681,项城市,4,411600 +411702,驿城区,4,411700 +411721,西平县,4,411700 +411722,上蔡县,4,411700 +411723,平舆县,4,411700 +411724,正阳县,4,411700 +411725,确山县,4,411700 +411726,泌阳县,4,411700 +411727,汝南县,4,411700 +411728,遂平县,4,411700 +411729,新蔡县,4,411700 +411771,河南驻马店经济开发区,4,411700 +419001,济源市,4,419000 +420102,江岸区,4,420100 +420103,江汉区,4,420100 +420104,硚口区,4,420100 +420105,汉阳区,4,420100 +420106,武昌区,4,420100 +420107,青山区,4,420100 +420111,洪山区,4,420100 +420112,东西湖区,4,420100 +420113,汉南区,4,420100 +420114,蔡甸区,4,420100 +420115,江夏区,4,420100 +420116,黄陂区,4,420100 +420117,新洲区,4,420100 +420202,黄石港区,4,420200 +420203,西塞山区,4,420200 +420204,下陆区,4,420200 +420205,铁山区,4,420200 +420222,阳新县,4,420200 +420281,大冶市,4,420200 +420302,茅箭区,4,420300 +420303,张湾区,4,420300 +420304,郧阳区,4,420300 +420322,郧西县,4,420300 +420323,竹山县,4,420300 +420324,竹溪县,4,420300 +420325,房县,4,420300 +420381,丹江口市,4,420300 +420502,西陵区,4,420500 +420503,伍家岗区,4,420500 +420504,点军区,4,420500 +420505,猇亭区,4,420500 +420506,夷陵区,4,420500 +420525,远安县,4,420500 +420526,兴山县,4,420500 +420527,秭归县,4,420500 +420528,长阳土家族自治县,4,420500 +420529,五峰土家族自治县,4,420500 +420581,宜都市,4,420500 +420582,当阳市,4,420500 +420583,枝江市,4,420500 +420602,襄城区,4,420600 +420606,樊城区,4,420600 +420607,襄州区,4,420600 +420624,南漳县,4,420600 +420625,谷城县,4,420600 +420626,保康县,4,420600 +420682,老河口市,4,420600 +420683,枣阳市,4,420600 +420684,宜城市,4,420600 +420702,梁子湖区,4,420700 +420703,华容区,4,420700 +420704,鄂城区,4,420700 +420802,东宝区,4,420800 +420804,掇刀区,4,420800 +420822,沙洋县,4,420800 +420881,钟祥市,4,420800 +420882,京山市,4,420800 +420902,孝南区,4,420900 +420921,孝昌县,4,420900 +420922,大悟县,4,420900 +420923,云梦县,4,420900 +420981,应城市,4,420900 +420982,安陆市,4,420900 +420984,汉川市,4,420900 +421002,沙市区,4,421000 +421003,荆州区,4,421000 +421022,公安县,4,421000 +421024,江陵县,4,421000 +421071,荆州经济技术开发区,4,421000 +421081,石首市,4,421000 +421083,洪湖市,4,421000 +421087,松滋市,4,421000 +421088,监利市,4,421000 +421102,黄州区,4,421100 +421121,团风县,4,421100 +421122,红安县,4,421100 +421123,罗田县,4,421100 +421124,英山县,4,421100 +421125,浠水县,4,421100 +421126,蕲春县,4,421100 +421127,黄梅县,4,421100 +421171,龙感湖管理区,4,421100 +421181,麻城市,4,421100 +421182,武穴市,4,421100 +421202,咸安区,4,421200 +421221,嘉鱼县,4,421200 +421222,通城县,4,421200 +421223,崇阳县,4,421200 +421224,通山县,4,421200 +421281,赤壁市,4,421200 +421303,曾都区,4,421300 +421321,随县,4,421300 +421381,广水市,4,421300 +422801,恩施市,4,422800 +422802,利川市,4,422800 +422822,建始县,4,422800 +422823,巴东县,4,422800 +422825,宣恩县,4,422800 +422826,咸丰县,4,422800 +422827,来凤县,4,422800 +422828,鹤峰县,4,422800 +429004,仙桃市,4,429000 +429005,潜江市,4,429000 +429006,天门市,4,429000 +429021,神农架林区,4,429000 +430102,芙蓉区,4,430100 +430103,天心区,4,430100 +430104,岳麓区,4,430100 +430105,开福区,4,430100 +430111,雨花区,4,430100 +430112,望城区,4,430100 +430121,长沙县,4,430100 +430181,浏阳市,4,430100 +430182,宁乡市,4,430100 +430202,荷塘区,4,430200 +430203,芦淞区,4,430200 +430204,石峰区,4,430200 +430211,天元区,4,430200 +430212,渌口区,4,430200 +430223,攸县,4,430200 +430224,茶陵县,4,430200 +430225,炎陵县,4,430200 +430271,云龙示范区,4,430200 +430281,醴陵市,4,430200 +430302,雨湖区,4,430300 +430304,岳塘区,4,430300 +430321,湘潭县,4,430300 +430371,湖南湘潭高新技术产业园区,4,430300 +430372,湘潭昭山示范区,4,430300 +430373,湘潭九华示范区,4,430300 +430381,湘乡市,4,430300 +430382,韶山市,4,430300 +430405,珠晖区,4,430400 +430406,雁峰区,4,430400 +430407,石鼓区,4,430400 +430408,蒸湘区,4,430400 +430412,南岳区,4,430400 +430421,衡阳县,4,430400 +430422,衡南县,4,430400 +430423,衡山县,4,430400 +430424,衡东县,4,430400 +430426,祁东县,4,430400 +430471,衡阳综合保税区,4,430400 +430472,湖南衡阳高新技术产业园区,4,430400 +430473,湖南衡阳松木经济开发区,4,430400 +430481,耒阳市,4,430400 +430482,常宁市,4,430400 +430502,双清区,4,430500 +430503,大祥区,4,430500 +430511,北塔区,4,430500 +430522,新邵县,4,430500 +430523,邵阳县,4,430500 +430524,隆回县,4,430500 +430525,洞口县,4,430500 +430527,绥宁县,4,430500 +430528,新宁县,4,430500 +430529,城步苗族自治县,4,430500 +430581,武冈市,4,430500 +430582,邵东市,4,430500 +430602,岳阳楼区,4,430600 +430603,云溪区,4,430600 +430611,君山区,4,430600 +430621,岳阳县,4,430600 +430623,华容县,4,430600 +430624,湘阴县,4,430600 +430626,平江县,4,430600 +430671,岳阳市屈原管理区,4,430600 +430681,汨罗市,4,430600 +430682,临湘市,4,430600 +430702,武陵区,4,430700 +430703,鼎城区,4,430700 +430721,安乡县,4,430700 +430722,汉寿县,4,430700 +430723,澧县,4,430700 +430724,临澧县,4,430700 +430725,桃源县,4,430700 +430726,石门县,4,430700 +430771,常德市西洞庭管理区,4,430700 +430781,津市市,4,430700 +430802,永定区,4,430800 +430811,武陵源区,4,430800 +430821,慈利县,4,430800 +430822,桑植县,4,430800 +430902,资阳区,4,430900 +430903,赫山区,4,430900 +430921,南县,4,430900 +430922,桃江县,4,430900 +430923,安化县,4,430900 +430971,益阳市大通湖管理区,4,430900 +430972,湖南益阳高新技术产业园区,4,430900 +430981,沅江市,4,430900 +431002,北湖区,4,431000 +431003,苏仙区,4,431000 +431021,桂阳县,4,431000 +431022,宜章县,4,431000 +431023,永兴县,4,431000 +431024,嘉禾县,4,431000 +431025,临武县,4,431000 +431026,汝城县,4,431000 +431027,桂东县,4,431000 +431028,安仁县,4,431000 +431081,资兴市,4,431000 +431102,零陵区,4,431100 +431103,冷水滩区,4,431100 +431122,东安县,4,431100 +431123,双牌县,4,431100 +431124,道县,4,431100 +431125,江永县,4,431100 +431126,宁远县,4,431100 +431127,蓝山县,4,431100 +431128,新田县,4,431100 +431129,江华瑶族自治县,4,431100 +431171,永州经济技术开发区,4,431100 +431173,永州市回龙圩管理区,4,431100 +431181,祁阳市,4,431100 +431202,鹤城区,4,431200 +431221,中方县,4,431200 +431222,沅陵县,4,431200 +431223,辰溪县,4,431200 +431224,溆浦县,4,431200 +431225,会同县,4,431200 +431226,麻阳苗族自治县,4,431200 +431227,新晃侗族自治县,4,431200 +431228,芷江侗族自治县,4,431200 +431229,靖州苗族侗族自治县,4,431200 +431230,通道侗族自治县,4,431200 +431271,怀化市洪江管理区,4,431200 +431281,洪江市,4,431200 +431302,娄星区,4,431300 +431321,双峰县,4,431300 +431322,新化县,4,431300 +431381,冷水江市,4,431300 +431382,涟源市,4,431300 +433101,吉首市,4,433100 +433122,泸溪县,4,433100 +433123,凤凰县,4,433100 +433124,花垣县,4,433100 +433125,保靖县,4,433100 +433126,古丈县,4,433100 +433127,永顺县,4,433100 +433130,龙山县,4,433100 +440103,荔湾区,4,440100 +440104,越秀区,4,440100 +440105,海珠区,4,440100 +440106,天河区,4,440100 +440111,白云区,4,440100 +440112,黄埔区,4,440100 +440113,番禺区,4,440100 +440114,花都区,4,440100 +440115,南沙区,4,440100 +440117,从化区,4,440100 +440118,增城区,4,440100 +440203,武江区,4,440200 +440204,浈江区,4,440200 +440205,曲江区,4,440200 +440222,始兴县,4,440200 +440224,仁化县,4,440200 +440229,翁源县,4,440200 +440232,乳源瑶族自治县,4,440200 +440233,新丰县,4,440200 +440281,乐昌市,4,440200 +440282,南雄市,4,440200 +440303,罗湖区,4,440300 +440304,福田区,4,440300 +440305,南山区,4,440300 +440306,宝安区,4,440300 +440307,龙岗区,4,440300 +440308,盐田区,4,440300 +440309,龙华区,4,440300 +440310,坪山区,4,440300 +440311,光明区,4,440300 +440402,香洲区,4,440400 +440403,斗门区,4,440400 +440404,金湾区,4,440400 +440507,龙湖区,4,440500 +440511,金平区,4,440500 +440512,濠江区,4,440500 +440513,潮阳区,4,440500 +440514,潮南区,4,440500 +440515,澄海区,4,440500 +440523,南澳县,4,440500 +440604,禅城区,4,440600 +440605,南海区,4,440600 +440606,顺德区,4,440600 +440607,三水区,4,440600 +440608,高明区,4,440600 +440703,蓬江区,4,440700 +440704,江海区,4,440700 +440705,新会区,4,440700 +440781,台山市,4,440700 +440783,开平市,4,440700 +440784,鹤山市,4,440700 +440785,恩平市,4,440700 +440802,赤坎区,4,440800 +440803,霞山区,4,440800 +440804,坡头区,4,440800 +440811,麻章区,4,440800 +440823,遂溪县,4,440800 +440825,徐闻县,4,440800 +440881,廉江市,4,440800 +440882,雷州市,4,440800 +440883,吴川市,4,440800 +440902,茂南区,4,440900 +440904,电白区,4,440900 +440981,高州市,4,440900 +440982,化州市,4,440900 +440983,信宜市,4,440900 +441202,端州区,4,441200 +441203,鼎湖区,4,441200 +441204,高要区,4,441200 +441223,广宁县,4,441200 +441224,怀集县,4,441200 +441225,封开县,4,441200 +441226,德庆县,4,441200 +441284,四会市,4,441200 +441302,惠城区,4,441300 +441303,惠阳区,4,441300 +441322,博罗县,4,441300 +441323,惠东县,4,441300 +441324,龙门县,4,441300 +441402,梅江区,4,441400 +441403,梅县区,4,441400 +441422,大埔县,4,441400 +441423,丰顺县,4,441400 +441424,五华县,4,441400 +441426,平远县,4,441400 +441427,蕉岭县,4,441400 +441481,兴宁市,4,441400 +441502,城区,4,441500 +441521,海丰县,4,441500 +441523,陆河县,4,441500 +441581,陆丰市,4,441500 +441602,源城区,4,441600 +441621,紫金县,4,441600 +441622,龙川县,4,441600 +441623,连平县,4,441600 +441624,和平县,4,441600 +441625,东源县,4,441600 +441702,江城区,4,441700 +441704,阳东区,4,441700 +441721,阳西县,4,441700 +441781,阳春市,4,441700 +441802,清城区,4,441800 +441803,清新区,4,441800 +441821,佛冈县,4,441800 +441823,阳山县,4,441800 +441825,连山壮族瑶族自治县,4,441800 +441826,连南瑶族自治县,4,441800 +441881,英德市,4,441800 +441882,连州市,4,441800 +445102,湘桥区,4,445100 +445103,潮安区,4,445100 +445122,饶平县,4,445100 +445202,榕城区,4,445200 +445203,揭东区,4,445200 +445222,揭西县,4,445200 +445224,惠来县,4,445200 +445281,普宁市,4,445200 +445302,云城区,4,445300 +445303,云安区,4,445300 +445321,新兴县,4,445300 +445322,郁南县,4,445300 +445381,罗定市,4,445300 +450102,兴宁区,4,450100 +450103,青秀区,4,450100 +450105,江南区,4,450100 +450107,西乡塘区,4,450100 +450108,良庆区,4,450100 +450109,邕宁区,4,450100 +450110,武鸣区,4,450100 +450123,隆安县,4,450100 +450124,马山县,4,450100 +450125,上林县,4,450100 +450126,宾阳县,4,450100 +450181,横州市,4,450100 +450202,城中区,4,450200 +450203,鱼峰区,4,450200 +450204,柳南区,4,450200 +450205,柳北区,4,450200 +450206,柳江区,4,450200 +450222,柳城县,4,450200 +450223,鹿寨县,4,450200 +450224,融安县,4,450200 +450225,融水苗族自治县,4,450200 +450226,三江侗族自治县,4,450200 +450302,秀峰区,4,450300 +450303,叠彩区,4,450300 +450304,象山区,4,450300 +450305,七星区,4,450300 +450311,雁山区,4,450300 +450312,临桂区,4,450300 +450321,阳朔县,4,450300 +450323,灵川县,4,450300 +450324,全州县,4,450300 +450325,兴安县,4,450300 +450326,永福县,4,450300 +450327,灌阳县,4,450300 +450328,龙胜各族自治县,4,450300 +450329,资源县,4,450300 +450330,平乐县,4,450300 +450332,恭城瑶族自治县,4,450300 +450381,荔浦市,4,450300 +450403,万秀区,4,450400 +450405,长洲区,4,450400 +450406,龙圩区,4,450400 +450421,苍梧县,4,450400 +450422,藤县,4,450400 +450423,蒙山县,4,450400 +450481,岑溪市,4,450400 +450502,海城区,4,450500 +450503,银海区,4,450500 +450512,铁山港区,4,450500 +450521,合浦县,4,450500 +450602,港口区,4,450600 +450603,防城区,4,450600 +450621,上思县,4,450600 +450681,东兴市,4,450600 +450702,钦南区,4,450700 +450703,钦北区,4,450700 +450721,灵山县,4,450700 +450722,浦北县,4,450700 +450802,港北区,4,450800 +450803,港南区,4,450800 +450804,覃塘区,4,450800 +450821,平南县,4,450800 +450881,桂平市,4,450800 +450902,玉州区,4,450900 +450903,福绵区,4,450900 +450921,容县,4,450900 +450922,陆川县,4,450900 +450923,博白县,4,450900 +450924,兴业县,4,450900 +450981,北流市,4,450900 +451002,右江区,4,451000 +451003,田阳区,4,451000 +451022,田东县,4,451000 +451024,德保县,4,451000 +451026,那坡县,4,451000 +451027,凌云县,4,451000 +451028,乐业县,4,451000 +451029,田林县,4,451000 +451030,西林县,4,451000 +451031,隆林各族自治县,4,451000 +451081,靖西市,4,451000 +451082,平果市,4,451000 +451102,八步区,4,451100 +451103,平桂区,4,451100 +451121,昭平县,4,451100 +451122,钟山县,4,451100 +451123,富川瑶族自治县,4,451100 +451202,金城江区,4,451200 +451203,宜州区,4,451200 +451221,南丹县,4,451200 +451222,天峨县,4,451200 +451223,凤山县,4,451200 +451224,东兰县,4,451200 +451225,罗城仫佬族自治县,4,451200 +451226,环江毛南族自治县,4,451200 +451227,巴马瑶族自治县,4,451200 +451228,都安瑶族自治县,4,451200 +451229,大化瑶族自治县,4,451200 +451302,兴宾区,4,451300 +451321,忻城县,4,451300 +451322,象州县,4,451300 +451323,武宣县,4,451300 +451324,金秀瑶族自治县,4,451300 +451381,合山市,4,451300 +451402,江州区,4,451400 +451421,扶绥县,4,451400 +451422,宁明县,4,451400 +451423,龙州县,4,451400 +451424,大新县,4,451400 +451425,天等县,4,451400 +451481,凭祥市,4,451400 +460105,秀英区,4,460100 +460106,龙华区,4,460100 +460107,琼山区,4,460100 +460108,美兰区,4,460100 +460202,海棠区,4,460200 +460203,吉阳区,4,460200 +460204,天涯区,4,460200 +460205,崖州区,4,460200 +460321,西沙群岛,4,460300 +460322,南沙群岛,4,460300 +460323,中沙群岛的岛礁及其海域,4,460300 +469001,五指山市,4,469000 +469002,琼海市,4,469000 +469005,文昌市,4,469000 +469006,万宁市,4,469000 +469007,东方市,4,469000 +469021,定安县,4,469000 +469022,屯昌县,4,469000 +469023,澄迈县,4,469000 +469024,临高县,4,469000 +469025,白沙黎族自治县,4,469000 +469026,昌江黎族自治县,4,469000 +469027,乐东黎族自治县,4,469000 +469028,陵水黎族自治县,4,469000 +469029,保亭黎族苗族自治县,4,469000 +469030,琼中黎族苗族自治县,4,469000 +500101,万州区,4,500100 +500102,涪陵区,4,500100 +500103,渝中区,4,500100 +500104,大渡口区,4,500100 +500105,江北区,4,500100 +500106,沙坪坝区,4,500100 +500107,九龙坡区,4,500100 +500108,南岸区,4,500100 +500109,北碚区,4,500100 +500110,綦江区,4,500100 +500111,大足区,4,500100 +500112,渝北区,4,500100 +500113,巴南区,4,500100 +500114,黔江区,4,500100 +500115,长寿区,4,500100 +500116,江津区,4,500100 +500117,合川区,4,500100 +500118,永川区,4,500100 +500119,南川区,4,500100 +500120,璧山区,4,500100 +500151,铜梁区,4,500100 +500152,潼南区,4,500100 +500153,荣昌区,4,500100 +500154,开州区,4,500100 +500155,梁平区,4,500100 +500156,武隆区,4,500100 +500229,城口县,4,500100 +500230,丰都县,4,500100 +500231,垫江县,4,500100 +500233,忠县,4,500100 +500235,云阳县,4,500100 +500236,奉节县,4,500100 +500237,巫山县,4,500100 +500238,巫溪县,4,500100 +500240,石柱土家族自治县,4,500100 +500241,秀山土家族苗族自治县,4,500100 +500242,酉阳土家族苗族自治县,4,500100 +500243,彭水苗族土家族自治县,4,500100 +510104,锦江区,4,510100 +510105,青羊区,4,510100 +510106,金牛区,4,510100 +510107,武侯区,4,510100 +510108,成华区,4,510100 +510112,龙泉驿区,4,510100 +510113,青白江区,4,510100 +510114,新都区,4,510100 +510115,温江区,4,510100 +510116,双流区,4,510100 +510117,郫都区,4,510100 +510118,新津区,4,510100 +510121,金堂县,4,510100 +510129,大邑县,4,510100 +510131,蒲江县,4,510100 +510181,都江堰市,4,510100 +510182,彭州市,4,510100 +510183,邛崃市,4,510100 +510184,崇州市,4,510100 +510185,简阳市,4,510100 +510302,自流井区,4,510300 +510303,贡井区,4,510300 +510304,大安区,4,510300 +510311,沿滩区,4,510300 +510321,荣县,4,510300 +510322,富顺县,4,510300 +510402,东区,4,510400 +510403,西区,4,510400 +510411,仁和区,4,510400 +510421,米易县,4,510400 +510422,盐边县,4,510400 +510502,江阳区,4,510500 +510503,纳溪区,4,510500 +510504,龙马潭区,4,510500 +510521,泸县,4,510500 +510522,合江县,4,510500 +510524,叙永县,4,510500 +510525,古蔺县,4,510500 +510603,旌阳区,4,510600 +510604,罗江区,4,510600 +510623,中江县,4,510600 +510681,广汉市,4,510600 +510682,什邡市,4,510600 +510683,绵竹市,4,510600 +510703,涪城区,4,510700 +510704,游仙区,4,510700 +510705,安州区,4,510700 +510722,三台县,4,510700 +510723,盐亭县,4,510700 +510725,梓潼县,4,510700 +510726,北川羌族自治县,4,510700 +510727,平武县,4,510700 +510781,江油市,4,510700 +510802,利州区,4,510800 +510811,昭化区,4,510800 +510812,朝天区,4,510800 +510821,旺苍县,4,510800 +510822,青川县,4,510800 +510823,剑阁县,4,510800 +510824,苍溪县,4,510800 +510903,船山区,4,510900 +510904,安居区,4,510900 +510921,蓬溪县,4,510900 +510923,大英县,4,510900 +510981,射洪市,4,510900 +511002,市中区,4,511000 +511011,东兴区,4,511000 +511024,威远县,4,511000 +511025,资中县,4,511000 +511071,内江经济开发区,4,511000 +511083,隆昌市,4,511000 +511102,市中区,4,511100 +511111,沙湾区,4,511100 +511112,五通桥区,4,511100 +511113,金口河区,4,511100 +511123,犍为县,4,511100 +511124,井研县,4,511100 +511126,夹江县,4,511100 +511129,沐川县,4,511100 +511132,峨边彝族自治县,4,511100 +511133,马边彝族自治县,4,511100 +511181,峨眉山市,4,511100 +511302,顺庆区,4,511300 +511303,高坪区,4,511300 +511304,嘉陵区,4,511300 +511321,南部县,4,511300 +511322,营山县,4,511300 +511323,蓬安县,4,511300 +511324,仪陇县,4,511300 +511325,西充县,4,511300 +511381,阆中市,4,511300 +511402,东坡区,4,511400 +511403,彭山区,4,511400 +511421,仁寿县,4,511400 +511423,洪雅县,4,511400 +511424,丹棱县,4,511400 +511425,青神县,4,511400 +511502,翠屏区,4,511500 +511503,南溪区,4,511500 +511504,叙州区,4,511500 +511523,江安县,4,511500 +511524,长宁县,4,511500 +511525,高县,4,511500 +511526,珙县,4,511500 +511527,筠连县,4,511500 +511528,兴文县,4,511500 +511529,屏山县,4,511500 +511602,广安区,4,511600 +511603,前锋区,4,511600 +511621,岳池县,4,511600 +511622,武胜县,4,511600 +511623,邻水县,4,511600 +511681,华蓥市,4,511600 +511702,通川区,4,511700 +511703,达川区,4,511700 +511722,宣汉县,4,511700 +511723,开江县,4,511700 +511724,大竹县,4,511700 +511725,渠县,4,511700 +511771,达州经济开发区,4,511700 +511781,万源市,4,511700 +511802,雨城区,4,511800 +511803,名山区,4,511800 +511822,荥经县,4,511800 +511823,汉源县,4,511800 +511824,石棉县,4,511800 +511825,天全县,4,511800 +511826,芦山县,4,511800 +511827,宝兴县,4,511800 +511902,巴州区,4,511900 +511903,恩阳区,4,511900 +511921,通江县,4,511900 +511922,南江县,4,511900 +511923,平昌县,4,511900 +511971,巴中经济开发区,4,511900 +512002,雁江区,4,512000 +512021,安岳县,4,512000 +512022,乐至县,4,512000 +513201,马尔康市,4,513200 +513221,汶川县,4,513200 +513222,理县,4,513200 +513223,茂县,4,513200 +513224,松潘县,4,513200 +513225,九寨沟县,4,513200 +513226,金川县,4,513200 +513227,小金县,4,513200 +513228,黑水县,4,513200 +513230,壤塘县,4,513200 +513231,阿坝县,4,513200 +513232,若尔盖县,4,513200 +513233,红原县,4,513200 +513301,康定市,4,513300 +513322,泸定县,4,513300 +513323,丹巴县,4,513300 +513324,九龙县,4,513300 +513325,雅江县,4,513300 +513326,道孚县,4,513300 +513327,炉霍县,4,513300 +513328,甘孜县,4,513300 +513329,新龙县,4,513300 +513330,德格县,4,513300 +513331,白玉县,4,513300 +513332,石渠县,4,513300 +513333,色达县,4,513300 +513334,理塘县,4,513300 +513335,巴塘县,4,513300 +513336,乡城县,4,513300 +513337,稻城县,4,513300 +513338,得荣县,4,513300 +513401,西昌市,4,513400 +513402,会理市,4,513400 +513422,木里藏族自治县,4,513400 +513423,盐源县,4,513400 +513424,德昌县,4,513400 +513426,会东县,4,513400 +513427,宁南县,4,513400 +513428,普格县,4,513400 +513429,布拖县,4,513400 +513430,金阳县,4,513400 +513431,昭觉县,4,513400 +513432,喜德县,4,513400 +513433,冕宁县,4,513400 +513434,越西县,4,513400 +513435,甘洛县,4,513400 +513436,美姑县,4,513400 +513437,雷波县,4,513400 +520102,南明区,4,520100 +520103,云岩区,4,520100 +520111,花溪区,4,520100 +520112,乌当区,4,520100 +520113,白云区,4,520100 +520115,观山湖区,4,520100 +520121,开阳县,4,520100 +520122,息烽县,4,520100 +520123,修文县,4,520100 +520181,清镇市,4,520100 +520201,钟山区,4,520200 +520203,六枝特区,4,520200 +520204,水城区,4,520200 +520281,盘州市,4,520200 +520302,红花岗区,4,520300 +520303,汇川区,4,520300 +520304,播州区,4,520300 +520322,桐梓县,4,520300 +520323,绥阳县,4,520300 +520324,正安县,4,520300 +520325,道真仡佬族苗族自治县,4,520300 +520326,务川仡佬族苗族自治县,4,520300 +520327,凤冈县,4,520300 +520328,湄潭县,4,520300 +520329,余庆县,4,520300 +520330,习水县,4,520300 +520381,赤水市,4,520300 +520382,仁怀市,4,520300 +520402,西秀区,4,520400 +520403,平坝区,4,520400 +520422,普定县,4,520400 +520423,镇宁布依族苗族自治县,4,520400 +520424,关岭布依族苗族自治县,4,520400 +520425,紫云苗族布依族自治县,4,520400 +520502,七星关区,4,520500 +520521,大方县,4,520500 +520523,金沙县,4,520500 +520524,织金县,4,520500 +520525,纳雍县,4,520500 +520526,威宁彝族回族苗族自治县,4,520500 +520527,赫章县,4,520500 +520581,黔西市,4,520500 +520602,碧江区,4,520600 +520603,万山区,4,520600 +520621,江口县,4,520600 +520622,玉屏侗族自治县,4,520600 +520623,石阡县,4,520600 +520624,思南县,4,520600 +520625,印江土家族苗族自治县,4,520600 +520626,德江县,4,520600 +520627,沿河土家族自治县,4,520600 +520628,松桃苗族自治县,4,520600 +522301,兴义市,4,522300 +522302,兴仁市,4,522300 +522323,普安县,4,522300 +522324,晴隆县,4,522300 +522325,贞丰县,4,522300 +522326,望谟县,4,522300 +522327,册亨县,4,522300 +522328,安龙县,4,522300 +522601,凯里市,4,522600 +522622,黄平县,4,522600 +522623,施秉县,4,522600 +522624,三穗县,4,522600 +522625,镇远县,4,522600 +522626,岑巩县,4,522600 +522627,天柱县,4,522600 +522628,锦屏县,4,522600 +522629,剑河县,4,522600 +522630,台江县,4,522600 +522631,黎平县,4,522600 +522632,榕江县,4,522600 +522633,从江县,4,522600 +522634,雷山县,4,522600 +522635,麻江县,4,522600 +522636,丹寨县,4,522600 +522701,都匀市,4,522700 +522702,福泉市,4,522700 +522722,荔波县,4,522700 +522723,贵定县,4,522700 +522725,瓮安县,4,522700 +522726,独山县,4,522700 +522727,平塘县,4,522700 +522728,罗甸县,4,522700 +522729,长顺县,4,522700 +522730,龙里县,4,522700 +522731,惠水县,4,522700 +522732,三都水族自治县,4,522700 +530102,五华区,4,530100 +530103,盘龙区,4,530100 +530111,官渡区,4,530100 +530112,西山区,4,530100 +530113,东川区,4,530100 +530114,呈贡区,4,530100 +530115,晋宁区,4,530100 +530124,富民县,4,530100 +530125,宜良县,4,530100 +530126,石林彝族自治县,4,530100 +530127,嵩明县,4,530100 +530128,禄劝彝族苗族自治县,4,530100 +530129,寻甸回族彝族自治县,4,530100 +530181,安宁市,4,530100 +530302,麒麟区,4,530300 +530303,沾益区,4,530300 +530304,马龙区,4,530300 +530322,陆良县,4,530300 +530323,师宗县,4,530300 +530324,罗平县,4,530300 +530325,富源县,4,530300 +530326,会泽县,4,530300 +530381,宣威市,4,530300 +530402,红塔区,4,530400 +530403,江川区,4,530400 +530423,通海县,4,530400 +530424,华宁县,4,530400 +530425,易门县,4,530400 +530426,峨山彝族自治县,4,530400 +530427,新平彝族傣族自治县,4,530400 +530428,元江哈尼族彝族傣族自治县,4,530400 +530481,澄江市,4,530400 +530502,隆阳区,4,530500 +530521,施甸县,4,530500 +530523,龙陵县,4,530500 +530524,昌宁县,4,530500 +530581,腾冲市,4,530500 +530602,昭阳区,4,530600 +530621,鲁甸县,4,530600 +530622,巧家县,4,530600 +530623,盐津县,4,530600 +530624,大关县,4,530600 +530625,永善县,4,530600 +530626,绥江县,4,530600 +530627,镇雄县,4,530600 +530628,彝良县,4,530600 +530629,威信县,4,530600 +530681,水富市,4,530600 +530702,古城区,4,530700 +530721,玉龙纳西族自治县,4,530700 +530722,永胜县,4,530700 +530723,华坪县,4,530700 +530724,宁蒗彝族自治县,4,530700 +530802,思茅区,4,530800 +530821,宁洱哈尼族彝族自治县,4,530800 +530822,墨江哈尼族自治县,4,530800 +530823,景东彝族自治县,4,530800 +530824,景谷傣族彝族自治县,4,530800 +530825,镇沅彝族哈尼族拉祜族自治县,4,530800 +530826,江城哈尼族彝族自治县,4,530800 +530827,孟连傣族拉祜族佤族自治县,4,530800 +530828,澜沧拉祜族自治县,4,530800 +530829,西盟佤族自治县,4,530800 +530902,临翔区,4,530900 +530921,凤庆县,4,530900 +530922,云县,4,530900 +530923,永德县,4,530900 +530924,镇康县,4,530900 +530925,双江拉祜族佤族布朗族傣族自治县,4,530900 +530926,耿马傣族佤族自治县,4,530900 +530927,沧源佤族自治县,4,530900 +532301,楚雄市,4,532300 +532302,禄丰市,4,532300 +532322,双柏县,4,532300 +532323,牟定县,4,532300 +532324,南华县,4,532300 +532325,姚安县,4,532300 +532326,大姚县,4,532300 +532327,永仁县,4,532300 +532328,元谋县,4,532300 +532329,武定县,4,532300 +532501,个旧市,4,532500 +532502,开远市,4,532500 +532503,蒙自市,4,532500 +532504,弥勒市,4,532500 +532523,屏边苗族自治县,4,532500 +532524,建水县,4,532500 +532525,石屏县,4,532500 +532527,泸西县,4,532500 +532528,元阳县,4,532500 +532529,红河县,4,532500 +532530,金平苗族瑶族傣族自治县,4,532500 +532531,绿春县,4,532500 +532532,河口瑶族自治县,4,532500 +532601,文山市,4,532600 +532622,砚山县,4,532600 +532623,西畴县,4,532600 +532624,麻栗坡县,4,532600 +532625,马关县,4,532600 +532626,丘北县,4,532600 +532627,广南县,4,532600 +532628,富宁县,4,532600 +532801,景洪市,4,532800 +532822,勐海县,4,532800 +532823,勐腊县,4,532800 +532901,大理市,4,532900 +532922,漾濞彝族自治县,4,532900 +532923,祥云县,4,532900 +532924,宾川县,4,532900 +532925,弥渡县,4,532900 +532926,南涧彝族自治县,4,532900 +532927,巍山彝族回族自治县,4,532900 +532928,永平县,4,532900 +532929,云龙县,4,532900 +532930,洱源县,4,532900 +532931,剑川县,4,532900 +532932,鹤庆县,4,532900 +533102,瑞丽市,4,533100 +533103,芒市,4,533100 +533122,梁河县,4,533100 +533123,盈江县,4,533100 +533124,陇川县,4,533100 +533301,泸水市,4,533300 +533323,福贡县,4,533300 +533324,贡山独龙族怒族自治县,4,533300 +533325,兰坪白族普米族自治县,4,533300 +533401,香格里拉市,4,533400 +533422,德钦县,4,533400 +533423,维西傈僳族自治县,4,533400 +540102,城关区,4,540100 +540103,堆龙德庆区,4,540100 +540104,达孜区,4,540100 +540121,林周县,4,540100 +540122,当雄县,4,540100 +540123,尼木县,4,540100 +540124,曲水县,4,540100 +540127,墨竹工卡县,4,540100 +540171,格尔木藏青工业园区,4,540100 +540172,拉萨经济技术开发区,4,540100 +540173,西藏文化旅游创意园区,4,540100 +540174,达孜工业园区,4,540100 +540202,桑珠孜区,4,540200 +540221,南木林县,4,540200 +540222,江孜县,4,540200 +540223,定日县,4,540200 +540224,萨迦县,4,540200 +540225,拉孜县,4,540200 +540226,昂仁县,4,540200 +540227,谢通门县,4,540200 +540228,白朗县,4,540200 +540229,仁布县,4,540200 +540230,康马县,4,540200 +540231,定结县,4,540200 +540232,仲巴县,4,540200 +540233,亚东县,4,540200 +540234,吉隆县,4,540200 +540235,聂拉木县,4,540200 +540236,萨嘎县,4,540200 +540237,岗巴县,4,540200 +540302,卡若区,4,540300 +540321,江达县,4,540300 +540322,贡觉县,4,540300 +540323,类乌齐县,4,540300 +540324,丁青县,4,540300 +540325,察雅县,4,540300 +540326,八宿县,4,540300 +540327,左贡县,4,540300 +540328,芒康县,4,540300 +540329,洛隆县,4,540300 +540330,边坝县,4,540300 +540402,巴宜区,4,540400 +540421,工布江达县,4,540400 +540422,米林县,4,540400 +540423,墨脱县,4,540400 +540424,波密县,4,540400 +540425,察隅县,4,540400 +540426,朗县,4,540400 +540502,乃东区,4,540500 +540521,扎囊县,4,540500 +540522,贡嘎县,4,540500 +540523,桑日县,4,540500 +540524,琼结县,4,540500 +540525,曲松县,4,540500 +540526,措美县,4,540500 +540527,洛扎县,4,540500 +540528,加查县,4,540500 +540529,隆子县,4,540500 +540530,错那县,4,540500 +540531,浪卡子县,4,540500 +540602,色尼区,4,540600 +540621,嘉黎县,4,540600 +540622,比如县,4,540600 +540623,聂荣县,4,540600 +540624,安多县,4,540600 +540625,申扎县,4,540600 +540626,索县,4,540600 +540627,班戈县,4,540600 +540628,巴青县,4,540600 +540629,尼玛县,4,540600 +540630,双湖县,4,540600 +542521,普兰县,4,542500 +542522,札达县,4,542500 +542523,噶尔县,4,542500 +542524,日土县,4,542500 +542525,革吉县,4,542500 +542526,改则县,4,542500 +542527,措勤县,4,542500 +610102,新城区,4,610100 +610103,碑林区,4,610100 +610104,莲湖区,4,610100 +610111,灞桥区,4,610100 +610112,未央区,4,610100 +610113,雁塔区,4,610100 +610114,阎良区,4,610100 +610115,临潼区,4,610100 +610116,长安区,4,610100 +610117,高陵区,4,610100 +610118,鄠邑区,4,610100 +610122,蓝田县,4,610100 +610124,周至县,4,610100 +610202,王益区,4,610200 +610203,印台区,4,610200 +610204,耀州区,4,610200 +610222,宜君县,4,610200 +610302,渭滨区,4,610300 +610303,金台区,4,610300 +610304,陈仓区,4,610300 +610305,凤翔区,4,610300 +610323,岐山县,4,610300 +610324,扶风县,4,610300 +610326,眉县,4,610300 +610327,陇县,4,610300 +610328,千阳县,4,610300 +610329,麟游县,4,610300 +610330,凤县,4,610300 +610331,太白县,4,610300 +610402,秦都区,4,610400 +610403,杨陵区,4,610400 +610404,渭城区,4,610400 +610422,三原县,4,610400 +610423,泾阳县,4,610400 +610424,乾县,4,610400 +610425,礼泉县,4,610400 +610426,永寿县,4,610400 +610428,长武县,4,610400 +610429,旬邑县,4,610400 +610430,淳化县,4,610400 +610431,武功县,4,610400 +610481,兴平市,4,610400 +610482,彬州市,4,610400 +610502,临渭区,4,610500 +610503,华州区,4,610500 +610522,潼关县,4,610500 +610523,大荔县,4,610500 +610524,合阳县,4,610500 +610525,澄城县,4,610500 +610526,蒲城县,4,610500 +610527,白水县,4,610500 +610528,富平县,4,610500 +610581,韩城市,4,610500 +610582,华阴市,4,610500 +610602,宝塔区,4,610600 +610603,安塞区,4,610600 +610621,延长县,4,610600 +610622,延川县,4,610600 +610625,志丹县,4,610600 +610626,吴起县,4,610600 +610627,甘泉县,4,610600 +610628,富县,4,610600 +610629,洛川县,4,610600 +610630,宜川县,4,610600 +610631,黄龙县,4,610600 +610632,黄陵县,4,610600 +610681,子长市,4,610600 +610702,汉台区,4,610700 +610703,南郑区,4,610700 +610722,城固县,4,610700 +610723,洋县,4,610700 +610724,西乡县,4,610700 +610725,勉县,4,610700 +610726,宁强县,4,610700 +610727,略阳县,4,610700 +610728,镇巴县,4,610700 +610729,留坝县,4,610700 +610730,佛坪县,4,610700 +610802,榆阳区,4,610800 +610803,横山区,4,610800 +610822,府谷县,4,610800 +610824,靖边县,4,610800 +610825,定边县,4,610800 +610826,绥德县,4,610800 +610827,米脂县,4,610800 +610828,佳县,4,610800 +610829,吴堡县,4,610800 +610830,清涧县,4,610800 +610831,子洲县,4,610800 +610881,神木市,4,610800 +610902,汉滨区,4,610900 +610921,汉阴县,4,610900 +610922,石泉县,4,610900 +610923,宁陕县,4,610900 +610924,紫阳县,4,610900 +610925,岚皋县,4,610900 +610926,平利县,4,610900 +610927,镇坪县,4,610900 +610929,白河县,4,610900 +610981,旬阳市,4,610900 +611002,商州区,4,611000 +611021,洛南县,4,611000 +611022,丹凤县,4,611000 +611023,商南县,4,611000 +611024,山阳县,4,611000 +611025,镇安县,4,611000 +611026,柞水县,4,611000 +620102,城关区,4,620100 +620103,七里河区,4,620100 +620104,西固区,4,620100 +620105,安宁区,4,620100 +620111,红古区,4,620100 +620121,永登县,4,620100 +620122,皋兰县,4,620100 +620123,榆中县,4,620100 +620171,兰州新区,4,620100 +620201,嘉峪关市,4,620200 +620302,金川区,4,620300 +620321,永昌县,4,620300 +620402,白银区,4,620400 +620403,平川区,4,620400 +620421,靖远县,4,620400 +620422,会宁县,4,620400 +620423,景泰县,4,620400 +620502,秦州区,4,620500 +620503,麦积区,4,620500 +620521,清水县,4,620500 +620522,秦安县,4,620500 +620523,甘谷县,4,620500 +620524,武山县,4,620500 +620525,张家川回族自治县,4,620500 +620602,凉州区,4,620600 +620621,民勤县,4,620600 +620622,古浪县,4,620600 +620623,天祝藏族自治县,4,620600 +620702,甘州区,4,620700 +620721,肃南裕固族自治县,4,620700 +620722,民乐县,4,620700 +620723,临泽县,4,620700 +620724,高台县,4,620700 +620725,山丹县,4,620700 +620802,崆峒区,4,620800 +620821,泾川县,4,620800 +620822,灵台县,4,620800 +620823,崇信县,4,620800 +620825,庄浪县,4,620800 +620826,静宁县,4,620800 +620881,华亭市,4,620800 +620902,肃州区,4,620900 +620921,金塔县,4,620900 +620922,瓜州县,4,620900 +620923,肃北蒙古族自治县,4,620900 +620924,阿克塞哈萨克族自治县,4,620900 +620981,玉门市,4,620900 +620982,敦煌市,4,620900 +621002,西峰区,4,621000 +621021,庆城县,4,621000 +621022,环县,4,621000 +621023,华池县,4,621000 +621024,合水县,4,621000 +621025,正宁县,4,621000 +621026,宁县,4,621000 +621027,镇原县,4,621000 +621102,安定区,4,621100 +621121,通渭县,4,621100 +621122,陇西县,4,621100 +621123,渭源县,4,621100 +621124,临洮县,4,621100 +621125,漳县,4,621100 +621126,岷县,4,621100 +621202,武都区,4,621200 +621221,成县,4,621200 +621222,文县,4,621200 +621223,宕昌县,4,621200 +621224,康县,4,621200 +621225,西和县,4,621200 +621226,礼县,4,621200 +621227,徽县,4,621200 +621228,两当县,4,621200 +622901,临夏市,4,622900 +622921,临夏县,4,622900 +622922,康乐县,4,622900 +622923,永靖县,4,622900 +622924,广河县,4,622900 +622925,和政县,4,622900 +622926,东乡族自治县,4,622900 +622927,积石山保安族东乡族撒拉族自治县,4,622900 +623001,合作市,4,623000 +623021,临潭县,4,623000 +623022,卓尼县,4,623000 +623023,舟曲县,4,623000 +623024,迭部县,4,623000 +623025,玛曲县,4,623000 +623026,碌曲县,4,623000 +623027,夏河县,4,623000 +630102,城东区,4,630100 +630103,城中区,4,630100 +630104,城西区,4,630100 +630105,城北区,4,630100 +630106,湟中区,4,630100 +630121,大通回族土族自治县,4,630100 +630123,湟源县,4,630100 +630202,乐都区,4,630200 +630203,平安区,4,630200 +630222,民和回族土族自治县,4,630200 +630223,互助土族自治县,4,630200 +630224,化隆回族自治县,4,630200 +630225,循化撒拉族自治县,4,630200 +632221,门源回族自治县,4,632200 +632222,祁连县,4,632200 +632223,海晏县,4,632200 +632224,刚察县,4,632200 +632301,同仁市,4,632300 +632322,尖扎县,4,632300 +632323,泽库县,4,632300 +632324,河南蒙古族自治县,4,632300 +632521,共和县,4,632500 +632522,同德县,4,632500 +632523,贵德县,4,632500 +632524,兴海县,4,632500 +632525,贵南县,4,632500 +632621,玛沁县,4,632600 +632622,班玛县,4,632600 +632623,甘德县,4,632600 +632624,达日县,4,632600 +632625,久治县,4,632600 +632626,玛多县,4,632600 +632701,玉树市,4,632700 +632722,杂多县,4,632700 +632723,称多县,4,632700 +632724,治多县,4,632700 +632725,囊谦县,4,632700 +632726,曲麻莱县,4,632700 +632801,格尔木市,4,632800 +632802,德令哈市,4,632800 +632803,茫崖市,4,632800 +632821,乌兰县,4,632800 +632822,都兰县,4,632800 +632823,天峻县,4,632800 +632857,大柴旦行政委员会,4,632800 +640104,兴庆区,4,640100 +640105,西夏区,4,640100 +640106,金凤区,4,640100 +640121,永宁县,4,640100 +640122,贺兰县,4,640100 +640181,灵武市,4,640100 +640202,大武口区,4,640200 +640205,惠农区,4,640200 +640221,平罗县,4,640200 +640302,利通区,4,640300 +640303,红寺堡区,4,640300 +640323,盐池县,4,640300 +640324,同心县,4,640300 +640381,青铜峡市,4,640300 +640402,原州区,4,640400 +640422,西吉县,4,640400 +640423,隆德县,4,640400 +640424,泾源县,4,640400 +640425,彭阳县,4,640400 +640502,沙坡头区,4,640500 +640521,中宁县,4,640500 +640522,海原县,4,640500 +650102,天山区,4,650100 +650103,沙依巴克区,4,650100 +650104,新市区,4,650100 +650105,水磨沟区,4,650100 +650106,头屯河区,4,650100 +650107,达坂城区,4,650100 +650109,米东区,4,650100 +650121,乌鲁木齐县,4,650100 +650202,独山子区,4,650200 +650203,克拉玛依区,4,650200 +650204,白碱滩区,4,650200 +650205,乌尔禾区,4,650200 +650402,高昌区,4,650400 +650421,鄯善县,4,650400 +650422,托克逊县,4,650400 +650502,伊州区,4,650500 +650521,巴里坤哈萨克自治县,4,650500 +650522,伊吾县,4,650500 +652301,昌吉市,4,652300 +652302,阜康市,4,652300 +652323,呼图壁县,4,652300 +652324,玛纳斯县,4,652300 +652325,奇台县,4,652300 +652327,吉木萨尔县,4,652300 +652328,木垒哈萨克自治县,4,652300 +652701,博乐市,4,652700 +652702,阿拉山口市,4,652700 +652722,精河县,4,652700 +652723,温泉县,4,652700 +652801,库尔勒市,4,652800 +652822,轮台县,4,652800 +652823,尉犁县,4,652800 +652824,若羌县,4,652800 +652825,且末县,4,652800 +652826,焉耆回族自治县,4,652800 +652827,和静县,4,652800 +652828,和硕县,4,652800 +652829,博湖县,4,652800 +652871,库尔勒经济技术开发区,4,652800 +652901,阿克苏市,4,652900 +652902,库车市,4,652900 +652922,温宿县,4,652900 +652924,沙雅县,4,652900 +652925,新和县,4,652900 +652926,拜城县,4,652900 +652927,乌什县,4,652900 +652928,阿瓦提县,4,652900 +652929,柯坪县,4,652900 +653001,阿图什市,4,653000 +653022,阿克陶县,4,653000 +653023,阿合奇县,4,653000 +653024,乌恰县,4,653000 +653101,喀什市,4,653100 +653121,疏附县,4,653100 +653122,疏勒县,4,653100 +653123,英吉沙县,4,653100 +653124,泽普县,4,653100 +653125,莎车县,4,653100 +653126,叶城县,4,653100 +653127,麦盖提县,4,653100 +653128,岳普湖县,4,653100 +653129,伽师县,4,653100 +653130,巴楚县,4,653100 +653131,塔什库尔干塔吉克自治县,4,653100 +653201,和田市,4,653200 +653221,和田县,4,653200 +653222,墨玉县,4,653200 +653223,皮山县,4,653200 +653224,洛浦县,4,653200 +653225,策勒县,4,653200 +653226,于田县,4,653200 +653227,民丰县,4,653200 +654002,伊宁市,4,654000 +654003,奎屯市,4,654000 +654004,霍尔果斯市,4,654000 +654021,伊宁县,4,654000 +654022,察布查尔锡伯自治县,4,654000 +654023,霍城县,4,654000 +654024,巩留县,4,654000 +654025,新源县,4,654000 +654026,昭苏县,4,654000 +654027,特克斯县,4,654000 +654028,尼勒克县,4,654000 +654201,塔城市,4,654200 +654202,乌苏市,4,654200 +654203,沙湾市,4,654200 +654221,额敏县,4,654200 +654224,托里县,4,654200 +654225,裕民县,4,654200 +654226,和布克赛尔蒙古自治县,4,654200 +654301,阿勒泰市,4,654300 +654321,布尔津县,4,654300 +654322,富蕴县,4,654300 +654323,福海县,4,654300 +654324,哈巴河县,4,654300 +654325,青河县,4,654300 +654326,吉木乃县,4,654300 +659001,石河子市,4,659000 +659002,阿拉尔市,4,659000 +659003,图木舒克市,4,659000 +659004,五家渠市,4,659000 +659005,北屯市,4,659000 +659006,铁门关市,4,659000 +659007,双河市,4,659000 +659008,可克达拉市,4,659000 +659009,昆玉市,4,659000 +659010,胡杨河市,4,659000 +659011,新星市,4,659000 \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb new file mode 100644 index 0000000..58596a5 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/ip2region.xdb differ diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java new file mode 100644 index 0000000..cc23819 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.ip.core.utils; + + +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link AreaUtils} 的单元测试 + * + * @author 芋道源码 + */ +public class AreaUtilsTest { + + @Test + public void testGetArea() { + // 调用:北京 + Area area = AreaUtils.getArea(110100); + // 断言 + assertEquals(area.getId(), 110100); + assertEquals(area.getName(), "北京市"); + assertEquals(area.getType(), AreaTypeEnum.CITY.getType()); + assertEquals(area.getParent().getId(), 110000); + assertEquals(area.getChildren().size(), 16); + } + + @Test + public void testFormat() { + assertEquals(AreaUtils.format(110105), "北京市 北京市 朝阳区"); + assertEquals(AreaUtils.format(1), "中国"); + assertEquals(AreaUtils.format(2), "蒙古"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtilsTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtilsTest.java new file mode 100644 index 0000000..761a1aa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtilsTest.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.framework.ip.core.utils; + +import cn.iocoder.yudao.framework.ip.core.Area; +import org.junit.jupiter.api.Test; +import org.lionsoul.ip2region.xdb.Searcher; + + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link IPUtils} 的单元测试 + * + * @author wanglhup + */ +public class IPUtilsTest { + + @Test + public void testGetAreaId_string() { + // 120.202.4.0|120.202.4.255|420600 + Integer areaId = IPUtils.getAreaId("120.202.4.50"); + assertEquals(420600, areaId); + } + + @Test + public void testGetAreaId_long() throws Exception { + // 120.203.123.0|120.203.133.255|360900 + long ip = Searcher.checkIP("120.203.123.250"); + Integer areaId = IPUtils.getAreaId(ip); + assertEquals(360900, areaId); + } + + @Test + public void testGetArea_string() { + // 120.202.4.0|120.202.4.255|420600 + Area area = IPUtils.getArea("120.202.4.50"); + assertEquals("襄阳市", area.getName()); + } + + @Test + public void testGetArea_long() throws Exception { + // 120.203.123.0|120.203.133.255|360900 + long ip = Searcher.checkIP("120.203.123.252"); + Area area = IPUtils.getArea(ip); + assertEquals("宜春市", area.getName()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/pom.xml new file mode 100644 index 0000000..c1a5376 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/pom.xml @@ -0,0 +1,83 @@ + + + + yudao-framework + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-spring-boot-starter-biz-tenant + jar + + ${project.artifactId} + 多租户 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-job + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + true + + + org.springframework.kafka + spring-kafka + true + + + org.springframework.amqp + spring-rabbit + true + + + org.apache.rocketmq + rocketmq-spring-boot-starter + true + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + com.google.guava + guava + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java new file mode 100644 index 0000000..7cb813c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.tenant.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Collections; +import java.util.Set; + +/** + * 多租户配置 + * + * @author 芋道源码 + */ +@ConfigurationProperties(prefix = "yudao.tenant") +@Data +public class TenantProperties { + + /** + * 租户是否开启 + */ + private static final Boolean ENABLE_DEFAULT = true; + + /** + * 是否开启 + */ + private Boolean enable = ENABLE_DEFAULT; + + /** + * 需要忽略多租户的请求 + * + * 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API! + */ + private Set ignoreUrls = Collections.emptySet(); + + /** + * 需要忽略多租户的表 + * + * 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟 + */ + private Set ignoreTables = Collections.emptySet(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java new file mode 100644 index 0000000..c3dd35c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java @@ -0,0 +1,132 @@ +package cn.iocoder.yudao.framework.tenant.config; + +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; +import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; +import cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq.TenantRabbitMQInitializer; +import cn.iocoder.yudao.framework.tenant.core.mq.redis.TenantRedisMessageInterceptor; +import cn.iocoder.yudao.framework.tenant.core.mq.rocketmq.TenantRocketMQInitializer; +import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager; +import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl; +import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.BatchStrategies; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Objects; + +@AutoConfiguration +@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户 +@EnableConfigurationProperties(TenantProperties.class) +public class YudaoTenantAutoConfiguration { + + @Bean + public TenantFrameworkService tenantFrameworkService(TenantApi tenantApi) { + return new TenantFrameworkServiceImpl(tenantApi); + } + + // ========== AOP ========== + + @Bean + public TenantIgnoreAspect tenantIgnoreAspect() { + return new TenantIgnoreAspect(); + } + + // ========== DB ========== + + @Bean + public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties properties, + MybatisPlusInterceptor interceptor) { + TenantLineInnerInterceptor inner = new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(properties)); + // 添加到 interceptor 中 + // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定 + MyBatisUtils.addInterceptor(interceptor, inner, 0); + return inner; + } + + // ========== WEB ========== + + @Bean + public FilterRegistrationBean tenantContextWebFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TenantContextWebFilter()); + registrationBean.setOrder(WebFilterOrderEnum.TENANT_CONTEXT_FILTER); + return registrationBean; + } + + // ========== Security ========== + + @Bean + public FilterRegistrationBean tenantSecurityWebFilter(TenantProperties tenantProperties, + WebProperties webProperties, + GlobalExceptionHandler globalExceptionHandler, + TenantFrameworkService tenantFrameworkService) { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TenantSecurityWebFilter(tenantProperties, webProperties, + globalExceptionHandler, tenantFrameworkService)); + registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER); + return registrationBean; + } + + // ========== MQ ========== + + @Bean + public TenantRedisMessageInterceptor tenantRedisMessageInterceptor() { + return new TenantRedisMessageInterceptor(); + } + + @Bean + @ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate") + public TenantRabbitMQInitializer tenantRabbitMQInitializer() { + return new TenantRabbitMQInitializer(); + } + + @Bean + @ConditionalOnClass(name = "org.apache.rocketmq.spring.core.RocketMQTemplate") + public TenantRocketMQInitializer tenantRocketMQInitializer() { + return new TenantRocketMQInitializer(); + } + + // ========== Job ========== + + @Bean + public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) { + return new TenantJobAspect(tenantFrameworkService); + } + + // ========== Redis ========== + + @Bean + @Primary // 引入租户时,tenantRedisCacheManager 为主 Bean + public RedisCacheManager tenantRedisCacheManager(RedisTemplate redisTemplate, + RedisCacheConfiguration redisCacheConfiguration, + YudaoCacheProperties yudaoCacheProperties) { + // 创建 RedisCacheWriter 对象 + RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); + RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, + BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize())); + // 创建 TenantRedisCacheManager 对象 + return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java new file mode 100644 index 0000000..f2fec50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnore.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.tenant.core.aop; + +import java.lang.annotation.*; + +/** + * 忽略租户,标记指定方法不进行租户的自动过滤 + * + * 注意,只有 DB 的场景会过滤,其它场景暂时不过滤: + * 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的 + * 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface TenantIgnore { +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java new file mode 100644 index 0000000..b7d0fa3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/TenantIgnoreAspect.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.tenant.core.aop; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * 忽略多租户的 Aspect,基于 {@link TenantIgnore} 注解实现,用于一些全局的逻辑。 + * 例如说,一个定时任务,读取所有数据,进行处理。 + * 又例如说,读取所有数据,进行缓存。 + * + * 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致 + * + * @author 芋道源码 + */ +@Aspect +@Slf4j +public class TenantIgnoreAspect { + + @Around("@annotation(tenantIgnore)") + public Object around(ProceedingJoinPoint joinPoint, TenantIgnore tenantIgnore) throws Throwable { + Boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setIgnore(true); + // 执行逻辑 + return joinPoint.proceed(); + } finally { + TenantContextHolder.setIgnore(oldIgnore); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java new file mode 100644 index 0000000..4e7b5e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.tenant.core.context; + +import cn.iocoder.yudao.framework.common.enums.DocumentEnum; +import com.alibaba.ttl.TransmittableThreadLocal; + +/** + * 多租户上下文 Holder + * + * @author 芋道源码 + */ +public class TenantContextHolder { + + /** + * 当前租户编号 + */ + private static final ThreadLocal TENANT_ID = new TransmittableThreadLocal<>(); + + /** + * 是否忽略租户 + */ + private static final ThreadLocal IGNORE = new TransmittableThreadLocal<>(); + + /** + * 获得租户编号 + * + * @return 租户编号 + */ + public static Long getTenantId() { + return TENANT_ID.get(); + } + + /** + * 获得租户编号。如果不存在,则抛出 NullPointerException 异常 + * + * @return 租户编号 + */ + public static Long getRequiredTenantId() { + Long tenantId = getTenantId(); + if (tenantId == null) { + throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:" + + DocumentEnum.TENANT.getUrl()); + } + return tenantId; + } + + public static void setTenantId(Long tenantId) { + TENANT_ID.set(tenantId); + } + + public static void setIgnore(Boolean ignore) { + IGNORE.set(ignore); + } + + /** + * 当前是否忽略租户 + * + * @return 是否忽略 + */ + public static boolean isIgnore() { + return Boolean.TRUE.equals(IGNORE.get()); + } + + public static void clear() { + TENANT_ID.remove(); + IGNORE.remove(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java new file mode 100644 index 0000000..f4f0ea5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.tenant.core.db; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 拓展多租户的 BaseDO 基类 + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public abstract class TenantBaseDO extends BaseDO { + + /** + * 多租户编号 + */ + private Long tenantId; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java new file mode 100644 index 0000000..8ea1a96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.tenant.core.db; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; + +import java.util.HashSet; +import java.util.Set; + +/** + * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 + * + * @author 芋道源码 + */ +public class TenantDatabaseInterceptor implements TenantLineHandler { + + private final Set ignoreTables = new HashSet<>(); + + public TenantDatabaseInterceptor(TenantProperties properties) { + // 不同 DB 下,大小写的习惯不同,所以需要都添加进去 + properties.getIgnoreTables().forEach(table -> { + ignoreTables.add(table.toLowerCase()); + ignoreTables.add(table.toUpperCase()); + }); + // 在 OracleKeyGenerator 中,生成主键时,会查询这个表,查询这个表后,会自动拼接 TENANT_ID 导致报错 + ignoreTables.add("DUAL"); + } + + @Override + public Expression getTenantId() { + return new LongValue(TenantContextHolder.getRequiredTenantId()); + } + + @Override + public boolean ignoreTable(String tableName) { + return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户 + || CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表 + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java new file mode 100644 index 0000000..23474bb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJob.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.framework.tenant.core.job; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 多租户 Job 注解 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TenantJob { +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java new file mode 100644 index 0000000..732a073 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.tenant.core.job; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 多租户 JobHandler AOP + * 任务执行时,会按照租户逐个执行 Job 的逻辑 + * + * 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。 + * + * @author 芋道源码 + */ +@Aspect +@RequiredArgsConstructor +@Slf4j +public class TenantJobAspect { + + private final TenantFrameworkService tenantFrameworkService; + + @Around("@annotation(tenantJob)") + public String around(ProceedingJoinPoint joinPoint, TenantJob tenantJob) { + // 获得租户列表 + List tenantIds = tenantFrameworkService.getTenantIds(); + if (CollUtil.isEmpty(tenantIds)) { + return null; + } + + // 逐个租户,执行 Job + Map results = new ConcurrentHashMap<>(); + tenantIds.parallelStream().forEach(tenantId -> { + // TODO 芋艿:先通过 parallel 实现并行;1)多个租户,是一条执行日志;2)异常的情况 + TenantUtils.execute(tenantId, () -> { + try { + joinPoint.proceed(); + } catch (Throwable e) { + results.put(tenantId, ExceptionUtil.getRootCauseMessage(e)); + } + }); + }); + return JsonUtils.toJsonString(results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java new file mode 100644 index 0000000..8bf7cc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.kafka; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * 多租户的 Kafka 的 {@link EnvironmentPostProcessor} 实现类 + * + * Kafka Producer 发送消息时,增加 {@link TenantKafkaProducerInterceptor} 拦截器 + * + * @author 芋道源码 + */ +@Slf4j +public class TenantKafkaEnvironmentPostProcessor implements EnvironmentPostProcessor { + + private static final String PROPERTY_KEY_INTERCEPTOR_CLASSES = "spring.kafka.producer.properties.interceptor.classes"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + // 添加 TenantKafkaProducerInterceptor 拦截器 + try { + String value = environment.getProperty(PROPERTY_KEY_INTERCEPTOR_CLASSES); + if (StrUtil.isEmpty(value)) { + value = TenantKafkaProducerInterceptor.class.getName(); + } else { + value += "," + TenantKafkaProducerInterceptor.class.getName(); + } + environment.getSystemProperties().put(PROPERTY_KEY_INTERCEPTOR_CLASSES, value); + } catch (NoClassDefFoundError ignore) { + // 如果触发 NoClassDefFoundError 异常,说明 TenantKafkaProducerInterceptor 类不存在,即没引入 kafka-spring 依赖 + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java new file mode 100644 index 0000000..8ded801 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaProducerInterceptor.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.kafka; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import org.apache.kafka.clients.producer.ProducerInterceptor; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.apache.kafka.common.header.Headers; +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * Kafka 消息队列的多租户 {@link ProducerInterceptor} 实现类 + * + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现 + * + * @author 芋道源码 + */ +public class TenantKafkaProducerInterceptor implements ProducerInterceptor { + + @Override + public ProducerRecord onSend(ProducerRecord record) { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId != null) { + Headers headers = (Headers) ReflectUtil.getFieldValue(record, "headers"); // private 属性,没有 get 方法,智能反射 + headers.add(HEADER_TENANT_ID, tenantId.toString().getBytes()); + } + return record; + } + + @Override + public void onAcknowledgement(RecordMetadata metadata, Exception exception) { + } + + @Override + public void close() { + } + + @Override + public void configure(Map configs) { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java new file mode 100644 index 0000000..b856ce9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQInitializer.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * 多租户的 RabbitMQ 初始化器 + * + * @author 芋道源码 + */ +public class TenantRabbitMQInitializer implements BeanPostProcessor { + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof RabbitTemplate) { + RabbitTemplate rabbitTemplate = (RabbitTemplate) bean; + rabbitTemplate.addBeforePublishPostProcessors(new TenantRabbitMQMessagePostProcessor()); + } + return bean; + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java new file mode 100644 index 0000000..3e6969c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rabbitmq/TenantRabbitMQMessagePostProcessor.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.rabbitmq; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import org.apache.kafka.clients.producer.ProducerInterceptor; +import org.springframework.amqp.AmqpException; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessagePostProcessor; +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * RabbitMQ 消息队列的多租户 {@link ProducerInterceptor} 实现类 + * + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现 + * + * @author 芋道源码 + */ +public class TenantRabbitMQMessagePostProcessor implements MessagePostProcessor { + + @Override + public Message postProcessMessage(Message message) throws AmqpException { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId != null) { + message.getMessageProperties().getHeaders().put(HEADER_TENANT_ID, tenantId); + } + return message; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java new file mode 100644 index 0000000..f6b7747 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/redis/TenantRedisMessageInterceptor.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.redis; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * 多租户 {@link AbstractRedisMessage} 拦截器 + * + * 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中 + * 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中 + * + * @author 芋道源码 + */ +public class TenantRedisMessageInterceptor implements RedisMessageInterceptor { + + @Override + public void sendMessageBefore(AbstractRedisMessage message) { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId != null) { + message.addHeader(HEADER_TENANT_ID, tenantId.toString()); + } + } + + @Override + public void consumeMessageBefore(AbstractRedisMessage message) { + String tenantIdStr = message.getHeader(HEADER_TENANT_ID); + if (StrUtil.isNotEmpty(tenantIdStr)) { + TenantContextHolder.setTenantId(Long.valueOf(tenantIdStr)); + } + } + + @Override + public void consumeMessageAfter(AbstractRedisMessage message) { + // 注意,Consumer 是一个逻辑的入口,所以不考虑原本上下文就存在租户编号的情况 + TenantContextHolder.clear(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java new file mode 100644 index 0000000..d9d7334 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQConsumeMessageHook.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import org.apache.rocketmq.client.hook.ConsumeMessageContext; +import org.apache.rocketmq.client.hook.ConsumeMessageHook; +import org.apache.rocketmq.common.message.MessageExt; +import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; + +import java.util.List; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * RocketMQ 消息队列的多租户 {@link ConsumeMessageHook} 实现类 + * + * Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中,通过 {@link InvocableHandlerMethod} 实现 + * + * @author 芋道源码 + */ +public class TenantRocketMQConsumeMessageHook implements ConsumeMessageHook { + + @Override + public String hookName() { + return getClass().getSimpleName(); + } + + @Override + public void consumeMessageBefore(ConsumeMessageContext context) { + // 校验,消息必须是单条,不然设置租户可能不正确 + List messages = context.getMsgList(); + Assert.isTrue(messages.size() == 1, "消息条数({})不正确", messages.size()); + // 设置租户编号 + String tenantId = messages.get(0).getUserProperty(HEADER_TENANT_ID); + if (StrUtil.isNotEmpty(tenantId)) { + TenantContextHolder.setTenantId(Long.parseLong(tenantId)); + } + } + + @Override + public void consumeMessageAfter(ConsumeMessageContext context) { + TenantContextHolder.clear(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java new file mode 100644 index 0000000..7f12ac5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; + +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl; +import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * 多租户的 RocketMQ 初始化器 + * + * @author 芋道源码 + */ +public class TenantRocketMQInitializer implements BeanPostProcessor { + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof DefaultRocketMQListenerContainer) { + DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean; + initTenantConsumer(container.getConsumer()); + } else if (bean instanceof RocketMQTemplate) { + RocketMQTemplate template = (RocketMQTemplate) bean; + initTenantProducer(template.getProducer()); + } + return bean; + } + + private void initTenantProducer(DefaultMQProducer producer) { + if (producer == null) { + return; + } + DefaultMQProducerImpl producerImpl = producer.getDefaultMQProducerImpl(); + if (producerImpl == null) { + return; + } + producerImpl.registerSendMessageHook(new TenantRocketMQSendMessageHook()); + } + + private void initTenantConsumer(DefaultMQPushConsumer consumer) { + if (consumer == null) { + return; + } + DefaultMQPushConsumerImpl consumerImpl = consumer.getDefaultMQPushConsumerImpl(); + if (consumerImpl == null) { + return; + } + consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java new file mode 100644 index 0000000..4f03074 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import org.apache.rocketmq.client.hook.SendMessageContext; +import org.apache.rocketmq.client.hook.SendMessageHook; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * RocketMQ 消息队列的多租户 {@link SendMessageHook} 实现类 + * + * Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中 + * + * @author 芋道源码 + */ +public class TenantRocketMQSendMessageHook implements SendMessageHook { + + @Override + public String hookName() { + return getClass().getSimpleName(); + } + + @Override + public void sendMessageBefore(SendMessageContext sendMessageContext) { + Long tenantId = TenantContextHolder.getTenantId(); + if (tenantId == null) { + return; + } + sendMessageContext.getMessage().putUserProperty(HEADER_TENANT_ID, tenantId.toString()); + } + + @Override + public void sendMessageAfter(SendMessageContext sendMessageContext) { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java new file mode 100644 index 0000000..240b920 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.tenant.core.redis; + +import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.Cache; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; + +/** + * 多租户的 {@link RedisCacheManager} 实现类 + * + * 操作指定 name 的 {@link Cache} 时,自动拼接租户后缀,格式为 name + ":" + tenantId + 后缀 + * + * @author airhead + */ +@Slf4j +public class TenantRedisCacheManager extends TimeoutRedisCacheManager { + + public TenantRedisCacheManager(RedisCacheWriter cacheWriter, + RedisCacheConfiguration defaultCacheConfiguration) { + super(cacheWriter, defaultCacheConfiguration); + } + + @Override + public Cache getCache(String name) { + // 如果开启多租户,则 name 拼接租户后缀 + if (!TenantContextHolder.isIgnore() + && TenantContextHolder.getTenantId() != null) { + name = name + ":" + TenantContextHolder.getTenantId(); + } + + // 继续基于父方法 + return super.getCache(name); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java new file mode 100644 index 0000000..41ffef0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.framework.tenant.core.security; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.AntPathMatcher; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Objects; + +/** + * 多租户 Security Web 过滤器 + * 1. 如果是登陆的用户,校验是否有权限访问该租户,避免越权问题。 + * 2. 如果请求未带租户的编号,检查是否是忽略的 URL,否则也不允许访问。 + * 3. 校验租户是合法,例如说被禁用、到期 + * + * @author 芋道源码 + */ +@Slf4j +public class TenantSecurityWebFilter extends ApiRequestFilter { + + private final TenantProperties tenantProperties; + + private final AntPathMatcher pathMatcher; + + private final GlobalExceptionHandler globalExceptionHandler; + private final TenantFrameworkService tenantFrameworkService; + + public TenantSecurityWebFilter(TenantProperties tenantProperties, + WebProperties webProperties, + GlobalExceptionHandler globalExceptionHandler, + TenantFrameworkService tenantFrameworkService) { + super(webProperties); + this.tenantProperties = tenantProperties; + this.pathMatcher = new AntPathMatcher(); + this.globalExceptionHandler = globalExceptionHandler; + this.tenantFrameworkService = tenantFrameworkService; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + Long tenantId = TenantContextHolder.getTenantId(); + // 1. 登陆的用户,校验是否有权限访问该租户,避免越权问题。 + LoginUser user = SecurityFrameworkUtils.getLoginUser(); + if (user != null) { + // 如果获取不到租户编号,则尝试使用登陆用户的租户编号 + if (tenantId == null) { + tenantId = user.getTenantId(); + TenantContextHolder.setTenantId(tenantId); + // 如果传递了租户编号,则进行比对租户编号,避免越权问题 + } else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) { + log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]", + user.getTenantId(), user.getId(), user.getUserType(), + TenantContextHolder.getTenantId(), request.getRequestURI(), request.getMethod()); + ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.FORBIDDEN.getCode(), + "您无权访问该租户的数据")); + return; + } + } + + // 如果非允许忽略租户的 URL,则校验租户是否合法 + if (!isIgnoreUrl(request)) { + // 2. 如果请求未带租户的编号,不允许访问。 + if (tenantId == null) { + log.error("[doFilterInternal][URL({}/{}) 未传递租户编号]", request.getRequestURI(), request.getMethod()); + ServletUtils.writeJSON(response, CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), + "请求的租户标识未传递,请进行排查")); + return; + } + // 3. 校验租户是合法,例如说被禁用、到期 + try { + tenantFrameworkService.validTenant(tenantId); + } catch (Throwable ex) { + CommonResult result = globalExceptionHandler.allExceptionHandler(request, ex); + ServletUtils.writeJSON(response, result); + return; + } + } else { // 如果是允许忽略租户的 URL,若未传递租户编号,则默认忽略租户编号,避免报错 + if (tenantId == null) { + TenantContextHolder.setIgnore(true); + } + } + + // 继续过滤 + chain.doFilter(request, response); + } + + private boolean isIgnoreUrl(HttpServletRequest request) { + // 快速匹配,保证性能 + if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) { + return true; + } + // 逐个 Ant 路径匹配 + for (String url : tenantProperties.getIgnoreUrls()) { + if (pathMatcher.match(url, request.getRequestURI())) { + return true; + } + } + return false; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java new file mode 100644 index 0000000..2ca474d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkService.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.tenant.core.service; + +import java.util.List; + +/** + * Tenant 框架 Service 接口,定义获取租户信息 + * + * @author 芋道源码 + */ +public interface TenantFrameworkService { + + /** + * 获得所有租户 + * + * @return 租户编号数组 + */ + List getTenantIds(); + + /** + * 校验租户是否合法 + * + * @param id 租户编号 + */ + void validTenant(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java new file mode 100644 index 0000000..f2b7b27 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/service/TenantFrameworkServiceImpl.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.framework.tenant.core.service; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; +import cn.iocoder.yudao.module.system.api.tenant.TenantApi; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; + +import java.time.Duration; +import java.util.List; + +/** + * Tenant 框架 Service 实现类 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class TenantFrameworkServiceImpl implements TenantFrameworkService { + + private static final ServiceException SERVICE_EXCEPTION_NULL = new ServiceException(); + + private final TenantApi tenantApi; + + /** + * 针对 {@link #getTenantIds()} 的缓存 + */ + private final LoadingCache> getTenantIdsCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader>() { + + @Override + public List load(Object key) { + return tenantApi.getTenantIdList(); + } + + }); + + /** + * 针对 {@link #validTenant(Long)} 的缓存 + */ + private final LoadingCache validTenantCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader() { + + @Override + public ServiceException load(Long id) { + try { + tenantApi.validateTenant(id); + return SERVICE_EXCEPTION_NULL; + } catch (ServiceException ex) { + return ex; + } + } + + }); + + @Override + @SneakyThrows + public List getTenantIds() { + return getTenantIdsCache.get(Boolean.TRUE); + } + + @Override + public void validTenant(Long id) { + ServiceException serviceException = validTenantCache.getUnchecked(id); + if (serviceException != SERVICE_EXCEPTION_NULL) { + throw serviceException; + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java new file mode 100644 index 0000000..7ec9c69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.framework.tenant.core.util; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; + +import java.util.Map; +import java.util.concurrent.Callable; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * 多租户 Util + * + * @author 芋道源码 + */ +public class TenantUtils { + + /** + * 使用指定租户,执行对应的逻辑 + * + * 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户 + * 当然,执行完成后,还是会恢复回去 + * + * @param tenantId 租户编号 + * @param runnable 逻辑 + */ + public static void execute(Long tenantId, Runnable runnable) { + Long oldTenantId = TenantContextHolder.getTenantId(); + Boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setTenantId(tenantId); + TenantContextHolder.setIgnore(false); + // 执行逻辑 + runnable.run(); + } finally { + TenantContextHolder.setTenantId(oldTenantId); + TenantContextHolder.setIgnore(oldIgnore); + } + } + + /** + * 使用指定租户,执行对应的逻辑 + * + * 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户 + * 当然,执行完成后,还是会恢复回去 + * + * @param tenantId 租户编号 + * @param callable 逻辑 + */ + public static V execute(Long tenantId, Callable callable) { + Long oldTenantId = TenantContextHolder.getTenantId(); + Boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setTenantId(tenantId); + TenantContextHolder.setIgnore(false); + // 执行逻辑 + return callable.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + TenantContextHolder.setTenantId(oldTenantId); + TenantContextHolder.setIgnore(oldIgnore); + } + } + + /** + * 忽略租户,执行对应的逻辑 + * + * @param runnable 逻辑 + */ + public static void executeIgnore(Runnable runnable) { + Boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setIgnore(true); + // 执行逻辑 + runnable.run(); + } finally { + TenantContextHolder.setIgnore(oldIgnore); + } + } + + /** + * 将多租户编号,添加到 header 中 + * + * @param headers HTTP 请求 headers + * @param tenantId 租户编号 + */ + public static void addTenantHeader(Map headers, Long tenantId) { + if (tenantId != null) { + headers.put(HEADER_TENANT_ID, tenantId.toString()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java new file mode 100644 index 0000000..8e37727 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantContextWebFilter.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.tenant.core.web; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 多租户 Context Web 过滤器 + * 将请求 Header 中的 tenant-id 解析出来,添加到 {@link TenantContextHolder} 中,这样后续的 DB 等操作,可以获得到租户编号。 + * + * @author 芋道源码 + */ +public class TenantContextWebFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + // 设置 + Long tenantId = WebFrameworkUtils.getTenantId(request); + if (tenantId != null) { + TenantContextHolder.setTenantId(tenantId); + } + try { + chain.doFilter(request, response); + } finally { + // 清理 + TenantContextHolder.clear(); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java new file mode 100644 index 0000000..aa22cdb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java @@ -0,0 +1,17 @@ +/** + * 多租户,支持如下层面: + * 1. DB:基于 MyBatis Plus 多租户的功能实现。 + * 2. Redis:通过在 Redis Key 上拼接租户编号的方式,进行隔离。 + * 3. Web:请求 HTTP API 时,解析 Header 的 tenant-id 租户编号,添加到租户上下文。 + * 4. Security:校验当前登陆的用户,是否越权访问其它租户的数据。 + * 5. Job:在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。 + * 6. MQ:在 Producer 发送消息时,Header 带上 tenant-id 租户编号;在 Consumer 消费消息时,将 Header 的 tenant-id 租户编号,添加到租户上下文。 + * 7. Async:异步需要保证 ThreadLocal 的传递性,通过使用阿里开源的 TransmittableThreadLocal 实现。相关的改造点,可见: + * 1)Spring Async: + * {@link cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()} + * 2)Spring Security: + * TransmittableThreadLocalSecurityContextHolderStrategy + * 和 YudaoSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法 + * + */ +package cn.iocoder.yudao.framework.tenant; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java new file mode 100644 index 0000000..059d8f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java @@ -0,0 +1,269 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.messaging.handler.invocation; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.MethodParameter; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.core.ResolvableType; +import org.springframework.lang.Nullable; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.HandlerMethod; +import org.springframework.util.ObjectUtils; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * Extension of {@link HandlerMethod} that invokes the underlying method with + * argument values resolved from the current HTTP request through a list of + * {@link HandlerMethodArgumentResolver}. + * + * 针对 rabbitmq-spring 和 kafka-spring,不存在合适的拓展点,可以实现 Consumer 消费前,读取 Header 中的 tenant-id 设置到 {@link TenantContextHolder} 中 + * TODO 芋艿:持续跟进,看看有没新的拓展点 + * + * @author Rossen Stoyanchev + * @author Juergen Hoeller + * @since 4.0 + */ +public class InvocableHandlerMethod extends HandlerMethod { + + private static final Object[] EMPTY_ARGS = new Object[0]; + + private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); + + private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); + + /** + * Create an instance from a {@code HandlerMethod}. + */ + public InvocableHandlerMethod(HandlerMethod handlerMethod) { + super(handlerMethod); + } + + /** + * Create an instance from a bean instance and a method. + */ + public InvocableHandlerMethod(Object bean, Method method) { + super(bean, method); + } + + /** + * Construct a new handler method with the given bean instance, method name and parameters. + * @param bean the object bean + * @param methodName the method name + * @param parameterTypes the method parameter types + * @throws NoSuchMethodException when the method cannot be found + */ + public InvocableHandlerMethod(Object bean, String methodName, Class... parameterTypes) + throws NoSuchMethodException { + + super(bean, methodName, parameterTypes); + } + + /** + * Set {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} to use for resolving method argument values. + */ + public void setMessageMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) { + this.resolvers = argumentResolvers; + } + + /** + * Set the ParameterNameDiscoverer for resolving parameter names when needed + * (e.g. default request attribute name). + *

Default is a {@link DefaultParameterNameDiscoverer}. + */ + public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { + this.parameterNameDiscoverer = parameterNameDiscoverer; + } + + /** + * Invoke the method after resolving its argument values in the context of the given message. + *

Argument values are commonly resolved through + * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. + * The {@code providedArgs} parameter however may supply argument values to be used directly, + * i.e. without argument resolution. + *

Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the + * resolved arguments. + * @param message the current message being processed + * @param providedArgs "given" arguments matched by type, not resolved + * @return the raw value returned by the invoked method + * @throws Exception raised if no suitable argument resolver can be found, + * or if the method raised an exception + * @see #getMethodArgumentValues + * @see #doInvoke + */ + @Nullable + public Object invoke(Message message, Object... providedArgs) throws Exception { + Object[] args = getMethodArgumentValues(message, providedArgs); + if (logger.isTraceEnabled()) { + logger.trace("Arguments: " + Arrays.toString(args)); + } + // 注意:如下是本类的改动点!!! + // 情况一:无租户编号的情况 + Long tenantId= parseTenantId(message); + if (tenantId == null) { + return doInvoke(args); + } + // 情况二:有租户的情况下 + return TenantUtils.execute(tenantId, () -> doInvoke(args)); + } + + private Long parseTenantId(Message message) { + Object tenantId = message.getHeaders().get(HEADER_TENANT_ID); + if (tenantId == null) { + return null; + } + if (tenantId instanceof Long) { + return (Long) tenantId; + } + if (tenantId instanceof Number) { + return ((Number) tenantId).longValue(); + } + if (tenantId instanceof String) { + return Long.parseLong((String) tenantId); + } + if (tenantId instanceof byte[]) { + return Long.parseLong(new String((byte[]) tenantId)); + } + throw new IllegalArgumentException("未知的数据类型:" + tenantId); + } + + /** + * Get the method argument values for the current message, checking the provided + * argument values and falling back to the configured argument resolvers. + *

The resulting array will be passed into {@link #doInvoke}. + * @since 5.1.2 + */ + protected Object[] getMethodArgumentValues(Message message, Object... providedArgs) throws Exception { + MethodParameter[] parameters = getMethodParameters(); + if (ObjectUtils.isEmpty(parameters)) { + return EMPTY_ARGS; + } + + Object[] args = new Object[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + MethodParameter parameter = parameters[i]; + parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); + args[i] = findProvidedArgument(parameter, providedArgs); + if (args[i] != null) { + continue; + } + if (!this.resolvers.supportsParameter(parameter)) { + throw new MethodArgumentResolutionException( + message, parameter, formatArgumentError(parameter, "No suitable resolver")); + } + try { + args[i] = this.resolvers.resolveArgument(parameter, message); + } + catch (Exception ex) { + // Leave stack trace for later, exception may actually be resolved and handled... + if (logger.isDebugEnabled()) { + String exMsg = ex.getMessage(); + if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { + logger.debug(formatArgumentError(parameter, exMsg)); + } + } + throw ex; + } + } + return args; + } + + /** + * Invoke the handler method with the given argument values. + */ + @Nullable + protected Object doInvoke(Object... args) throws Exception { + try { + return getBridgedMethod().invoke(getBean(), args); + } + catch (IllegalArgumentException ex) { + assertTargetBean(getBridgedMethod(), getBean(), args); + String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); + throw new IllegalStateException(formatInvokeError(text, args), ex); + } + catch (InvocationTargetException ex) { + // Unwrap for HandlerExceptionResolvers ... + Throwable targetException = ex.getTargetException(); + if (targetException instanceof RuntimeException) { + throw (RuntimeException) targetException; + } + else if (targetException instanceof Error) { + throw (Error) targetException; + } + else if (targetException instanceof Exception) { + throw (Exception) targetException; + } + else { + throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); + } + } + } + + MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) { + return new AsyncResultMethodParameter(returnValue); + } + + private class AsyncResultMethodParameter extends HandlerMethodParameter { + + @Nullable + private final Object returnValue; + + private final ResolvableType returnType; + + public AsyncResultMethodParameter(@Nullable Object returnValue) { + super(-1); + this.returnValue = returnValue; + this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric(); + } + + protected AsyncResultMethodParameter(AsyncResultMethodParameter original) { + super(original); + this.returnValue = original.returnValue; + this.returnType = original.returnType; + } + + @Override + public Class getParameterType() { + if (this.returnValue != null) { + return this.returnValue.getClass(); + } + if (!ResolvableType.NONE.equals(this.returnType)) { + return this.returnType.toClass(); + } + return super.getParameterType(); + } + + @Override + public Type getGenericParameterType() { + return this.returnType.getType(); + } + + @Override + public AsyncResultMethodParameter clone() { + return new AsyncResultMethodParameter(this); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..a495842 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..603831e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.tenant.config.YudaoTenantAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/pom.xml new file mode 100644 index 0000000..3da22b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/pom.xml @@ -0,0 +1,75 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-excel + jar + + ${project.artifactId} + Excel 拓展 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + org.springframework + spring-web + provided + + + + jakarta.servlet + jakarta.servlet-api + provided + + + + + com.alibaba + easyexcel + + + + com.google.guava + guava + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + true + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java new file mode 100644 index 0000000..8a6075e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.dict.config; + +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +@AutoConfiguration +public class YudaoDictAutoConfiguration { + + @Bean + @SuppressWarnings("InstantiationOfUtilityClass") + public DictFrameworkUtils dictUtils(DictDataApi dictDataApi) { + DictFrameworkUtils.init(dictDataApi); + return new DictFrameworkUtils(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java new file mode 100644 index 0000000..8dada3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.framework.dict.core; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.time.Duration; +import java.util.List; + +/** + * 字典工具类 + * + * @author 芋道源码 + */ +@Slf4j +public class DictFrameworkUtils { + + private static DictDataApi dictDataApi; + + private static final DictDataRespDTO DICT_DATA_NULL = new DictDataRespDTO(); + + // TODO @puhui999:GET_DICT_DATA_CACHE、GET_DICT_DATA_LIST_CACHE、PARSE_DICT_DATA_CACHE 这 3 个缓存是有点重叠,可以思考下,有没可能减少 1 个。微信讨论好私聊,再具体改哈 + /** + * 针对 {@link #getDictDataLabel(String, String)} 的缓存 + */ + private static final LoadingCache, DictDataRespDTO> GET_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader, DictDataRespDTO>() { + + @Override + public DictDataRespDTO load(KeyValue key) { + return ObjectUtil.defaultIfNull(dictDataApi.getDictData(key.getKey(), key.getValue()), DICT_DATA_NULL); + } + + }); + + /** + * 针对 {@link #getDictDataLabelList(String)} 的缓存 + */ + private static final LoadingCache> GET_DICT_DATA_LIST_CACHE = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader>() { + + @Override + public List load(String dictType) { + return dictDataApi.getDictDataLabelList(dictType); + } + + }); + + /** + * 针对 {@link #parseDictDataValue(String, String)} 的缓存 + */ + private static final LoadingCache, DictDataRespDTO> PARSE_DICT_DATA_CACHE = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader, DictDataRespDTO>() { + + @Override + public DictDataRespDTO load(KeyValue key) { + return ObjectUtil.defaultIfNull(dictDataApi.parseDictData(key.getKey(), key.getValue()), DICT_DATA_NULL); + } + + }); + + public static void init(DictDataApi dictDataApi) { + DictFrameworkUtils.dictDataApi = dictDataApi; + log.info("[init][初始化 DictFrameworkUtils 成功]"); + } + + @SneakyThrows + public static String getDictDataLabel(String dictType, Integer value) { + return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, String.valueOf(value))).getLabel(); + } + + @SneakyThrows + public static String getDictDataLabel(String dictType, String value) { + return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, value)).getLabel(); + } + + @SneakyThrows + public static List getDictDataLabelList(String dictType) { + return GET_DICT_DATA_LIST_CACHE.get(dictType); + } + + @SneakyThrows + public static String parseDictDataValue(String dictType, String label) { + return PARSE_DICT_DATA_CACHE.get(new KeyValue<>(dictType, label)).getValue(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java new file mode 100644 index 0000000..fd87fda --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java @@ -0,0 +1,6 @@ +/** + * 字典数据模块,提供 {@link cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils} 工具类 + * + * 通过将字典缓存在内存中,保证性能 + */ +package cn.iocoder.yudao.framework.dict; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java new file mode 100644 index 0000000..0d898b4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.excel.core.annotations; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * 实现将字典数据的值,格式化成字典数据的标签 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface DictFormat { + + /** + * 例如说,SysDictTypeConstants、InfDictTypeConstants + * + * @return 字典类型 + */ + String value(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java new file mode 100644 index 0000000..b4ff140 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.excel.core.annotations; + +import java.lang.annotation.*; + +/** + * 给 Excel 列添加下拉选择数据 + * + * 其中 {@link #dictType()} 和 {@link #functionName()} 二选一 + * + * @author HUIHUI + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelColumnSelect { + + /** + * @return 字典类型 + */ + String dictType() default ""; + + /** + * @return 获取下拉数据源的方法名称 + */ + String functionName() default ""; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java new file mode 100644 index 0000000..9778b17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.excel.core.convert; + +import cn.hutool.core.convert.Convert; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +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.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +/** + * Excel 数据地区转换器 + * + * @author HUIHUI + */ +@Slf4j +public class AreaConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // 解析地区编号 + String label = readCellData.getStringValue(); + Area area = AreaUtils.parseArea(label); + if (area == null) { + log.error("[convertToJavaData][label({}) 解析不掉]", label); + return null; + } + // 将 value 转换成对应的属性 + Class fieldClazz = contentProperty.getField().getType(); + return Convert.convert(fieldClazz, area.getId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java new file mode 100644 index 0000000..fc79585 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.framework.excel.core.convert; + +import cn.hutool.core.convert.Convert; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +/** + * Excel 数据字典转换器 + * + * @author 芋道源码 + */ +@Slf4j +public class DictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // 使用字典解析 + String type = getType(contentProperty); + String label = readCellData.getStringValue(); + String value = DictFrameworkUtils.parseDictDataValue(type, label); + if (value == null) { + log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label); + return null; + } + // 将 String 的 value 转换成对应的属性 + Class fieldClazz = contentProperty.getField().getType(); + return Convert.convert(fieldClazz, value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // 空时,返回空 + if (object == null) { + return new WriteCellData<>(""); + } + + // 使用字典格式化 + String type = getType(contentProperty); + String value = String.valueOf(object); + String label = DictFrameworkUtils.getDictDataLabel(type, value); + if (label == null) { + log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value); + return new WriteCellData<>(""); + } + // 生成 Excel 小表格 + return new WriteCellData<>(label); + } + + private static String getType(ExcelContentProperty contentProperty) { + return contentProperty.getField().getAnnotation(DictFormat.class).value(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java new file mode 100644 index 0000000..0d4794e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/JsonConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.excel.core.convert; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +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; + +/** + * Excel Json 转换器 + * + * @author 芋道源码 + */ +public class JsonConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public WriteCellData convertToExcelData(Object value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // 生成 Excel 小表格 + return new WriteCellData<>(JsonUtils.toJsonString(value)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java new file mode 100644 index 0000000..ee66fe7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/MoneyConvert.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.framework.excel.core.convert; + +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; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 金额转换器 + * + * 金额单位:分 + * + * @author 芋道源码 + */ +public class MoneyConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + throw new UnsupportedOperationException("暂不支持,也不需要"); + } + + @Override + public WriteCellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + BigDecimal result = BigDecimal.valueOf(value) + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); + return new WriteCellData<>(result.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java new file mode 100644 index 0000000..51953c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.excel.core.function; + +import java.util.List; + +/** + * Excel 列下拉数据源获取接口 + * + * 为什么不直接解析字典还搞个接口?考虑到有的下拉数据不是从字典中获取的所有需要做一个兼容 + + * @author HUIHUI + */ +public interface ExcelColumnSelectFunction { + + /** + * 获得方法名称 + * + * @return 方法名称 + */ + String getName(); + + /** + * 获得列下拉数据源 + * + * @return 下拉数据源 + */ + List getOptions(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java new file mode 100644 index 0000000..22337f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.framework.excel.core.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; +import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; +import com.alibaba.excel.annotation.ExcelProperty; +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.hssf.usermodel.HSSFDataValidation; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; + +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 基于固定 sheet 实现下拉框 + * + * @author HUIHUI + */ +@Slf4j +public class SelectSheetWriteHandler implements SheetWriteHandler { + + /** + * 数据起始行从 0 开始 + * + * 约定:本项目第一行有标题所以从 1 开始如果您的 Excel 有多行标题请自行更改 + */ + public static final int FIRST_ROW = 1; + /** + * 下拉列需要创建下拉框的行数,默认两千行如需更多请自行调整 + */ + public static final int LAST_ROW = 2000; + + private static final String DICT_SHEET_NAME = "字典sheet"; + + /** + * key: 列 value: 下拉数据源 + */ + private final Map> selectMap = new HashMap<>(); + + public SelectSheetWriteHandler(Class head) { + // 加载下拉数据获取接口 + Map beansMap = SpringUtil.getBeanFactory().getBeansOfType(ExcelColumnSelectFunction.class); + if (MapUtil.isEmpty(beansMap)) { + return; + } + + // 解析下拉数据 + int colIndex = 0; + for (Field field : head.getDeclaredFields()) { + if (field.isAnnotationPresent(ExcelColumnSelect.class)) { + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty != null && excelProperty.index() != -1) { + colIndex = excelProperty.index(); + } + getSelectDataList(colIndex, field); + } + colIndex++; + } + } + + /** + * 获得下拉数据,并添加到 {@link #selectMap} 中 + * + * @param colIndex 列索引 + * @param field 字段 + */ + private void getSelectDataList(int colIndex, Field field) { + ExcelColumnSelect columnSelect = field.getAnnotation(ExcelColumnSelect.class); + String dictType = columnSelect.dictType(); + String functionName = columnSelect.functionName(); + Assert.isTrue(ObjectUtil.isNotEmpty(dictType) || ObjectUtil.isNotEmpty(functionName), + "Field({}) 的 @ExcelColumnSelect 注解,dictType 和 functionName 不能同时为空", field.getName()); + + // 情况一:使用 dictType 获得下拉数据 + if (StrUtil.isNotEmpty(dictType)) { // 情况一: 字典数据 (默认) + selectMap.put(colIndex, DictFrameworkUtils.getDictDataLabelList(dictType)); + return; + } + + // 情况二:使用 functionName 获得下拉数据 + Map functionMap = SpringUtil.getApplicationContext().getBeansOfType(ExcelColumnSelectFunction.class); + ExcelColumnSelectFunction function = CollUtil.findOne(functionMap.values(), item -> item.getName().equals(functionName)); + Assert.notNull(function, "未找到对应的 function({})", functionName); + selectMap.put(colIndex, function.getOptions()); + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + if (CollUtil.isEmpty(selectMap)) { + return; + } + + // 1. 获取相应操作对象 + DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); // 需要设置下拉框的 sheet 页的数据验证助手 + Workbook workbook = writeWorkbookHolder.getWorkbook(); // 获得工作簿 + List>> keyValues = convertList(selectMap.entrySet(), entry -> new KeyValue<>(entry.getKey(), entry.getValue())); + keyValues.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 + + // 2. 创建数据字典的 sheet 页 + Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); + for (KeyValue> keyValue : keyValues) { + int rowLength = keyValue.getValue().size(); + // 2.1 设置字典 sheet 页的值,每一列一个字典项 + for (int i = 0; i < rowLength; i++) { + Row row = dictSheet.getRow(i); + if (row == null) { + row = dictSheet.createRow(i); + } + row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); + } + // 2.2 设置单元格下拉选择 + setColumnSelect(writeSheetHolder, workbook, helper, keyValue); + } + } + + /** + * 设置单元格下拉选择 + */ + private static void setColumnSelect(WriteSheetHolder writeSheetHolder, Workbook workbook, DataValidationHelper helper, + KeyValue> keyValue) { + // 1.1 创建可被其他单元格引用的名称 + Name name = workbook.createName(); + String excelColumn = ExcelUtil.indexToColName(keyValue.getKey()); + // 1.2 下拉框数据来源 eg:字典sheet!$B1:$B2 + String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + keyValue.getValue().size(); + name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 + name.setRefersToFormula(refers); // 设置公式 + + // 2.1 设置约束 + DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); // 设置引用约束 + // 设置下拉单元格的首行、末行、首列、末列 + CellRangeAddressList rangeAddressList = new CellRangeAddressList(FIRST_ROW, LAST_ROW, + keyValue.getKey(), keyValue.getKey()); + DataValidation validation = helper.createValidation(constraint, rangeAddressList); + if (validation instanceof HSSFDataValidation) { + validation.setSuppressDropDownArrow(false); + } else { + validation.setSuppressDropDownArrow(true); + validation.setShowErrorBox(true); + } + // 2.2 阻止输入非下拉框的值 + validation.setErrorStyle(DataValidation.ErrorStyle.STOP); + validation.createErrorBox("提示", "此值不存在于下拉选择中!"); + // 2.3 添加下拉框约束 + writeSheetHolder.getSheet().addValidationData(validation); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java new file mode 100644 index 0000000..0bc5994 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.framework.excel.core.util; + +import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.converters.longconverter.LongStringConverter; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * Excel 工具类 + * + * @author 芋道源码 + */ +public class ExcelUtils { + + /** + * 将列表以 Excel 响应给前端 + * + * @param response 响应 + * @param filename 文件名 + * @param sheetName Excel sheet 名 + * @param head Excel head 头 + * @param data 数据列表哦 + * @param 泛型,保证 head 和 data 类型的一致性 + * @throws IOException 写入失败的情况 + */ + public static void write(HttpServletResponse response, String filename, String sheetName, + Class head, List data) throws IOException { + // 输出 Excel + EasyExcel.write(response.getOutputStream(), head) + .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 + .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 + .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 + .sheet(sheetName).doWrite(data); + // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + } + + public static List read(MultipartFile file, Class head) throws IOException { + return EasyExcel.read(file.getInputStream(), head, null) + .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 + .doReadAllSync(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java new file mode 100644 index 0000000..53bc5c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java @@ -0,0 +1,4 @@ +/** + * 基于 EasyExcel 实现 Excel 相关的操作 + */ +package cn.iocoder.yudao.framework.excel; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..2125cee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.dict.config.YudaoDictAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java new file mode 100644 index 0000000..54e8f8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.framework.dict.core.util; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +/** + * {@link DictFrameworkUtils} 的单元测试 + */ +public class DictFrameworkUtilsTest extends BaseMockitoUnitTest { + + @Mock + private DictDataApi dictDataApi; + + @BeforeEach + public void setUp() { + DictFrameworkUtils.init(dictDataApi); + } + + @Test + public void testGetDictDataLabel() { + // mock 数据 + DictDataRespDTO dataRespDTO = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + // mock 方法 + when(dictDataApi.getDictData(dataRespDTO.getDictType(), dataRespDTO.getValue())).thenReturn(dataRespDTO); + + // 断言返回值 + assertEquals(dataRespDTO.getLabel(), DictFrameworkUtils.getDictDataLabel(dataRespDTO.getDictType(), dataRespDTO.getValue())); + } + + @Test + public void testParseDictDataValue() { + // mock 数据 + DictDataRespDTO resp = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + // mock 方法 + when(dictDataApi.parseDictData(resp.getDictType(), resp.getLabel())).thenReturn(resp); + + // 断言返回值 + assertEquals(resp.getValue(), DictFrameworkUtils.parseDictDataValue(resp.getDictType(), resp.getLabel())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/pom.xml new file mode 100644 index 0000000..c17baf4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/pom.xml @@ -0,0 +1,41 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-job + jar + + ${project.artifactId} + 任务拓展 + 1. 定时任务,基于 Quartz 拓展 + 2. 异步任务,基于 Spring Async 拓展 + + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-quartz + + + + + jakarta.validation + jakarta.validation-api + + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java new file mode 100644 index 0000000..6d517e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoAsyncAutoConfiguration.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.quartz.config; + +import com.alibaba.ttl.TtlRunnable; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +/** + * 异步任务 Configuration + */ +@AutoConfiguration +@EnableAsync +public class YudaoAsyncAutoConfiguration { + + @Bean + public BeanPostProcessor threadPoolTaskExecutorBeanPostProcessor() { + return new BeanPostProcessor() { + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (!(bean instanceof ThreadPoolTaskExecutor)) { + return bean; + } + // 修改提交的任务,接入 TransmittableThreadLocal + ThreadPoolTaskExecutor executor = (ThreadPoolTaskExecutor) bean; + executor.setTaskDecorator(TtlRunnable::get); + return executor; + } + + }; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java new file mode 100644 index 0000000..aaf4fe5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.quartz.config; + +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Scheduler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Optional; + +/** + * 定时任务 Configuration + */ +@AutoConfiguration +@EnableScheduling // 开启 Spring 自带的定时任务 +@Slf4j +public class YudaoQuartzAutoConfiguration { + + @Bean + public SchedulerManager schedulerManager(Optional scheduler) { + if (!scheduler.isPresent()) { + log.info("[定时任务 - 已禁用][参考 https://doc.iocoder.cn/job/ 开启]"); + return new SchedulerManager(null); + } + return new SchedulerManager(scheduler.get()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java new file mode 100644 index 0000000..3154c40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.framework.quartz.core.enums; + +/** + * Quartz Job Data 的 key 枚举 + */ +public enum JobDataKeyEnum { + + JOB_ID, + JOB_HANDLER_NAME, + JOB_HANDLER_PARAM, + JOB_RETRY_COUNT, // 最大重试次数 + JOB_RETRY_INTERVAL, // 每次重试间隔 + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java new file mode 100644 index 0000000..381e132 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.quartz.core.handler; + +/** + * 任务处理器 + * + * @author 芋道源码 + */ +public interface JobHandler { + + /** + * 执行任务 + * + * @param param 参数 + * @return 结果 + * @throws Exception 异常 + */ + String execute(String param) throws Exception; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java new file mode 100644 index 0000000..736126f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.framework.quartz.core.handler; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.thread.ThreadUtil; +import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; +import cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.PersistJobDataAfterExecution; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; + +/** + * 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务 + * + * @author 芋道源码 + */ +@DisallowConcurrentExecution +@PersistJobDataAfterExecution +@Slf4j +public class JobHandlerInvoker extends QuartzJobBean { + + @Resource + private ApplicationContext applicationContext; + + @Resource + private JobLogFrameworkService jobLogFrameworkService; + + @Override + protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException { + // 第一步,获得 Job 数据 + Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name()); + String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name()); + String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name()); + int refireCount = executionContext.getRefireCount(); + int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0); + int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0); + + // 第二步,执行任务 + Long jobLogId = null; + LocalDateTime startTime = LocalDateTime.now(); + String data = null; + Throwable exception = null; + try { + // 记录 Job 日志(初始) + jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1); + // 执行任务 + data = this.executeInternal(jobHandlerName, jobHandlerParam); + } catch (Throwable ex) { + exception = ex; + } + + // 第三步,记录执行日志 + this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext); + + // 第四步,处理有异常的情况 + handleException(exception, refireCount, retryCount, retryInterval); + } + + private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception { + // 获得 JobHandler 对象 + JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class); + Assert.notNull(jobHandler, "JobHandler 不会为空"); + // 执行任务 + return jobHandler.execute(jobHandlerParam); + } + + private void updateJobLogResultAsync(Long jobLogId, LocalDateTime startTime, String data, Throwable exception, + JobExecutionContext executionContext) { + LocalDateTime endTime = LocalDateTime.now(); + // 处理是否成功 + boolean success = exception == null; + if (!success) { + data = getRootCauseMessage(exception); + } + // 更新日志 + try { + jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) LocalDateTimeUtil.between(startTime, endTime).toMillis(), success, data); + } catch (Exception ex) { + log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]", + executionContext.getJobDetail().getKey(), jobLogId, success, data); + } + } + + private void handleException(Throwable exception, + int refireCount, int retryCount, int retryInterval) throws JobExecutionException { + // 如果有异常,则进行重试 + if (exception == null) { + return; + } + // 情况一:如果到达重试上限,则直接抛出异常即可 + if (refireCount >= retryCount) { + throw new JobExecutionException(exception); + } + + // 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试 + // 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。 + if (retryInterval > 0) { + ThreadUtil.sleep(retryInterval); + } + // 第二个参数,refireImmediately = true,表示立即重试 + throw new JobExecutionException(exception, true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java new file mode 100644 index 0000000..d56682e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java @@ -0,0 +1,150 @@ +package cn.iocoder.yudao.framework.quartz.core.scheduler; + +import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker; +import org.quartz.*; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; + +/** + * {@link org.quartz.Scheduler} 的管理器,负责创建任务 + * + * 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即: + * 1. Job 的 {@link JobDetail#getKey()} + * 2. Trigger 的 {@link Trigger#getKey()} + * + * 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用 + * + * @author 芋道源码 + */ +public class SchedulerManager { + + private final Scheduler scheduler; + + public SchedulerManager(Scheduler scheduler) { + this.scheduler = scheduler; + } + + /** + * 添加 Job 到 Quartz 中 + * + * @param jobId 任务编号 + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @param cronExpression CRON 表达式 + * @param retryCount 重试次数 + * @param retryInterval 重试间隔 + * @throws SchedulerException 添加异常 + */ + public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) + throws SchedulerException { + validateScheduler(); + // 创建 JobDetail 对象 + JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) + .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId) + .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName) + .withIdentity(jobHandlerName).build(); + // 创建 Trigger 对象 + Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); + // 新增 Job 调度 + scheduler.scheduleJob(jobDetail, trigger); + } + + /** + * 更新 Job 到 Quartz + * + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @param cronExpression CRON 表达式 + * @param retryCount 重试次数 + * @param retryInterval 重试间隔 + * @throws SchedulerException 更新异常 + */ + public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) + throws SchedulerException { + validateScheduler(); + // 创建新 Trigger 对象 + Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); + // 修改调度 + scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); + } + + /** + * 删除 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 删除异常 + */ + public void deleteJob(String jobHandlerName) throws SchedulerException { + validateScheduler(); + // 暂停 Trigger 对象 + scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); + // 取消并删除 Job 调度 + scheduler.unscheduleJob(new TriggerKey(jobHandlerName)); + scheduler.deleteJob(new JobKey(jobHandlerName)); + } + + /** + * 暂停 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 暂停异常 + */ + public void pauseJob(String jobHandlerName) throws SchedulerException { + validateScheduler(); + scheduler.pauseJob(new JobKey(jobHandlerName)); + } + + /** + * 启动 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 启动异常 + */ + public void resumeJob(String jobHandlerName) throws SchedulerException { + validateScheduler(); + scheduler.resumeJob(new JobKey(jobHandlerName)); + scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); + } + + /** + * 立即触发一次 Quartz 中的 Job + * + * @param jobId 任务编号 + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @throws SchedulerException 触发异常 + */ + public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) + throws SchedulerException { + validateScheduler(); + // 触发任务 + JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval + data.put(JobDataKeyEnum.JOB_ID.name(), jobId); + data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); + data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); + scheduler.triggerJob(new JobKey(jobHandlerName), data); + } + + private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) { + return TriggerBuilder.newTrigger() + .withIdentity(jobHandlerName) + .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) + .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam) + .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount) + .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval) + .build(); + } + + private void validateScheduler() { + if (scheduler == null) { + throw exception0(NOT_IMPLEMENTED.getCode(), + "[定时任务 - 已禁用][参考 https://doc.iocoder.cn/job/ 开启]"); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java new file mode 100644 index 0000000..418dbfc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.quartz.core.service; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + * Job 日志 Framework Service 接口 + * + * @author 芋道源码 + */ +public interface JobLogFrameworkService { + + /** + * 创建 Job 日志 + * + * @param jobId 任务编号 + * @param beginTime 开始时间 + * @param jobHandlerName Job 处理器的名字 + * @param jobHandlerParam Job 处理器的参数 + * @param executeIndex 第几次执行 + * @return Job 日志的编号 + */ + Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId, + @NotNull(message = "开始时间") LocalDateTime beginTime, + @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName, + String jobHandlerParam, + @NotNull(message = "第几次执行不能为空") Integer executeIndex); + + /** + * 更新 Job 日志的执行结果 + * + * @param logId 日志编号 + * @param endTime 结束时间。因为是异步,避免记录时间不准去 + * @param duration 运行时长,单位:毫秒 + * @param success 是否成功 + * @param result 成功数据 + */ + void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId, + @NotNull(message = "结束时间不能为空") LocalDateTime endTime, + @NotNull(message = "运行时长不能为空") Integer duration, + boolean success, String result); +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java new file mode 100644 index 0000000..5658fa3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.quartz.core.util; + +import cn.hutool.core.date.LocalDateTimeUtil; +import org.quartz.CronExpression; + +import java.text.ParseException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Quartz Cron 表达式的工具类 + * + * @author 芋道源码 + */ +public class CronUtils { + + /** + * 校验 CRON 表达式是否有效 + * + * @param cronExpression CRON 表达式 + * @return 是否有效 + */ + public static boolean isValid(String cronExpression) { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 基于 CRON 表达式,获得下 n 个满足执行的时间 + * + * @param cronExpression CRON 表达式 + * @param n 数量 + * @return 满足条件的执行时间 + */ + public static List getNextTimes(String cronExpression, int n) { + // 1. 获得 CronExpression 对象 + CronExpression cron; + try { + cron = new CronExpression(cronExpression); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + // 2. 从当前开始计算,n 个满足条件的 + Date now = new Date(); + List nextTimes = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + Date nextTime = cron.getNextValidTimeAfter(now); + // 2.1 如果 nextTime 为 null,说明没有更多的有效时间,退出循环 + if (nextTime == null) { + break; + } + nextTimes.add(LocalDateTimeUtil.of(nextTime)); + // 2.2 切换现在,为下一个触发时间; + now = nextTime; + } + return nextTimes; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java new file mode 100644 index 0000000..cfd237b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java @@ -0,0 +1,7 @@ +/** + * 1. 定时任务,采用 Quartz 实现进程内的任务执行。 + * 考虑到高可用,使用 Quartz 自带的 MySQL 集群方案。 + * + * 2. 异步任务,采用 Spring Async 异步执行。 + */ +package cn.iocoder.yudao.framework.quartz; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..4086f7a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration +cn.iocoder.yudao.framework.quartz.config.YudaoAsyncAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 定时任务入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 定时任务入门》.md new file mode 100644 index 0000000..6564701 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 定时任务入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 异步任务入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 异步任务入门》.md new file mode 100644 index 0000000..5822b83 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-job/《芋道 Spring Boot 异步任务入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml new file mode 100644 index 0000000..ebd1210 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml @@ -0,0 +1,73 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-monitor + jar + + ${project.artifactId} + 服务监控,提供链路追踪、日志服务、指标收集等等功能 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.springframework + spring-web + provided + + + + jakarta.servlet + jakarta.servlet-api + provided + + + + + io.opentracing + opentracing-util + + + org.apache.skywalking + apm-toolkit-trace + + + org.apache.skywalking + apm-toolkit-logback-1.x + + + org.apache.skywalking + apm-toolkit-opentracing + + + + + io.micrometer + micrometer-registry-prometheus + + + + de.codecentric + spring-boot-admin-starter-client + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java new file mode 100644 index 0000000..11d25a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.framework.tracer.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * BizTracer配置类 + * + * @author 麻薯 + */ +@ConfigurationProperties("yudao.tracer") +@Data +public class TracerProperties { +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java new file mode 100644 index 0000000..cc2a0df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.tracer.config; + +import io.micrometer.core.instrument.MeterRegistry; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; + +/** + * Metrics 配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +@ConditionalOnClass({MeterRegistryCustomizer.class}) +@ConditionalOnProperty(prefix = "yudao.metrics", value = "enable", matchIfMissing = true) // 允许使用 yudao.metrics.enable=false 禁用 Metrics +public class YudaoMetricsAutoConfiguration { + + @Bean + public MeterRegistryCustomizer metricsCommonTags( + @Value("${spring.application.name}") String applicationName) { + return registry -> registry.config().commonTags("application", applicationName); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java new file mode 100644 index 0000000..c7d9e2c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.framework.tracer.config; + +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect; +import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +/** + * Tracer 配置类 + * + * @author mashu + */ +@AutoConfiguration +@ConditionalOnClass({BizTraceAspect.class}) +@EnableConfigurationProperties(TracerProperties.class) +@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true) +public class YudaoTracerAutoConfiguration { + + // TODO @芋艿:重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证阿里云短信 sdk +// @Bean +// public TracerProperties bizTracerProperties() { +// return new TracerProperties(); +// } +// +// @Bean +// public BizTraceAspect bizTracingAop() { +// return new BizTraceAspect(tracer()); +// } +// +// @Bean +// public Tracer tracer() { +// // 创建 SkywalkingTracer 对象 +// SkywalkingTracer tracer = new SkywalkingTracer(); +// // 设置为 GlobalTracer 的追踪器 +// GlobalTracer.register(tracer); +// return tracer; +// } + + /** + * 创建 TraceFilter 过滤器,响应 header 设置 traceId + */ + @Bean + public FilterRegistrationBean traceFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TraceFilter()); + registrationBean.setOrder(WebFilterOrderEnum.TRACE_FILTER); + return registrationBean; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java new file mode 100644 index 0000000..8b12140 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.tracer.core.annotation; + +import java.lang.annotation.*; + +/** + * 打印业务编号 / 业务类型注解 + * + * 使用时,需要设置 SkyWalking OAP Server 的 application.yaml 配置文件,修改 SW_SEARCHABLE_TAG_KEYS 配置项, + * 增加 biz.type 和 biz.id 两值,然后重启 SkyWalking OAP Server 服务器。 + * + * @author 麻薯 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface BizTrace { + + /** + * 业务编号 tag 名 + */ + String ID_TAG = "biz.id"; + /** + * 业务类型 tag 名 + */ + String TYPE_TAG = "biz.type"; + + /** + * @return 操作名 + */ + String operationName() default ""; + + /** + * @return 业务编号 + */ + String id(); + + /** + * @return 业务类型 + */ + String type(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java new file mode 100644 index 0000000..3c3b9f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.framework.tracer.core.aop; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.tracer.core.annotation.BizTrace; +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; +import cn.iocoder.yudao.framework.tracer.core.util.TracerFrameworkUtils; +import io.opentracing.Span; +import io.opentracing.Tracer; +import io.opentracing.tag.Tags; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import java.util.Map; + +import static java.util.Arrays.asList; + +/** + * {@link BizTrace} 切面,记录业务链路 + * + * @author mashu + */ +@Aspect +@AllArgsConstructor +@Slf4j +public class BizTraceAspect { + + private static final String BIZ_OPERATION_NAME_PREFIX = "Biz/"; + + private final Tracer tracer; + + @Around(value = "@annotation(trace)") + public Object around(ProceedingJoinPoint joinPoint, BizTrace trace) throws Throwable { + // 创建 span + String operationName = getOperationName(joinPoint, trace); + Span span = tracer.buildSpan(operationName) + .withTag(Tags.COMPONENT.getKey(), "biz") + .start(); + try { + // 执行原有方法 + return joinPoint.proceed(); + } catch (Throwable throwable) { + TracerFrameworkUtils.onError(throwable, span); + throw throwable; + } finally { + // 设置 Span 的 biz 属性 + setBizTag(span, joinPoint, trace); + // 完成 Span + span.finish(); + } + } + + private String getOperationName(ProceedingJoinPoint joinPoint, BizTrace trace) { + // 自定义操作名 + if (StrUtil.isNotEmpty(trace.operationName())) { + return BIZ_OPERATION_NAME_PREFIX + trace.operationName(); + } + // 默认操作名,使用方法名 + return BIZ_OPERATION_NAME_PREFIX + + joinPoint.getSignature().getDeclaringType().getSimpleName() + + "/" + joinPoint.getSignature().getName(); + } + + private void setBizTag(Span span, ProceedingJoinPoint joinPoint, BizTrace trace) { + try { + Map result = SpringExpressionUtils.parseExpressions(joinPoint, asList(trace.type(), trace.id())); + span.setTag(BizTrace.TYPE_TAG, MapUtil.getStr(result, trace.type())); + span.setTag(BizTrace.ID_TAG, MapUtil.getStr(result, trace.id())); + } catch (Exception ex) { + log.error("[setBizTag][解析 bizType 与 bizId 发生异常]", ex); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java new file mode 100644 index 0000000..91ac30f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.framework.tracer.core.filter; + +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Trace 过滤器,打印 traceId 到 header 中返回 + * + * @author 芋道源码 + */ +public class TraceFilter extends OncePerRequestFilter { + + /** + * Header 名 - 链路追踪编号 + */ + private static final String HEADER_NAME_TRACE_ID = "trace-id"; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws IOException, ServletException { + // 设置响应 traceId + response.addHeader(HEADER_NAME_TRACE_ID, TracerUtils.getTraceId()); + // 继续过滤 + chain.doFilter(request, response); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java new file mode 100644 index 0000000..51323e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/util/TracerFrameworkUtils.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.tracer.core.util; + +import io.opentracing.Span; +import io.opentracing.tag.Tags; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +/** + * 链路追踪 Util + * + * @author 芋道源码 + */ +public class TracerFrameworkUtils { + + /** + * 将异常记录到 Span 中,参考自 com.aliyuncs.utils.TraceUtils + * + * @param throwable 异常 + * @param span Span + */ + public static void onError(Throwable throwable, Span span) { + Tags.ERROR.set(span, Boolean.TRUE); + if (throwable != null) { + span.log(errorLogs(throwable)); + } + } + + private static Map errorLogs(Throwable throwable) { + Map errorLogs = new HashMap(10); + errorLogs.put("event", Tags.ERROR.getKey()); + errorLogs.put("error.object", throwable); + errorLogs.put("error.kind", throwable.getClass().getName()); + String message = throwable.getCause() != null ? throwable.getCause().getMessage() : throwable.getMessage(); + if (message != null) { + errorLogs.put("message", message); + } + StringWriter sw = new StringWriter(); + throwable.printStackTrace(new PrintWriter(sw)); + errorLogs.put("stack", sw.toString()); + return errorLogs; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java new file mode 100644 index 0000000..43ee5e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java @@ -0,0 +1,6 @@ +/** + * 使用 SkyWalking 组件,作为链路追踪、日志中心。 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.tracer; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..218ee31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +cn.iocoder.yudao.framework.tracer.config.YudaoTracerAutoConfiguration +cn.iocoder.yudao.framework.tracer.config.YudaoMetricsAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md new file mode 100644 index 0000000..7f898b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md new file mode 100644 index 0000000..b73a460 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md new file mode 100644 index 0000000..ed9d4fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/pom.xml new file mode 100644 index 0000000..c8972f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/pom.xml @@ -0,0 +1,43 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-mq + jar + + ${project.artifactId} + 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种 + https://github.com/YunaiV/ruoyi-vue-pro + + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + org.springframework.kafka + spring-kafka + true + + + org.springframework.amqp + spring-rabbit + true + + + org.apache.rocketmq + rocketmq-spring-boot-starter + true + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java new file mode 100644 index 0000000..3b716cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种 + */ +package cn.iocoder.yudao.framework.mq; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java new file mode 100644 index 0000000..af14673 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.mq.rabbitmq.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; + +/** + * RabbitMQ 消息队列配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +@Slf4j +@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate") +public class YudaoRabbitMQAutoConfiguration { + + /** + * Jackson2JsonMessageConverter Bean:使用 jackson 序列化消息 + */ + @Bean + public MessageConverter createMessageConverter() { + return new Jackson2JsonMessageConverter(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java new file mode 100644 index 0000000..2773b58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无特殊逻辑 + */ +package cn.iocoder.yudao.framework.mq.rabbitmq.core; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java new file mode 100644 index 0000000..9f6032c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列,基于 RabbitMQ 提供 + */ +package cn.iocoder.yudao.framework.mq.rabbitmq; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java new file mode 100644 index 0000000..d02e84b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java @@ -0,0 +1,151 @@ +package cn.iocoder.yudao.framework.mq.redis.config; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.common.enums.DocumentEnum; +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob; +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.connection.stream.Consumer; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.connection.stream.ReadOffset; +import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.List; +import java.util.Properties; + +/** + * Redis 消息队列 Consumer 配置类 + * + * @author 芋道源码 + */ +@Slf4j +@EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息 +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoRedisMQConsumerAutoConfiguration { + + /** + * 创建 Redis Pub/Sub 广播消费的容器 + */ + @Bean + @ConditionalOnBean(AbstractRedisChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听 + public RedisMessageListenerContainer redisMessageListenerContainer( + RedisMQTemplate redisMQTemplate, List> listeners) { + // 创建 RedisMessageListenerContainer 对象 + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + // 设置 RedisConnection 工厂。 + container.setConnectionFactory(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory()); + // 添加监听器 + listeners.forEach(listener -> { + listener.setRedisMQTemplate(redisMQTemplate); + container.addMessageListener(listener, new ChannelTopic(listener.getChannel())); + log.info("[redisMessageListenerContainer][注册 Channel({}) 对应的监听器({})]", + listener.getChannel(), listener.getClass().getName()); + }); + return container; + } + + /** + * 创建 Redis Stream 重新消费的任务 + */ + @Bean + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 + public RedisPendingMessageResendJob redisPendingMessageResendJob(List> listeners, + RedisMQTemplate redisTemplate, + @Value("${spring.application.name}") String groupName, + RedissonClient redissonClient) { + return new RedisPendingMessageResendJob(listeners, redisTemplate, groupName, redissonClient); + } + + /** + * 创建 Redis Stream 集群消费的容器 + * + * 基础知识:Redis Stream 的 xreadgroup 命令 + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听 + public StreamMessageListenerContainer> redisStreamMessageListenerContainer( + RedisMQTemplate redisMQTemplate, List> listeners) { + RedisTemplate redisTemplate = redisMQTemplate.getRedisTemplate(); + checkRedisVersion(redisTemplate); + // 第一步,创建 StreamMessageListenerContainer 容器 + // 创建 options 配置 + StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = + StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder() + .batchSize(10) // 一次性最多拉取多少条消息 + .targetType(String.class) // 目标类型。统一使用 String,通过自己封装的 AbstractStreamMessageListener 去反序列化 + .build(); + // 创建 container 对象 + StreamMessageListenerContainer> container = + StreamMessageListenerContainer.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions); + + // 第二步,注册监听器,消费对应的 Stream 主题 + String consumerName = buildConsumerName(); + listeners.parallelStream().forEach(listener -> { + log.info("[redisStreamMessageListenerContainer][开始注册 StreamKey({}) 对应的监听器({})]", + listener.getStreamKey(), listener.getClass().getName()); + // 创建 listener 对应的消费者分组 + try { + redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup()); + } catch (Exception ignore) { + } + // 设置 listener 对应的 redisTemplate + listener.setRedisMQTemplate(redisMQTemplate); + // 创建 Consumer 对象 + Consumer consumer = Consumer.from(listener.getGroup(), consumerName); + // 设置 Consumer 消费进度,以最小消费进度为准 + StreamOffset streamOffset = StreamOffset.create(listener.getStreamKey(), ReadOffset.lastConsumed()); + // 设置 Consumer 监听 + StreamMessageListenerContainer.StreamReadRequestBuilder builder = StreamMessageListenerContainer.StreamReadRequest + .builder(streamOffset).consumer(consumer) + .autoAcknowledge(false) // 不自动 ack + .cancelOnError(throwable -> false); // 默认配置,发生异常就取消消费,显然不符合预期;因此,我们设置为 false + container.register(builder.build(), listener); + log.info("[redisStreamMessageListenerContainer][完成注册 StreamKey({}) 对应的监听器({})]", + listener.getStreamKey(), listener.getClass().getName()); + }); + return container; + } + + /** + * 构建消费者名字,使用本地 IP + 进程编号的方式。 + * 参考自 RocketMQ clientId 的实现 + * + * @return 消费者名字 + */ + private static String buildConsumerName() { + return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); + } + + /** + * 校验 Redis 版本号,是否满足最低的版本号要求! + */ + private static void checkRedisVersion(RedisTemplate redisTemplate) { + // 获得 Redis 版本 + Properties info = redisTemplate.execute((RedisCallback) RedisServerCommands::info); + String version = MapUtil.getStr(info, "redis_version"); + // 校验最低版本必须大于等于 5.0.0 + int majorVersion = Integer.parseInt(StrUtil.subBefore(version, '.', false)); + if (majorVersion < 5) { + throw new IllegalStateException(StrUtil.format("您当前的 Redis 版本为 {},小于最低要求的 5.0.0 版本!" + + "请参考 {} 文档进行安装。", version, DocumentEnum.REDIS_INSTALL.getUrl())); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java new file mode 100644 index 0000000..c1950c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQProducerAutoConfiguration.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.mq.redis.config; + +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.List; + +/** + * Redis 消息队列 Producer 配置类 + * + * @author 芋道源码 + */ +@Slf4j +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoRedisMQProducerAutoConfiguration { + + @Bean + public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate, + List interceptors) { + RedisMQTemplate redisMQTemplate = new RedisMQTemplate(redisTemplate); + // 添加拦截器 + interceptors.forEach(redisMQTemplate::addInterceptor); + return redisMQTemplate; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java new file mode 100644 index 0000000..5755ffa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.framework.mq.redis.core; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage; +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.data.redis.connection.stream.RecordId; +import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.ArrayList; +import java.util.List; + +/** + * Redis MQ 操作模板类 + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class RedisMQTemplate { + + @Getter + private final RedisTemplate redisTemplate; + /** + * 拦截器数组 + */ + @Getter + private final List interceptors = new ArrayList<>(); + + /** + * 发送 Redis 消息,基于 Redis pub/sub 实现 + * + * @param message 消息 + */ + public void send(T message) { + try { + sendMessageBefore(message); + // 发送消息 + redisTemplate.convertAndSend(message.getChannel(), JsonUtils.toJsonString(message)); + } finally { + sendMessageAfter(message); + } + } + + /** + * 发送 Redis 消息,基于 Redis Stream 实现 + * + * @param message 消息 + * @return 消息记录的编号对象 + */ + public RecordId send(T message) { + try { + sendMessageBefore(message); + // 发送消息 + return redisTemplate.opsForStream().add(StreamRecords.newRecord() + .ofObject(JsonUtils.toJsonString(message)) // 设置内容 + .withStreamKey(message.getStreamKey())); // 设置 stream key + } finally { + sendMessageAfter(message); + } + } + + /** + * 添加拦截器 + * + * @param interceptor 拦截器 + */ + public void addInterceptor(RedisMessageInterceptor interceptor) { + interceptors.add(interceptor); + } + + private void sendMessageBefore(AbstractRedisMessage message) { + // 正序 + interceptors.forEach(interceptor -> interceptor.sendMessageBefore(message)); + } + + private void sendMessageAfter(AbstractRedisMessage message) { + // 倒序 + for (int i = interceptors.size() - 1; i >= 0; i--) { + interceptors.get(i).sendMessageAfter(message); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java new file mode 100644 index 0000000..dbcee7f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.mq.redis.core.interceptor; + +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; + +/** + * {@link AbstractRedisMessage} 消息拦截器 + * 通过拦截器,作为插件机制,实现拓展。 + * 例如说,多租户场景下的 MQ 消息处理 + * + * @author 芋道源码 + */ +public interface RedisMessageInterceptor { + + default void sendMessageBefore(AbstractRedisMessage message) { + } + + default void sendMessageAfter(AbstractRedisMessage message) { + } + + default void consumeMessageBefore(AbstractRedisMessage message) { + } + + default void consumeMessageAfter(AbstractRedisMessage message) { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java new file mode 100644 index 0000000..b84f17c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.framework.mq.redis.core.job; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.data.domain.Range; +import org.springframework.data.redis.connection.stream.*; +import org.springframework.data.redis.core.StreamOperations; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 这个任务用于处理,crash 之后的消费者未消费完的消息 + */ +@Slf4j +@AllArgsConstructor +public class RedisPendingMessageResendJob { + + private static final String LOCK_KEY = "redis:pending:msg:lock"; + + /** + * 消息超时时间,默认 5 分钟 + * + * 1. 超时的消息才会被重新投递 + * 2. 由于定时任务 1 分钟一次,消息超时后不会被立即重投,极端情况下消息5分钟过期后,再等 1 分钟才会被扫瞄到 + */ + private static final int EXPIRE_TIME = 5 * 60; + + private final List> listeners; + private final RedisMQTemplate redisTemplate; + private final String groupName; + private final RedissonClient redissonClient; + + /** + * 一分钟执行一次,这里选择每分钟的35秒执行,是为了避免整点任务过多的问题 + */ + @Scheduled(cron = "35 * * * * ?") + public void messageResend() { + RLock lock = redissonClient.getLock(LOCK_KEY); + // 尝试加锁 + if (lock.tryLock()) { + try { + execute(); + } catch (Exception ex) { + log.error("[messageResend][执行异常]", ex); + } finally { + lock.unlock(); + } + } + } + + /** + * 执行清理逻辑 + * + * @see 讨论 + */ + private void execute() { + StreamOperations ops = redisTemplate.getRedisTemplate().opsForStream(); + listeners.forEach(listener -> { + PendingMessagesSummary pendingMessagesSummary = Objects.requireNonNull(ops.pending(listener.getStreamKey(), groupName)); + // 每个消费者的 pending 队列消息数量 + Map pendingMessagesPerConsumer = pendingMessagesSummary.getPendingMessagesPerConsumer(); + pendingMessagesPerConsumer.forEach((consumerName, pendingMessageCount) -> { + log.info("[processPendingMessage][消费者({}) 消息数量({})]", consumerName, pendingMessageCount); + // 每个消费者的 pending消息的详情信息 + PendingMessages pendingMessages = ops.pending(listener.getStreamKey(), Consumer.from(groupName, consumerName), Range.unbounded(), pendingMessageCount); + if (pendingMessages.isEmpty()) { + return; + } + pendingMessages.forEach(pendingMessage -> { + // 获取消息上一次传递到 consumer 的时间, + long lastDelivery = pendingMessage.getElapsedTimeSinceLastDelivery().getSeconds(); + if (lastDelivery < EXPIRE_TIME){ + return; + } + // 获取指定 id 的消息体 + List> records = ops.range(listener.getStreamKey(), + Range.of(Range.Bound.inclusive(pendingMessage.getIdAsString()), Range.Bound.inclusive(pendingMessage.getIdAsString()))); + if (CollUtil.isEmpty(records)) { + return; + } + // 重新投递消息 + redisTemplate.getRedisTemplate().opsForStream().add(StreamRecords.newRecord() + .ofObject(records.get(0).getValue()) // 设置内容 + .withStreamKey(listener.getStreamKey())); + // ack 消息消费完成 + redisTemplate.getRedisTemplate().opsForStream().acknowledge(groupName, records.get(0)); + log.info("[processPendingMessage][消息({})重新投递成功]", records.get(0).getId()); + }); + }); + }); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java new file mode 100644 index 0000000..ee40814 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.mq.redis.core.message; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * Redis 消息抽象基类 + * + * @author 芋道源码 + */ +@Data +public abstract class AbstractRedisMessage { + + /** + * 头 + */ + private Map headers = new HashMap<>(); + + public String getHeader(String key) { + return headers.get(key); + } + + public void addHeader(String key, String value) { + headers.put(key, value); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java new file mode 100644 index 0000000..d5ea5b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.mq.redis.core.pubsub; + +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * Redis Channel Message 抽象类 + * + * @author 芋道源码 + */ +public abstract class AbstractRedisChannelMessage extends AbstractRedisMessage { + + /** + * 获得 Redis Channel,默认使用类名 + * + * @return Channel + */ + @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。 + public String getChannel() { + return getClass().getSimpleName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java new file mode 100644 index 0000000..fd7c910 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.framework.mq.redis.core.pubsub; + +import cn.hutool.core.util.TypeUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import lombok.Setter; +import lombok.SneakyThrows; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; + +import java.lang.reflect.Type; +import java.util.List; + +/** + * Redis Pub/Sub 监听器抽象类,用于实现广播消费 + * + * @param 消息类型。一定要填写噢,不然会报错 + * + * @author 芋道源码 + */ +public abstract class AbstractRedisChannelMessageListener implements MessageListener { + + /** + * 消息类型 + */ + private final Class messageType; + /** + * Redis Channel + */ + private final String channel; + /** + * RedisMQTemplate + */ + @Setter + private RedisMQTemplate redisMQTemplate; + + @SneakyThrows + protected AbstractRedisChannelMessageListener() { + this.messageType = getMessageClass(); + this.channel = messageType.getDeclaredConstructor().newInstance().getChannel(); + } + + /** + * 获得 Sub 订阅的 Redis Channel 通道 + * + * @return channel + */ + public final String getChannel() { + return channel; + } + + @Override + public final void onMessage(Message message, byte[] bytes) { + T messageObj = JsonUtils.parseObject(message.getBody(), messageType); + try { + consumeMessageBefore(messageObj); + // 消费消息 + this.onMessage(messageObj); + } finally { + consumeMessageAfter(messageObj); + } + } + + /** + * 处理消息 + * + * @param message 消息 + */ + public abstract void onMessage(T message); + + /** + * 通过解析类上的泛型,获得消息类型 + * + * @return 消息类型 + */ + @SuppressWarnings("unchecked") + private Class getMessageClass() { + Type type = TypeUtil.getTypeArgument(getClass(), 0); + if (type == null) { + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName())); + } + return (Class) type; + } + + private void consumeMessageBefore(AbstractRedisMessage message) { + assert redisMQTemplate != null; + List interceptors = redisMQTemplate.getInterceptors(); + // 正序 + interceptors.forEach(interceptor -> interceptor.consumeMessageBefore(message)); + } + + private void consumeMessageAfter(AbstractRedisMessage message) { + assert redisMQTemplate != null; + List interceptors = redisMQTemplate.getInterceptors(); + // 倒序 + for (int i = interceptors.size() - 1; i >= 0; i--) { + interceptors.get(i).consumeMessageAfter(message); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java new file mode 100644 index 0000000..9017e08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessage.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.mq.redis.core.stream; + +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * Redis Stream Message 抽象类 + * + * @author 芋道源码 + */ +public abstract class AbstractRedisStreamMessage extends AbstractRedisMessage { + + /** + * 获得 Redis Stream Key,默认使用类名 + * + * @return Channel + */ + @JsonIgnore // 避免序列化 + public String getStreamKey() { + return getClass().getSimpleName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java new file mode 100644 index 0000000..3e656af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/stream/AbstractRedisStreamMessageListener.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.framework.mq.redis.core.stream; + +import cn.hutool.core.util.TypeUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor; +import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage; +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.stream.StreamListener; + +import java.lang.reflect.Type; +import java.util.List; + +/** + * Redis Stream 监听器抽象类,用于实现集群消费 + * + * @param 消息类型。一定要填写噢,不然会报错 + * + * @author 芋道源码 + */ +public abstract class AbstractRedisStreamMessageListener + implements StreamListener> { + + /** + * 消息类型 + */ + private final Class messageType; + /** + * Redis Channel + */ + @Getter + private final String streamKey; + + /** + * Redis 消费者分组,默认使用 spring.application.name 名字 + */ + @Value("${spring.application.name}") + @Getter + private String group; + /** + * RedisMQTemplate + */ + @Setter + private RedisMQTemplate redisMQTemplate; + + @SneakyThrows + protected AbstractRedisStreamMessageListener() { + this.messageType = getMessageClass(); + this.streamKey = messageType.getDeclaredConstructor().newInstance().getStreamKey(); + } + + @Override + public void onMessage(ObjectRecord message) { + // 消费消息 + T messageObj = JsonUtils.parseObject(message.getValue(), messageType); + try { + consumeMessageBefore(messageObj); + // 消费消息 + this.onMessage(messageObj); + // ack 消息消费完成 + redisMQTemplate.getRedisTemplate().opsForStream().acknowledge(group, message); + // TODO 芋艿:需要额外考虑以下几个点: + // 1. 处理异常的情况 + // 2. 发送日志;以及事务的结合 + // 3. 消费日志;以及通用的幂等性 + // 4. 消费失败的重试,https://zhuanlan.zhihu.com/p/60501638 + } finally { + consumeMessageAfter(messageObj); + } + } + + /** + * 处理消息 + * + * @param message 消息 + */ + public abstract void onMessage(T message); + + /** + * 通过解析类上的泛型,获得消息类型 + * + * @return 消息类型 + */ + @SuppressWarnings("unchecked") + private Class getMessageClass() { + Type type = TypeUtil.getTypeArgument(getClass(), 0); + if (type == null) { + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName())); + } + return (Class) type; + } + + private void consumeMessageBefore(AbstractRedisMessage message) { + assert redisMQTemplate != null; + List interceptors = redisMQTemplate.getInterceptors(); + // 正序 + interceptors.forEach(interceptor -> interceptor.consumeMessageBefore(message)); + } + + private void consumeMessageAfter(AbstractRedisMessage message) { + assert redisMQTemplate != null; + List interceptors = redisMQTemplate.getInterceptors(); + // 倒序 + for (int i = interceptors.size() - 1; i >= 0; i--) { + interceptors.get(i).consumeMessageAfter(message); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java new file mode 100644 index 0000000..6621fc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/package-info.java @@ -0,0 +1,6 @@ +/** + * 消息队列,基于 Redis 提供: + * 1. 基于 Pub/Sub 实现广播消费 + * 2. 基于 Stream 实现集群消费 + */ +package cn.iocoder.yudao.framework.mq.redis; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..213850b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQProducerAutoConfiguration +cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration +cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md new file mode 100644 index 0000000..08586b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md new file mode 100644 index 0000000..b66d633 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md new file mode 100644 index 0000000..eff46e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md new file mode 100644 index 0000000..08586b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml new file mode 100644 index 0000000..89e0611 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -0,0 +1,95 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-mybatis + jar + + ${project.artifactId} + 数据库连接池、多数据源、事务、MyBatis 拓展 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + provided + + + + + com.mysql + mysql-connector-j + + + com.oracle.database.jdbc + ojdbc8 + true + + + org.postgresql + postgresql + true + + + com.microsoft.sqlserver + mssql-jdbc + true + + + com.dameng + DmJdbcDriver18 + true + + + cn.com.kingbase + kingbase8 + true + + + org.opengauss + opengauss-jdbc + true + + + + com.alibaba + druid-spring-boot-starter + + + com.baomidou + mybatis-plus-boot-starter + + + com.baomidou + dynamic-datasource-spring-boot-starter + + + + com.github.yulichang + mybatis-plus-join-boot-starter + + + + com.fhs-opensource + easy-trans-spring-boot-starter + + + com.fhs-opensource + easy-trans-mybatis-plus-extend + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java new file mode 100644 index 0000000..7032b48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.datasource.config; + +import cn.iocoder.yudao.framework.datasource.core.filter.DruidAdRemoveFilter; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +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; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * 数据库配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理 +@EnableConfigurationProperties(DruidStatProperties.class) +public class YudaoDataSourceAutoConfiguration { + + /** + * 创建 DruidAdRemoveFilter 过滤器,过滤 common.js 的广告 + */ + @Bean + @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true") + public FilterRegistrationBean druidAdRemoveFilterFilter(DruidStatProperties properties) { + // 获取 druid web 监控页面的参数 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); + // 提取 common.js 的配置路径 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); + // 创建 DruidAdRemoveFilter Bean + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new DruidAdRemoveFilter()); + registrationBean.addUrlPatterns(commonJsPattern); + return registrationBean; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java new file mode 100644 index 0000000..c99a256 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.datasource.core.enums; + +/** + * 对应于多数据源中不同数据源配置 + * + * 通过在方法上,使用 {@link com.baomidou.dynamic.datasource.annotation.DS} 注解,设置使用的数据源。 + * 注意,默认是 {@link #MASTER} 数据源 + * + * 对应官方文档为 http://dynamic-datasource.com/guide/customize/Annotation.html + */ +public interface DataSourceEnum { + + /** + * 主库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Master} 注解 + */ + String MASTER = "master"; + /** + * 从库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Slave} 注解 + */ + String SLAVE = "slave"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java new file mode 100644 index 0000000..78e8a3e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.datasource.core.filter; + +import com.alibaba.druid.util.Utils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Druid 底部广告过滤器 + * + * @author 芋道源码 + */ +public class DruidAdRemoveFilter extends OncePerRequestFilter { + + /** + * common.js 的路径 + */ + private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js"; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + chain.doFilter(request, response); + // 重置缓冲区,响应头不会被重置 + response.resetBuffer(); + // 获取 common.js + String text = Utils.readFromResource(COMMON_JS_ILE_PATH); + // 正则替换 banner, 除去底部的广告信息 + text = text.replaceAll("
", ""); + text = text.replaceAll("powered.*?shrek.wang", ""); + response.getWriter().write(text); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java new file mode 100644 index 0000000..8512891 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java @@ -0,0 +1,5 @@ +/** + * 数据库连接池,采用 Druid + * 多数据源,采用爆米花 + */ +package cn.iocoder.yudao.framework.datasource; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java new file mode 100644 index 0000000..b8c8e0b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.framework.mybatis.config; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants; +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.annotation.IdType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; + +import java.util.Set; + +/** + * 当 IdType 为 {@link IdType#NONE} 时,根据 PRIMARY 数据源所使用的数据库,自动设置 + * + * @author 芋道源码 + */ +@Slf4j +public class IdTypeEnvironmentPostProcessor implements EnvironmentPostProcessor { + + private static final String ID_TYPE_KEY = "mybatis-plus.global-config.db-config.id-type"; + + private static final String DATASOURCE_DYNAMIC_KEY = "spring.datasource.dynamic"; + + private static final String QUARTZ_JOB_STORE_DRIVER_KEY = "spring.quartz.properties.org.quartz.jobStore.driverDelegateClass"; + + private static final Set INPUT_ID_TYPES = SetUtils.asSet(DbType.ORACLE, DbType.ORACLE_12C, + DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.DB2, DbType.H2); + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + // 如果获取不到 DbType,则不进行处理 + DbType dbType = getDbType(environment); + if (dbType == null) { + return; + } + + // 设置 Quartz JobStore 对应的 Driver + // TODO 芋艿:暂时没有找到特别合适的地方,先放在这里 + setJobStoreDriverIfPresent(environment, dbType); + + // 初始化 SQL 静态变量 + SqlConstants.init(dbType); + + // 如果非 NONE,则不进行处理 + IdType idType = getIdType(environment); + if (idType != IdType.NONE) { + return; + } + // 情况一,用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 + if (INPUT_ID_TYPES.contains(dbType)) { + setIdType(environment, IdType.INPUT); + return; + } + // 情况二,自增 ID,适合 MySQL 等直接自增的数据库 + setIdType(environment, IdType.AUTO); + } + + public IdType getIdType(ConfigurableEnvironment environment) { + return environment.getProperty(ID_TYPE_KEY, IdType.class); + } + + public void setIdType(ConfigurableEnvironment environment, IdType idType) { + environment.getSystemProperties().put(ID_TYPE_KEY, idType); + log.info("[setIdType][修改 MyBatis Plus 的 idType 为({})]", idType); + } + + public void setJobStoreDriverIfPresent(ConfigurableEnvironment environment, DbType dbType) { + String driverClass = environment.getProperty(QUARTZ_JOB_STORE_DRIVER_KEY); + if (StrUtil.isNotEmpty(driverClass)) { + return; + } + // 根据 dbType 类型,获取对应的 driverClass + switch (dbType) { + case POSTGRE_SQL: + driverClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; + break; + case ORACLE: + case ORACLE_12C: + driverClass = "org.quartz.impl.jdbcjobstore.oracle.OracleDelegate"; + break; + case SQL_SERVER: + case SQL_SERVER2005: + driverClass = "org.quartz.impl.jdbcjobstore.MSSQLDelegate"; + break; + } + // 设置 driverClass 变量 + if (StrUtil.isNotEmpty(driverClass)) { + environment.getSystemProperties().put(QUARTZ_JOB_STORE_DRIVER_KEY, driverClass); + } + } + + public static DbType getDbType(ConfigurableEnvironment environment) { + String primary = environment.getProperty(DATASOURCE_DYNAMIC_KEY + "." + "primary"); + if (StrUtil.isEmpty(primary)) { + return null; + } + String url = environment.getProperty(DATASOURCE_DYNAMIC_KEY + ".datasource." + primary + ".url"); + if (StrUtil.isEmpty(url)) { + return null; + } + return JdbcUtils.getDbType(url); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java new file mode 100644 index 0000000..d685fd8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.mybatis.config; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.extension.incrementer.*; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.apache.ibatis.annotations.Mapper; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * MyBaits 配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration(before = MybatisPlusAutoConfiguration.class) // 目的:先于 MyBatis Plus 自动配置,避免 @MapperScan 可能扫描不到 Mapper 打印 warn 日志 +@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class, + lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试 +public class YudaoMybatisAutoConfiguration { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); + mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件 + return mybatisPlusInterceptor; + } + + @Bean + public MetaObjectHandler defaultMetaObjectHandler(){ + return new DefaultDBFieldHandler(); // 自动填充参数类 + } + + @Bean + @ConditionalOnProperty(prefix = "mybatis-plus.global-config.db-config", name = "id-type", havingValue = "INPUT") + public IKeyGenerator keyGenerator(ConfigurableEnvironment environment) { + DbType dbType = IdTypeEnvironmentPostProcessor.getDbType(environment); + if (dbType != null) { + switch (dbType) { + case POSTGRE_SQL: + return new PostgreKeyGenerator(); + case ORACLE: + case ORACLE_12C: + return new OracleKeyGenerator(); + case H2: + return new H2KeyGenerator(); + case KINGBASE_ES: + return new KingbaseKeyGenerator(); + case DM: + return new DmKeyGenerator(); + } + } + // 找不到合适的 IKeyGenerator 实现类 + throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java new file mode 100644 index 0000000..fc5f0a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.mybatis.core.dataobject; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fhs.core.trans.vo.TransPojo; +import lombok.Data; +import org.apache.ibatis.type.JdbcType; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 基础实体对象 + * + * 为什么实现 {@link TransPojo} 接口? + * 因为使用 Easy-Trans TransType.SIMPLE 模式,集成 MyBatis Plus 查询 + * + * @author 芋道源码 + */ +@Data +@JsonIgnoreProperties(value = "transMap") // 由于 Easy-Trans 会添加 transMap 属性,避免 Jackson 在 Spring Cache 反序列化报错 +public abstract class BaseDO implements Serializable, TransPojo { + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + /** + * 最后更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + /** + * 创建者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + @TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR) + private String creator; + /** + * 更新者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR) + private String updater; + /** + * 是否删除 + */ + @TableLogic + private Boolean deleted; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java new file mode 100644 index 0000000..974986f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.framework.mybatis.core.enums; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.DbType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 针对 MyBatis Plus 的 {@link DbType} 增强,补充更多信息 + */ +@Getter +@AllArgsConstructor +public enum DbTypeEnum { + + /** + * MySQL + */ + MY_SQL( DbType.MYSQL, "MySQL", "FIND_IN_SET('#{value}', #{column}) <> 0"), + + /** + * Oracle + */ + ORACLE(DbType.ORACLE, "Oracle", "FIND_IN_SET('#{value}', #{column}) <> 0"), + + /** + * PostgreSQL + * + * 华为 openGauss 使用 ProductName 与 PostgreSQL 相同 + */ + POSTGRE_SQL(DbType.POSTGRE_SQL,"PostgreSQL", "POSITION('#{value}' IN #{column}) <> 0"), + + /** + * SQL Server + */ + SQL_SERVER(DbType.SQL_SERVER, "Microsoft SQL Server", "CHARINDEX(',' + #{value} + ',', ',' + #{column} + ',') <> 0"), + + /** + * 达梦 + */ + DM(DbType.DM, "DM DBMS", "FIND_IN_SET('#{value}', #{column}) <> 0"), + + /** + * 人大金仓 + */ + KINGBASE_ES(DbType.KINGBASE_ES, "KingbaseES", "POSITION('#{value}' IN #{column}) <> 0"), + ; + + public static final Map MAP_BY_NAME = Arrays.stream(values()) + .collect(Collectors.toMap(DbTypeEnum::getProductName, Function.identity())); + + public static final Map MAP_BY_MP = Arrays.stream(values()) + .collect(Collectors.toMap(DbTypeEnum::getMpDbType, Function.identity())); + + /** + * MyBatis Plus 类型 + */ + private final DbType mpDbType; + /** + * 数据库产品名 + */ + private final String productName; + /** + * SQL FIND_IN_SET 模板 + */ + private final String findInSetTemplate; + + public static DbType find(String databaseProductName) { + if (StrUtil.isBlank(databaseProductName)) { + return null; + } + return MAP_BY_NAME.get(databaseProductName).getMpDbType(); + } + + public static String getFindInSetTemplate(DbType dbType) { + return Optional.of(MAP_BY_MP.get(dbType).getFindInSetTemplate()) + .orElseThrow(() -> new IllegalArgumentException("FIND_IN_SET not supported")); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/SqlConstants.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/SqlConstants.java new file mode 100644 index 0000000..d775f17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/SqlConstants.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.mybatis.core.enums; + +import com.baomidou.mybatisplus.annotation.DbType; + +/** + * SQL相关常量类 + * + * @author 芋道源码 + */ +public class SqlConstants { + + /** + * 数据库的类型 + */ + public static DbType DB_TYPE; + + public static void init(DbType dbType) { + DB_TYPE = dbType; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java new file mode 100644 index 0000000..94dada1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.mybatis.core.handler; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import org.apache.ibatis.reflection.MetaObject; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * 通用参数填充实现类 + * + * 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值 + * + * @author hexiaowu + */ +public class DefaultDBFieldHandler implements MetaObjectHandler { + + @Override + public void insertFill(MetaObject metaObject) { + if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) { + BaseDO baseDO = (BaseDO) metaObject.getOriginalObject(); + + LocalDateTime current = LocalDateTime.now(); + // 创建时间为空,则以当前时间为插入时间 + if (Objects.isNull(baseDO.getCreateTime())) { + baseDO.setCreateTime(current); + } + // 更新时间为空,则以当前时间为更新时间 + if (Objects.isNull(baseDO.getUpdateTime())) { + baseDO.setUpdateTime(current); + } + + Long userId = WebFrameworkUtils.getLoginUserId(); + // 当前登录用户不为空,创建人为空,则当前登录用户为创建人 + if (Objects.nonNull(userId) && Objects.isNull(baseDO.getCreator())) { + baseDO.setCreator(userId.toString()); + } + // 当前登录用户不为空,更新人为空,则当前登录用户为更新人 + if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) { + baseDO.setUpdater(userId.toString()); + } + } + } + + @Override + public void updateFill(MetaObject metaObject) { + // 更新时间为空,则以当前时间为更新时间 + Object modifyTime = getFieldValByName("updateTime", metaObject); + if (Objects.isNull(modifyTime)) { + setFieldValByName("updateTime", LocalDateTime.now(), metaObject); + } + + // 当前登录用户不为空,更新人为空,则当前登录用户为更新人 + Object modifier = getFieldValByName("updater", metaObject); + Long userId = WebFrameworkUtils.getLoginUserId(); + if (Objects.nonNull(userId) && Objects.isNull(modifier)) { + setFieldValByName("updater", userId.toString(), metaObject); + } + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java new file mode 100644 index 0000000..e7767c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -0,0 +1,204 @@ +package cn.iocoder.yudao.framework.mybatis.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.framework.common.pojo.SortingField; +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import com.github.yulichang.base.MPJBaseMapper; +import com.github.yulichang.interfaces.MPJBaseJoin; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 + * + * 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口,提供基础的 CRUD 能力 + * 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口,提供连表 Join 能力 + */ +public interface BaseMapperX extends MPJBaseMapper { + + default PageResult selectPage(SortablePageParam pageParam, @Param("ew") Wrapper queryWrapper) { + return selectPage(pageParam, pageParam.getSortingFields(), queryWrapper); + } + + default PageResult selectPage(PageParam pageParam, @Param("ew") Wrapper queryWrapper) { + return selectPage(pageParam, null, queryWrapper); + } + + default PageResult selectPage(PageParam pageParam, Collection sortingFields, @Param("ew") Wrapper queryWrapper) { + // 特殊:不分页,直接查询全部 + if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageSize())) { + List list = selectList(queryWrapper); + return new PageResult<>(list, (long) list.size()); + } + + // MyBatis Plus 查询 + IPage mpPage = MyBatisUtils.buildPage(pageParam, sortingFields); + selectPage(mpPage, queryWrapper); + // 转换返回 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); + } + + default PageResult selectJoinPage(PageParam pageParam, Class clazz, MPJLambdaWrapper lambdaWrapper) { + // 特殊:不分页,直接查询全部 + if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageNo())) { + List list = selectJoinList(clazz, lambdaWrapper); + return new PageResult<>(list, (long) list.size()); + } + + // MyBatis Plus Join 查询 + IPage mpPage = MyBatisUtils.buildPage(pageParam); + mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper); + // 转换返回 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); + } + + default PageResult selectJoinPage(PageParam pageParam, Class resultTypeClass, MPJBaseJoin joinQueryWrapper) { + IPage mpPage = MyBatisUtils.buildPage(pageParam); + selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper); + // 转换返回 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); + } + + default T selectOne(String field, Object value) { + return selectOne(new QueryWrapper().eq(field, value)); + } + + default T selectOne(SFunction field, Object value) { + return selectOne(new LambdaQueryWrapper().eq(field, value)); + } + + default T selectOne(String field1, Object value1, String field2, Object value2) { + return selectOne(new QueryWrapper().eq(field1, value1).eq(field2, value2)); + } + + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2)); + } + + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2, + SFunction field3, Object value3) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2) + .eq(field3, value3)); + } + + default Long selectCount() { + return selectCount(new QueryWrapper<>()); + } + + default Long selectCount(String field, Object value) { + return selectCount(new QueryWrapper().eq(field, value)); + } + + default Long selectCount(SFunction field, Object value) { + return selectCount(new LambdaQueryWrapper().eq(field, value)); + } + + default List selectList() { + return selectList(new QueryWrapper<>()); + } + + default List selectList(String field, Object value) { + return selectList(new QueryWrapper().eq(field, value)); + } + + default List selectList(SFunction field, Object value) { + return selectList(new LambdaQueryWrapper().eq(field, value)); + } + + default List selectList(String field, Collection values) { + if (CollUtil.isEmpty(values)) { + return CollUtil.newArrayList(); + } + return selectList(new QueryWrapper().in(field, values)); + } + + default List selectList(SFunction field, Collection values) { + if (CollUtil.isEmpty(values)) { + return CollUtil.newArrayList(); + } + return selectList(new LambdaQueryWrapper().in(field, values)); + } + + @Deprecated + default List selectList(SFunction leField, SFunction geField, Object value) { + return selectList(new LambdaQueryWrapper().le(leField, value).ge(geField, value)); + } + + default List selectList(SFunction field1, Object value1, SFunction field2, Object value2) { + return selectList(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2)); + } + + /** + * 批量插入,适合大量数据插入 + * + * @param entities 实体们 + */ + default Boolean insertBatch(Collection entities) { + // 特殊:SQL Server 批量插入后,获取 id 会报错,因此通过循环处理 + if (Objects.equals(SqlConstants.DB_TYPE, DbType.SQL_SERVER)) { + entities.forEach(this::insert); + return CollUtil.isNotEmpty(entities); + } + return Db.saveBatch(entities); + } + + /** + * 批量插入,适合大量数据插入 + * + * @param entities 实体们 + * @param size 插入数量 Db.saveBatch 默认为 1000 + */ + default Boolean insertBatch(Collection entities, int size) { + // 特殊:SQL Server 批量插入后,获取 id 会报错,因此通过循环处理 + if (Objects.equals(SqlConstants.DB_TYPE, DbType.SQL_SERVER)) { + entities.forEach(this::insert); + return CollUtil.isNotEmpty(entities); + } + return Db.saveBatch(entities, size); + } + + default int updateBatch(T update) { + return update(update, new QueryWrapper<>()); + } + + default Boolean updateBatch(Collection entities) { + return Db.updateBatchById(entities); + } + + default Boolean updateBatch(Collection entities, int size) { + return Db.updateBatchById(entities, size); + } + + default Boolean insertOrUpdate(T entity) { + return Db.saveOrUpdate(entity); + } + + default Boolean insertOrUpdateBatch(Collection collection) { + return Db.saveOrUpdateBatch(collection); + } + + default int delete(String field, String value) { + return delete(new QueryWrapper().eq(field, value)); + } + + default int delete(SFunction field, Object value) { + return delete(new LambdaQueryWrapper().eq(field, value)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java new file mode 100644 index 0000000..a728365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.framework.mybatis.core.query; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import org.springframework.util.StringUtils; + +import java.util.Collection; + +/** + * 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能: + *

+ * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。 + * + * @param 数据类型 + */ +public class LambdaQueryWrapperX extends LambdaQueryWrapper { + + public LambdaQueryWrapperX likeIfPresent(SFunction column, String val) { + if (StringUtils.hasText(val)) { + return (LambdaQueryWrapperX) super.like(column, val); + } + return this; + } + + public LambdaQueryWrapperX inIfPresent(SFunction column, Collection values) { + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { + return (LambdaQueryWrapperX) super.in(column, values); + } + return this; + } + + public LambdaQueryWrapperX inIfPresent(SFunction column, Object... values) { + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { + return (LambdaQueryWrapperX) super.in(column, values); + } + return this; + } + + public LambdaQueryWrapperX eqIfPresent(SFunction column, Object val) { + if (ObjectUtil.isNotEmpty(val)) { + return (LambdaQueryWrapperX) super.eq(column, val); + } + return this; + } + + public LambdaQueryWrapperX neIfPresent(SFunction column, Object val) { + if (ObjectUtil.isNotEmpty(val)) { + return (LambdaQueryWrapperX) super.ne(column, val); + } + return this; + } + + public LambdaQueryWrapperX gtIfPresent(SFunction column, Object val) { + if (val != null) { + return (LambdaQueryWrapperX) super.gt(column, val); + } + return this; + } + + public LambdaQueryWrapperX geIfPresent(SFunction column, Object val) { + if (val != null) { + return (LambdaQueryWrapperX) super.ge(column, val); + } + return this; + } + + public LambdaQueryWrapperX ltIfPresent(SFunction column, Object val) { + if (val != null) { + return (LambdaQueryWrapperX) super.lt(column, val); + } + return this; + } + + public LambdaQueryWrapperX leIfPresent(SFunction column, Object val) { + if (val != null) { + return (LambdaQueryWrapperX) super.le(column, val); + } + return this; + } + + public LambdaQueryWrapperX betweenIfPresent(SFunction column, Object val1, Object val2) { + if (val1 != null && val2 != null) { + return (LambdaQueryWrapperX) super.between(column, val1, val2); + } + if (val1 != null) { + return (LambdaQueryWrapperX) ge(column, val1); + } + if (val2 != null) { + return (LambdaQueryWrapperX) le(column, val2); + } + return this; + } + + public LambdaQueryWrapperX betweenIfPresent(SFunction column, Object[] values) { + Object val1 = ArrayUtils.get(values, 0); + Object val2 = ArrayUtils.get(values, 1); + return betweenIfPresent(column, val1, val2); + } + + // ========== 重写父类方法,方便链式调用 ========== + + @Override + public LambdaQueryWrapperX eq(boolean condition, SFunction column, Object val) { + super.eq(condition, column, val); + return this; + } + + @Override + public LambdaQueryWrapperX eq(SFunction column, Object val) { + super.eq(column, val); + return this; + } + + @Override + public LambdaQueryWrapperX orderByDesc(SFunction column) { + super.orderByDesc(true, column); + return this; + } + + @Override + public LambdaQueryWrapperX last(String lastSql) { + super.last(lastSql); + return this; + } + + @Override + public LambdaQueryWrapperX in(SFunction column, Collection coll) { + super.in(column, coll); + return this; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java new file mode 100644 index 0000000..7950a2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java @@ -0,0 +1,313 @@ +package cn.iocoder.yudao.framework.mybatis.core.query; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.github.yulichang.toolkit.MPJWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.function.Consumer; + +/** + * 拓展 MyBatis Plus Join QueryWrapper 类,主要增加如下功能: + *

+ * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。 + * + * @param 数据类型 + */ +public class MPJLambdaWrapperX extends MPJLambdaWrapper { + + public MPJLambdaWrapperX likeIfPresent(SFunction column, String val) { + MPJWrappers.lambdaJoin().like(column, val); + if (StringUtils.hasText(val)) { + return (MPJLambdaWrapperX) super.like(column, val); + } + return this; + } + + public MPJLambdaWrapperX inIfPresent(SFunction column, Collection values) { + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { + return (MPJLambdaWrapperX) super.in(column, values); + } + return this; + } + + public MPJLambdaWrapperX inIfPresent(SFunction column, Object... values) { + if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { + return (MPJLambdaWrapperX) super.in(column, values); + } + return this; + } + + public MPJLambdaWrapperX eqIfPresent(SFunction column, Object val) { + if (ObjectUtil.isNotEmpty(val)) { + return (MPJLambdaWrapperX) super.eq(column, val); + } + return this; + } + + public MPJLambdaWrapperX neIfPresent(SFunction column, Object val) { + if (ObjectUtil.isNotEmpty(val)) { + return (MPJLambdaWrapperX) super.ne(column, val); + } + return this; + } + + public MPJLambdaWrapperX gtIfPresent(SFunction column, Object val) { + if (val != null) { + return (MPJLambdaWrapperX) super.gt(column, val); + } + return this; + } + + public MPJLambdaWrapperX geIfPresent(SFunction column, Object val) { + if (val != null) { + return (MPJLambdaWrapperX) super.ge(column, val); + } + return this; + } + + public MPJLambdaWrapperX ltIfPresent(SFunction column, Object val) { + if (val != null) { + return (MPJLambdaWrapperX) super.lt(column, val); + } + return this; + } + + public MPJLambdaWrapperX leIfPresent(SFunction column, Object val) { + if (val != null) { + return (MPJLambdaWrapperX) super.le(column, val); + } + return this; + } + + public MPJLambdaWrapperX betweenIfPresent(SFunction column, Object val1, Object val2) { + if (val1 != null && val2 != null) { + return (MPJLambdaWrapperX) super.between(column, val1, val2); + } + if (val1 != null) { + return (MPJLambdaWrapperX) ge(column, val1); + } + if (val2 != null) { + return (MPJLambdaWrapperX) le(column, val2); + } + return this; + } + + public MPJLambdaWrapperX betweenIfPresent(SFunction column, Object[] values) { + Object val1 = ArrayUtils.get(values, 0); + Object val2 = ArrayUtils.get(values, 1); + return betweenIfPresent(column, val1, val2); + } + + // ========== 重写父类方法,方便链式调用 ========== + + @Override + public MPJLambdaWrapperX eq(boolean condition, SFunction column, Object val) { + super.eq(condition, column, val); + return this; + } + + @Override + public MPJLambdaWrapperX eq(SFunction column, Object val) { + super.eq(column, val); + return this; + } + + @Override + public MPJLambdaWrapperX orderByDesc(SFunction column) { + //noinspection unchecked + super.orderByDesc(true, column); + return this; + } + + @Override + public MPJLambdaWrapperX last(String lastSql) { + super.last(lastSql); + return this; + } + + @Override + public MPJLambdaWrapperX in(SFunction column, Collection coll) { + super.in(column, coll); + return this; + } + + @Override + public MPJLambdaWrapperX selectAll(Class clazz) { + super.selectAll(clazz); + return this; + } + + @Override + public MPJLambdaWrapperX selectAll(Class clazz, String prefix) { + super.selectAll(clazz, prefix); + return this; + } + + @Override + public MPJLambdaWrapperX selectAs(SFunction column, String alias) { + super.selectAs(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAs(String column, SFunction alias) { + super.selectAs(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAs(SFunction column, SFunction alias) { + super.selectAs(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAs(String index, SFunction column, SFunction alias) { + super.selectAs(index, column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAsClass(Class source, Class tag) { + super.selectAsClass(source, tag); + return this; + } + + @Override + public MPJLambdaWrapperX selectSub(Class clazz, Consumer> consumer, SFunction alias) { + super.selectSub(clazz, consumer, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectSub(Class clazz, String st, Consumer> consumer, SFunction alias) { + super.selectSub(clazz, st, consumer, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectCount(SFunction column) { + super.selectCount(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectCount(Object column, String alias) { + super.selectCount(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectCount(Object column, SFunction alias) { + super.selectCount(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectCount(SFunction column, String alias) { + super.selectCount(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectCount(SFunction column, SFunction alias) { + super.selectCount(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectSum(SFunction column) { + super.selectSum(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectSum(SFunction column, String alias) { + super.selectSum(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectSum(SFunction column, SFunction alias) { + super.selectSum(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectMax(SFunction column) { + super.selectMax(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectMax(SFunction column, String alias) { + super.selectMax(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectMax(SFunction column, SFunction alias) { + super.selectMax(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectMin(SFunction column) { + super.selectMin(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectMin(SFunction column, String alias) { + super.selectMin(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectMin(SFunction column, SFunction alias) { + super.selectMin(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAvg(SFunction column) { + super.selectAvg(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectAvg(SFunction column, String alias) { + super.selectAvg(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectAvg(SFunction column, SFunction alias) { + super.selectAvg(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectLen(SFunction column) { + super.selectLen(column); + return this; + } + + @Override + public MPJLambdaWrapperX selectLen(SFunction column, String alias) { + super.selectLen(column, alias); + return this; + } + + @Override + public MPJLambdaWrapperX selectLen(SFunction column, SFunction alias) { + super.selectLen(column, alias); + return this; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java new file mode 100644 index 0000000..eec4172 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java @@ -0,0 +1,166 @@ +package cn.iocoder.yudao.framework.mybatis.core.query; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.Collection; + +/** + * 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能: + * + * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。 + * + * @param 数据类型 + */ +public class QueryWrapperX extends QueryWrapper { + + public QueryWrapperX likeIfPresent(String column, String val) { + if (StringUtils.hasText(val)) { + return (QueryWrapperX) super.like(column, val); + } + return this; + } + + public QueryWrapperX inIfPresent(String column, Collection values) { + if (!CollectionUtils.isEmpty(values)) { + return (QueryWrapperX) super.in(column, values); + } + return this; + } + + public QueryWrapperX inIfPresent(String column, Object... values) { + if (!ArrayUtils.isEmpty(values)) { + return (QueryWrapperX) super.in(column, values); + } + return this; + } + + public QueryWrapperX eqIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.eq(column, val); + } + return this; + } + + public QueryWrapperX neIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.ne(column, val); + } + return this; + } + + public QueryWrapperX gtIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.gt(column, val); + } + return this; + } + + public QueryWrapperX geIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.ge(column, val); + } + return this; + } + + public QueryWrapperX ltIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.lt(column, val); + } + return this; + } + + public QueryWrapperX leIfPresent(String column, Object val) { + if (val != null) { + return (QueryWrapperX) super.le(column, val); + } + return this; + } + + public QueryWrapperX betweenIfPresent(String column, Object val1, Object val2) { + if (val1 != null && val2 != null) { + return (QueryWrapperX) super.between(column, val1, val2); + } + if (val1 != null) { + return (QueryWrapperX) ge(column, val1); + } + if (val2 != null) { + return (QueryWrapperX) le(column, val2); + } + return this; + } + + public QueryWrapperX betweenIfPresent(String column, Object[] values) { + if (values!= null && values.length != 0 && values[0] != null && values[1] != null) { + return (QueryWrapperX) super.between(column, values[0], values[1]); + } + if (values!= null && values.length != 0 && values[0] != null) { + return (QueryWrapperX) ge(column, values[0]); + } + if (values!= null && values.length != 0 && values[1] != null) { + return (QueryWrapperX) le(column, values[1]); + } + return this; + } + + // ========== 重写父类方法,方便链式调用 ========== + + @Override + public QueryWrapperX eq(boolean condition, String column, Object val) { + super.eq(condition, column, val); + return this; + } + + @Override + public QueryWrapperX eq(String column, Object val) { + super.eq(column, val); + return this; + } + + @Override + public QueryWrapperX orderByDesc(String column) { + super.orderByDesc(true, column); + return this; + } + + @Override + public QueryWrapperX last(String lastSql) { + super.last(lastSql); + return this; + } + + @Override + public QueryWrapperX in(String column, Collection coll) { + super.in(column, coll); + return this; + } + + /** + * 设置只返回最后一条 + * + * TODO 芋艿:不是完美解,需要在思考下。如果使用多数据源,并且数据源是多种类型时,可能会存在问题:实现之返回一条的语法不同 + * + * @return this + */ + public QueryWrapperX limitN(int n) { + Assert.notNull(SqlConstants.DB_TYPE, "获取不到数据库的类型"); + switch (SqlConstants.DB_TYPE) { + case ORACLE: + case ORACLE_12C: + super.le("ROWNUM", n); + break; + case SQL_SERVER: + case SQL_SERVER2005: + super.select("TOP " + n + " *"); // 由于 SQL Server 是通过 SELECT TOP 1 实现限制一条,所以只好使用 * 查询剩余字段 + break; + default: + super.last("LIMIT " + n); + } + return this; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java new file mode 100644 index 0000000..7ef0f4e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.lang.Assert; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.extra.spring.SpringUtil; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * 字段字段的 TypeHandler 实现类,基于 {@link cn.hutool.crypto.symmetric.AES} 实现 + * 可通过 jasypt.encryptor.password 配置项,设置密钥 + * + * @author 芋道源码 + */ +public class EncryptTypeHandler extends BaseTypeHandler { + + private static final String ENCRYPTOR_PROPERTY_NAME = "mybatis-plus.encryptor.password"; + + private static AES aes; + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { + ps.setString(i, encrypt(parameter)); + } + + @Override + public String getNullableResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return decrypt(value); + } + + @Override + public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return decrypt(value); + } + + @Override + public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return decrypt(value); + } + + private static String decrypt(String value) { + if (value == null) { + return null; + } + return getEncryptor().decryptStr(value); + } + + public static String encrypt(String rawValue) { + if (rawValue == null) { + return null; + } + return getEncryptor().encryptBase64(rawValue); + } + + private static AES getEncryptor() { + if (aes != null) { + return aes; + } + // 构建 AES + String password = SpringUtil.getProperty(ENCRYPTOR_PROPERTY_NAME); + Assert.notEmpty(password, "配置项({}) 不能为空", ENCRYPTOR_PROPERTY_NAME); + aes = SecureUtil.aes(password.getBytes()); + return aes; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java new file mode 100644 index 0000000..18455ba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/IntegerListTypeHandler.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * List 的类型转换器实现类,对应数据库的 varchar 类型 + * + * @author jason + */ +@MappedJdbcTypes(JdbcType.VARCHAR) +@MappedTypes(List.class) +public class IntegerListTypeHandler implements TypeHandler> { + + private static final String COMMA = ","; + + @Override + public void setParameter(PreparedStatement ps, int i, List strings, JdbcType jdbcType) throws SQLException { + ps.setString(i, CollUtil.join(strings, COMMA)); + } + + @Override + public List getResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return getResult(value); + } + + @Override + public List getResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return getResult(value); + } + + @Override + public List getResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return getResult(value); + } + + private List getResult(String value) { + if (value == null) { + return null; + } + return StrUtils.splitToInteger(value, COMMA); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/JsonLongSetTypeHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/JsonLongSetTypeHandler.java new file mode 100644 index 0000000..052c723 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/JsonLongSetTypeHandler.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.Set; + +/** + * 参考 {@link com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler} 实现 + * 在我们将字符串反序列化为 Set 并且泛型为 Long 时,如果每个元素的数值太小,会被处理成 Integer 类型,导致可能存在隐性的 BUG。 + * + * 例如说哦,SysUserDO 的 postIds 属性 + * + * @author 芋道源码 + */ +public class JsonLongSetTypeHandler extends AbstractJsonTypeHandler { + + private static final TypeReference> TYPE_REFERENCE = new TypeReference>(){}; + + @Override + protected Object parse(String json) { + return JsonUtils.parseObject(json, TYPE_REFERENCE); + } + + @Override + protected String toJson(Object obj) { + return JsonUtils.toJsonString(obj); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java new file mode 100644 index 0000000..8c30f3d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongListTypeHandler.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * List 的类型转换器实现类,对应数据库的 varchar 类型 + * + * @author 芋道源码 + */ +@MappedJdbcTypes(JdbcType.VARCHAR) +@MappedTypes(List.class) +public class LongListTypeHandler implements TypeHandler> { + + private static final String COMMA = ","; + + @Override + public void setParameter(PreparedStatement ps, int i, List strings, JdbcType jdbcType) throws SQLException { + // 设置占位符 + ps.setString(i, CollUtil.join(strings, COMMA)); + } + + @Override + public List getResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return getResult(value); + } + + @Override + public List getResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return getResult(value); + } + + @Override + public List getResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return getResult(value); + } + + private List getResult(String value) { + if (value == null) { + return null; + } + return StrUtils.splitToLong(value, COMMA); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java new file mode 100644 index 0000000..598a15e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * List 的类型转换器实现类,对应数据库的 varchar 类型 + * + * @author 永不言败 + * @since 2022 3/23 12:50:15 + */ +@MappedJdbcTypes(JdbcType.VARCHAR) +@MappedTypes(List.class) +public class StringListTypeHandler implements TypeHandler> { + + private static final String COMMA = ","; + + @Override + public void setParameter(PreparedStatement ps, int i, List strings, JdbcType jdbcType) throws SQLException { + // 设置占位符 + ps.setString(i, CollUtil.join(strings, COMMA)); + } + + @Override + public List getResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return getResult(value); + } + + @Override + public List getResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return getResult(value); + } + + @Override + public List getResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return getResult(value); + } + + private List getResult(String value) { + if (value == null) { + return null; + } + return StrUtil.splitTrim(value, COMMA); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java new file mode 100644 index 0000000..c4894ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.framework.mybatis.core.util; + +import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; +import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.mybatisplus.annotation.DbType; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * JDBC 工具类 + * + * @author 芋道源码 + */ +public class JdbcUtils { + + /** + * 判断连接是否正确 + * + * @param url 数据源连接 + * @param username 账号 + * @param password 密码 + * @return 是否正确 + */ + public static boolean isConnectionOK(String url, String username, String password) { + try (Connection ignored = DriverManager.getConnection(url, username, password)) { + return true; + } catch (Exception ex) { + return false; + } + } + + /** + * 获得 URL 对应的 DB 类型 + * + * @param url URL + * @return DB 类型 + */ + public static DbType getDbType(String url) { + return com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url); + } + + /** + * 通过当前数据库连接获得对应的 DB 类型 + * + * @return DB 类型 + */ + public static DbType getDbType() { + DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class); + DataSource dataSource = dynamicRoutingDataSource.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + return DbTypeEnum.find(conn.getMetaData().getDatabaseProductName()); + } catch (SQLException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java new file mode 100644 index 0000000..611b715 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.framework.mybatis.core.util; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.SortingField; +import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +/** + * MyBatis 工具类 + */ +public class MyBatisUtils { + + private static final String MYSQL_ESCAPE_CHARACTER = "`"; + + public static Page buildPage(PageParam pageParam) { + return buildPage(pageParam, null); + } + + public static Page buildPage(PageParam pageParam, Collection sortingFields) { + // 页码 + 数量 + Page page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize()); + // 排序字段 + if (!CollectionUtil.isEmpty(sortingFields)) { + page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? + OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField())) + .collect(Collectors.toList())); + } + return page; + } + + /** + * 将拦截器添加到链中 + * 由于 MybatisPlusInterceptor 不支持添加拦截器,所以只能全量设置 + * + * @param interceptor 链 + * @param inner 拦截器 + * @param index 位置 + */ + public static void addInterceptor(MybatisPlusInterceptor interceptor, InnerInterceptor inner, int index) { + List inners = new ArrayList<>(interceptor.getInterceptors()); + inners.add(index, inner); + interceptor.setInterceptors(inners); + } + + /** + * 获得 Table 对应的表名 + *

+ * 兼容 MySQL 转义表名 `t_xxx` + * + * @param table 表 + * @return 去除转移字符后的表名 + */ + public static String getTableName(Table table) { + String tableName = table.getName(); + if (tableName.startsWith(MYSQL_ESCAPE_CHARACTER) && tableName.endsWith(MYSQL_ESCAPE_CHARACTER)) { + tableName = tableName.substring(1, tableName.length() - 1); + } + return tableName; + } + + /** + * 构建 Column 对象 + * + * @param tableName 表名 + * @param tableAlias 别名 + * @param column 字段名 + * @return Column 对象 + */ + public static Column buildColumn(String tableName, Alias tableAlias, String column) { + if (tableAlias != null) { + tableName = tableAlias.getName(); + } + return new Column(tableName + StringPool.DOT + column); + } + + /** + * 跨数据库的 find_in_set 实现 + * + * @param column 字段名称 + * @param value 查询值(不带单引号) + * @return sql + */ + public static String findInSet(String column, Object value) { + // 这里不用SqlConstants.DB_TYPE,因为它是使用 primary 数据源的 url 推断出来的类型 + DbType dbType = JdbcUtils.getDbType(); + return DbTypeEnum.getFindInSetTemplate(dbType) + .replace("#{column}", column) + .replace("#{value}", StrUtil.toString(value)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java new file mode 100644 index 0000000..50b1e85 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java @@ -0,0 +1,4 @@ +/** + * 使用 MyBatis Plus 提升使用 MyBatis 的开发效率 + */ +package cn.iocoder.yudao.framework.mybatis; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java new file mode 100644 index 0000000..bcc46b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.translate.config; + +import cn.iocoder.yudao.framework.translate.core.TranslateUtils; +import com.fhs.trans.service.impl.TransService; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +@AutoConfiguration +public class YudaoTranslateAutoConfiguration { + + @Bean + @SuppressWarnings({"InstantiationOfUtilityClass", "SpringJavaInjectionPointsAutowiringInspection"}) + public TranslateUtils translateUtils(TransService transService) { + TranslateUtils.init(transService); + return new TranslateUtils(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java new file mode 100644 index 0000000..2974b0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/core/TranslateUtils.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.translate.core; + +import cn.hutool.core.collection.CollUtil; +import com.fhs.core.trans.vo.VO; +import com.fhs.trans.service.impl.TransService; + +import java.util.List; + +/** + * VO 数据翻译 Utils + * + * @author 芋道源码 + */ +public class TranslateUtils { + + private static TransService transService; + + public static void init(TransService transService) { + TranslateUtils.transService = transService; + } + + /** + * 数据翻译 + * + * 使用场景:无法使用 @TransMethodResult 注解的场景,只能通过手动触发翻译 + * + * @param data 数据 + * @return 翻译结果 + */ + public static List translate(List data) { + if (CollUtil.isNotEmpty((data))) { + transService.transBatch(data); + } + return data; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java new file mode 100644 index 0000000..f14914a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/package-info.java @@ -0,0 +1,4 @@ +/** + * 使用 Easy-Trans 提升使用 VO 数据翻译的开发效率 + */ +package cn.iocoder.yudao.framework.translate; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..eb172e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + cn.iocoder.yudao.framework.mybatis.config.IdTypeEnvironmentPostProcessor diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..4a4eb95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration +cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration +cn.iocoder.yudao.framework.translate.config.YudaoTranslateAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot MyBatis 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot MyBatis 入门》.md new file mode 100644 index 0000000..d684e1d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot MyBatis 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md new file mode 100644 index 0000000..2113374 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 多数据源(读写分离)入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 数据库连接池入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 数据库连接池入门》.md new file mode 100644 index 0000000..21b5075 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-mybatis/《芋道 Spring Boot 数据库连接池入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/pom.xml new file mode 100644 index 0000000..7e7279e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/pom.xml @@ -0,0 +1,47 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-protection + jar + + ${project.artifactId} + 服务保证,提供分布式锁、幂等、限流、熔断、API 签名等等功能 + https://github.com/YunaiV/ruoyi-vue-pro + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + provided + + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + com.baomidou + lock4j-redisson-spring-boot-starter + true + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java new file mode 100644 index 0000000..de74963 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.framework.idempotent.config; + +import cn.iocoder.yudao.framework.idempotent.core.aop.IdempotentAspect; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.List; + +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoIdempotentConfiguration { + + @Bean + public IdempotentAspect idempotentAspect(List keyResolvers, IdempotentRedisDAO idempotentRedisDAO) { + return new IdempotentAspect(keyResolvers, idempotentRedisDAO); + } + + @Bean + public IdempotentRedisDAO idempotentRedisDAO(StringRedisTemplate stringRedisTemplate) { + return new IdempotentRedisDAO(stringRedisTemplate); + } + + // ========== 各种 IdempotentKeyResolver Bean ========== + + @Bean + public DefaultIdempotentKeyResolver defaultIdempotentKeyResolver() { + return new DefaultIdempotentKeyResolver(); + } + + @Bean + public UserIdempotentKeyResolver userIdempotentKeyResolver() { + return new UserIdempotentKeyResolver(); + } + + @Bean + public ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() { + return new ExpressionIdempotentKeyResolver(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java new file mode 100644 index 0000000..cd6add8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.idempotent.core.annotation; + +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * 幂等注解 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Idempotent { + + /** + * 幂等的超时时间,默认为 1 秒 + * + * 注意,如果执行时间超过它,请求还是会进来 + */ + int timeout() default 1; + /** + * 时间单位,默认为 SECONDS 秒 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 提示信息,正在执行中的提示 + */ + String message() default "重复请求,请稍后重试"; + + /** + * 使用的 Key 解析器 + * + * @see DefaultIdempotentKeyResolver 全局级别 + * @see UserIdempotentKeyResolver 用户级别 + * @see ExpressionIdempotentKeyResolver 自定义表达式,通过 {@link #keyArg()} 计算 + */ + Class keyResolver() default DefaultIdempotentKeyResolver.class; + /** + * 使用的 Key 参数 + */ + String keyArg() default ""; + + /** + * 删除 Key,当发生异常时候 + * + * 问题:为什么发生异常时,需要删除 Key 呢? + * 回答:发生异常时,说明业务发生错误,此时需要删除 Key,避免下次请求无法正常执行。 + * + * 问题:为什么不搞 deleteWhenSuccess 执行成功时,需要删除 Key 呢? + * 回答:这种情况下,本质上是分布式锁,推荐使用 @Lock4j 注解 + */ + boolean deleteKeyWhenException() default true; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java new file mode 100644 index 0000000..11ff765 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.idempotent.core.aop; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.util.Assert; + +import java.util.List; +import java.util.Map; + +/** + * 拦截声明了 {@link Idempotent} 注解的方法,实现幂等操作 + * + * @author 芋道源码 + */ +@Aspect +@Slf4j +public class IdempotentAspect { + + /** + * IdempotentKeyResolver 集合 + */ + private final Map, IdempotentKeyResolver> keyResolvers; + + private final IdempotentRedisDAO idempotentRedisDAO; + + public IdempotentAspect(List keyResolvers, IdempotentRedisDAO idempotentRedisDAO) { + this.keyResolvers = CollectionUtils.convertMap(keyResolvers, IdempotentKeyResolver::getClass); + this.idempotentRedisDAO = idempotentRedisDAO; + } + + @Around(value = "@annotation(idempotent)") + public Object aroundPointCut(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable { + // 获得 IdempotentKeyResolver + IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver()); + Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver"); + // 解析 Key + String key = keyResolver.resolver(joinPoint, idempotent); + + // 1. 锁定 Key + boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit()); + // 锁定失败,抛出异常 + if (!success) { + log.info("[aroundPointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs()); + throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), idempotent.message()); + } + + // 2. 执行逻辑 + try { + return joinPoint.proceed(); + } catch (Throwable throwable) { + // 3. 异常时,删除 Key + // 参考美团 GTIS 思路:https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html + if (idempotent.deleteKeyWhenException()) { + idempotentRedisDAO.delete(key); + } + throw throwable; + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java new file mode 100644 index 0000000..1617570 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/IdempotentKeyResolver.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.idempotent.core.keyresolver; + +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import org.aspectj.lang.JoinPoint; + +/** + * 幂等 Key 解析器接口 + * + * @author 芋道源码 + */ +public interface IdempotentKeyResolver { + + /** + * 解析一个 Key + * + * @param idempotent 幂等注解 + * @param joinPoint AOP 切面 + * @return Key + */ + String resolver(JoinPoint joinPoint, Idempotent idempotent); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java new file mode 100644 index 0000000..7b5e145 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * 默认(全局级别)幂等 Key 解析器,使用方法名 + 方法参数,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, Idempotent idempotent) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + return SecureUtil.md5(methodName + argsStr); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java new file mode 100644 index 0000000..50b4a2c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/ExpressionIdempotentKeyResolver.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; + +/** + * 基于 Spring EL 表达式, + * + * @author 芋道源码 + */ +public class ExpressionIdempotentKeyResolver implements IdempotentKeyResolver { + + private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); + private final ExpressionParser expressionParser = new SpelExpressionParser(); + + @Override + public String resolver(JoinPoint joinPoint, Idempotent idempotent) { + // 获得被拦截方法参数名列表 + Method method = getMethod(joinPoint); + Object[] args = joinPoint.getArgs(); + String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); + // 准备 Spring EL 表达式解析的上下文 + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + if (ArrayUtil.isNotEmpty(parameterNames)) { + for (int i = 0; i < parameterNames.length; i++) { + evaluationContext.setVariable(parameterNames[i], args[i]); + } + } + + // 解析参数 + Expression expression = expressionParser.parseExpression(idempotent.keyArg()); + return expression.getValue(evaluationContext, String.class); + } + + private static Method getMethod(JoinPoint point) { + // 处理,声明在类上的情况 + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + if (!method.getDeclaringClass().isInterface()) { + return method; + } + + // 处理,声明在接口上的情况 + try { + return point.getTarget().getClass().getDeclaredMethod( + point.getSignature().getName(), method.getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java new file mode 100644 index 0000000..2fa91ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.aspectj.lang.JoinPoint; + +/** + * 用户级别的幂等 Key 解析器,使用方法名 + 方法参数 + userId + userType,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class UserIdempotentKeyResolver implements IdempotentKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, Idempotent idempotent) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + Long userId = WebFrameworkUtils.getLoginUserId(); + Integer userType = WebFrameworkUtils.getLoginUserType(); + return SecureUtil.md5(methodName + argsStr + userId + userType); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java new file mode 100644 index 0000000..a8d981d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.framework.idempotent.core.redis; + +import lombok.AllArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * 幂等 Redis DAO + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class IdempotentRedisDAO { + + /** + * 幂等操作 + * + * KEY 格式:idempotent:%s // 参数为 uuid + * VALUE 格式:String + * 过期时间:不固定 + */ + private static final String IDEMPOTENT = "idempotent:%s"; + + private final StringRedisTemplate redisTemplate; + + public Boolean setIfAbsent(String key, long timeout, TimeUnit timeUnit) { + String redisKey = formatKey(key); + return redisTemplate.opsForValue().setIfAbsent(redisKey, "", timeout, timeUnit); + } + + public void delete(String key) { + String redisKey = formatKey(key); + redisTemplate.delete(redisKey); + } + + private static String formatKey(String key) { + return String.format(IDEMPOTENT, key); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java new file mode 100644 index 0000000..8cad5fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/package-info.java @@ -0,0 +1,12 @@ +/** + * 幂等组件,参考 https://github.com/it4alla/idempotent 项目实现 + * 实现原理是,相同参数的方法,一段时间内,有且仅能执行一次。通过这样的方式,保证幂等性。 + * + * 使用场景:例如说,用户快速的双击了某个按钮,前端没有禁用该按钮,导致发送了两次重复的请求。 + * + * 和 it4alla/idempotent 组件的差异点,主要体现在两点: + * 1. 我们去掉了 @Idempotent 注解的 delKey 属性。原因是,本质上 delKey 为 true 时,实现的是分布式锁的能力 + * 此时,我们偏向使用 Lock4j 组件。原则上,一个组件只提供一种单一的能力。 + * 2. 考虑到组件的通用性,我们并未像 it4alla/idempotent 组件一样使用 Redisson RMap 结构,而是直接使用 Redis 的 String 数据格式。 + */ +package cn.iocoder.yudao.framework.idempotent; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java new file mode 100644 index 0000000..f9b883c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.lock4j.config; + +import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; +import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; + +@AutoConfiguration(before = LockAutoConfiguration.class) +@ConditionalOnClass(name = "com.baomidou.lock.annotation.Lock4j") +public class YudaoLock4jConfiguration { + + @Bean + public DefaultLockFailureStrategy lockFailureStrategy() { + return new DefaultLockFailureStrategy(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java new file mode 100644 index 0000000..2cea08b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/DefaultLockFailureStrategy.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.lock4j.core; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import com.baomidou.lock.LockFailureStrategy; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Method; + +/** + * 自定义获取锁失败策略,抛出 {@link ServiceException} 异常 + */ +@Slf4j +public class DefaultLockFailureStrategy implements LockFailureStrategy { + + @Override + public void onLockFailure(String key, Method method, Object[] arguments) { + log.debug("[onLockFailure][线程:{} 获取锁失败,key:{} 获取失败:{} ]", Thread.currentThread().getName(), key, arguments); + throw new ServiceException(GlobalErrorCodeConstants.LOCKED); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java new file mode 100644 index 0000000..693d052 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.lock4j.core; + +/** + * Lock4j Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface Lock4jRedisKeyConstants { + + /** + * 分布式锁 + * + * KEY 格式:lock4j:%s // 参数来自 DefaultLockKeyBuilder 类 + * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构 + * 过期时间:不固定 + */ + String LOCK4J = "lock4j:%s"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java new file mode 100644 index 0000000..267b951 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java @@ -0,0 +1,4 @@ +/** + * 分布式锁组件,使用 https://gitee.com/baomidou/lock4j 开源项目 + */ +package cn.iocoder.yudao.framework.lock4j; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java new file mode 100644 index 0000000..68b910f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.framework.ratelimiter.config; + +import cn.iocoder.yudao.framework.ratelimiter.core.aop.RateLimiterAspect; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.*; +import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import org.redisson.api.RedissonClient; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoRateLimiterConfiguration { + + @Bean + public RateLimiterAspect rateLimiterAspect(List keyResolvers, RateLimiterRedisDAO rateLimiterRedisDAO) { + return new RateLimiterAspect(keyResolvers, rateLimiterRedisDAO); + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public RateLimiterRedisDAO rateLimiterRedisDAO(RedissonClient redissonClient) { + return new RateLimiterRedisDAO(redissonClient); + } + + // ========== 各种 RateLimiterRedisDAO Bean ========== + + @Bean + public DefaultRateLimiterKeyResolver defaultRateLimiterKeyResolver() { + return new DefaultRateLimiterKeyResolver(); + } + + @Bean + public UserRateLimiterKeyResolver userRateLimiterKeyResolver() { + return new UserRateLimiterKeyResolver(); + } + + @Bean + public ClientIpRateLimiterKeyResolver clientIpRateLimiterKeyResolver() { + return new ClientIpRateLimiterKeyResolver(); + } + + @Bean + public ServerNodeRateLimiterKeyResolver serverNodeRateLimiterKeyResolver() { + return new ServerNodeRateLimiterKeyResolver(); + } + + @Bean + public ExpressionRateLimiterKeyResolver expressionRateLimiterKeyResolver() { + return new ExpressionRateLimiterKeyResolver(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java new file mode 100644 index 0000000..417c4d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.annotation; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ClientIpRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.DefaultRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ServerNodeRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.UserRateLimiterKeyResolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * 限流注解 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RateLimiter { + + /** + * 限流的时间,默认为 1 秒 + */ + int time() default 1; + /** + * 时间单位,默认为 SECONDS 秒 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 限流次数 + */ + int count() default 100; + + /** + * 提示信息,请求过快的提示 + * + * @see GlobalErrorCodeConstants#TOO_MANY_REQUESTS + */ + String message() default ""; // 为空时,使用 TOO_MANY_REQUESTS 错误提示 + + /** + * 使用的 Key 解析器 + * + * @see DefaultRateLimiterKeyResolver 全局级别 + * @see UserRateLimiterKeyResolver 用户 ID 级别 + * @see ClientIpRateLimiterKeyResolver 用户 IP 级别 + * @see ServerNodeRateLimiterKeyResolver 服务器 Node 级别 + * @see ExpressionIdempotentKeyResolver 自定义表达式,通过 {@link #keyArg()} 计算 + */ + Class keyResolver() default DefaultRateLimiterKeyResolver.class; + /** + * 使用的 Key 参数 + */ + String keyArg() default ""; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java new file mode 100644 index 0000000..6ede62b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.aop; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.util.Assert; + +import java.util.List; +import java.util.Map; + +/** + * 拦截声明了 {@link RateLimiter} 注解的方法,实现限流操作 + * + * @author 芋道源码 + */ +@Aspect +@Slf4j +public class RateLimiterAspect { + + /** + * RateLimiterKeyResolver 集合 + */ + private final Map, RateLimiterKeyResolver> keyResolvers; + + private final RateLimiterRedisDAO rateLimiterRedisDAO; + + public RateLimiterAspect(List keyResolvers, RateLimiterRedisDAO rateLimiterRedisDAO) { + this.keyResolvers = CollectionUtils.convertMap(keyResolvers, RateLimiterKeyResolver::getClass); + this.rateLimiterRedisDAO = rateLimiterRedisDAO; + } + + @Before("@annotation(rateLimiter)") + public void beforePointCut(JoinPoint joinPoint, RateLimiter rateLimiter) { + // 获得 IdempotentKeyResolver 对象 + RateLimiterKeyResolver keyResolver = keyResolvers.get(rateLimiter.keyResolver()); + Assert.notNull(keyResolver, "找不到对应的 RateLimiterKeyResolver"); + // 解析 Key + String key = keyResolver.resolver(joinPoint, rateLimiter); + + // 获取 1 次限流 + boolean success = rateLimiterRedisDAO.tryAcquire(key, + rateLimiter.count(), rateLimiter.time(), rateLimiter.timeUnit()); + if (!success) { + log.info("[beforePointCut][方法({}) 参数({}) 请求过于频繁]", joinPoint.getSignature().toString(), joinPoint.getArgs()); + String message = StrUtil.blankToDefault(rateLimiter.message(), + GlobalErrorCodeConstants.TOO_MANY_REQUESTS.getMsg()); + throw new ServiceException(GlobalErrorCodeConstants.TOO_MANY_REQUESTS.getCode(), message); + } + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java new file mode 100644 index 0000000..44d7bdf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver; + +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import org.aspectj.lang.JoinPoint; + +/** + * 限流 Key 解析器接口 + * + * @author 芋道源码 + */ +public interface RateLimiterKeyResolver { + + /** + * 解析一个 Key + * + * @param rateLimiter 限流注解 + * @param joinPoint AOP 切面 + * @return Key + */ + String resolver(JoinPoint joinPoint, RateLimiter rateLimiter); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java new file mode 100644 index 0000000..8d6253c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * IP 级别的限流 Key 解析器,使用方法名 + 方法参数 + IP,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class ClientIpRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + String clientIp = ServletUtils.getClientIP(); + return SecureUtil.md5(methodName + argsStr + clientIp); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java new file mode 100644 index 0000000..236ea45 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * 默认(全局级别)限流 Key 解析器,使用方法名 + 方法参数,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class DefaultRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + return SecureUtil.md5(methodName + argsStr); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java new file mode 100644 index 0000000..118581e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; + +/** + * 基于 Spring EL 表达式的 {@link RateLimiterKeyResolver} 实现类 + * + * @author 芋道源码 + */ +public class ExpressionRateLimiterKeyResolver implements RateLimiterKeyResolver { + + private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); + + private final ExpressionParser expressionParser = new SpelExpressionParser(); + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + // 获得被拦截方法参数名列表 + Method method = getMethod(joinPoint); + Object[] args = joinPoint.getArgs(); + String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); + // 准备 Spring EL 表达式解析的上下文 + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + if (ArrayUtil.isNotEmpty(parameterNames)) { + for (int i = 0; i < parameterNames.length; i++) { + evaluationContext.setVariable(parameterNames[i], args[i]); + } + } + + // 解析参数 + Expression expression = expressionParser.parseExpression(rateLimiter.keyArg()); + return expression.getValue(evaluationContext, String.class); + } + + private static Method getMethod(JoinPoint point) { + // 处理,声明在类上的情况 + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + if (!method.getDeclaringClass().isInterface()) { + return method; + } + + // 处理,声明在接口上的情况 + try { + return point.getTarget().getClass().getDeclaredMethod( + point.getSignature().getName(), method.getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java new file mode 100644 index 0000000..300a4d2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * Server 节点级别的限流 Key 解析器,使用方法名 + 方法参数 + IP,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class ServerNodeRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + String serverNode = String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); + return SecureUtil.md5(methodName + argsStr + serverNode); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java new file mode 100644 index 0000000..a8d1c3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.aspectj.lang.JoinPoint; + +/** + * 用户级别的限流 Key 解析器,使用方法名 + 方法参数 + userId + userType,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class UserRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + Long userId = WebFrameworkUtils.getLoginUserId(); + Integer userType = WebFrameworkUtils.getLoginUserType(); + return SecureUtil.md5(methodName + argsStr + userId + userType); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java new file mode 100644 index 0000000..fc1378f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.redis; + +import lombok.AllArgsConstructor; +import org.redisson.api.*; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * 限流 Redis DAO + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class RateLimiterRedisDAO { + + /** + * 限流操作 + * + * KEY 格式:rate_limiter:%s // 参数为 uuid + * VALUE 格式:String + * 过期时间:不固定 + */ + private static final String RATE_LIMITER = "rate_limiter:%s"; + + private final RedissonClient redissonClient; + + public Boolean tryAcquire(String key, int count, int time, TimeUnit timeUnit) { + // 1. 获得 RRateLimiter,并设置 rate 速率 + RRateLimiter rateLimiter = getRRateLimiter(key, count, time, timeUnit); + // 2. 尝试获取 1 个 + return rateLimiter.tryAcquire(); + } + + private static String formatKey(String key) { + return String.format(RATE_LIMITER, key); + } + + private RRateLimiter getRRateLimiter(String key, long count, int time, TimeUnit timeUnit) { + String redisKey = formatKey(key); + RRateLimiter rateLimiter = redissonClient.getRateLimiter(redisKey); + long rateInterval = timeUnit.toSeconds(time); + // 1. 如果不存在,设置 rate 速率 + RateLimiterConfig config = rateLimiter.getConfig(); + if (config == null) { + rateLimiter.trySetRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS); + return rateLimiter; + } + // 2. 如果存在,并且配置相同,则直接返回 + if (config.getRateType() == RateType.OVERALL + && Objects.equals(config.getRate(), count) + && Objects.equals(config.getRateInterval(), TimeUnit.SECONDS.toMillis(rateInterval))) { + return rateLimiter; + } + // 3. 如果存在,并且配置不同,则进行新建 + rateLimiter.setRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS); + return rateLimiter; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java new file mode 100644 index 0000000..36a408c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java @@ -0,0 +1,4 @@ +/** + * 限流组件,基于 Redisson {@link org.redisson.api.RRateLimiter} 限流实现 + */ +package cn.iocoder.yudao.framework.ratelimiter; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java new file mode 100644 index 0000000..7c68424 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/config/YudaoApiSignatureAutoConfiguration.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.signature.config; + +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect; +import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * HTTP API 签名的自动配置类 + * + * @author Zhougang + */ +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoApiSignatureAutoConfiguration { + + @Bean + public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) { + return new ApiSignatureAspect(signatureRedisDAO); + } + + @Bean + public ApiSignatureRedisDAO signatureRedisDAO(StringRedisTemplate stringRedisTemplate) { + return new ApiSignatureRedisDAO(stringRedisTemplate); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java new file mode 100644 index 0000000..281bcec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/annotation/ApiSignature.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.framework.signature.core.annotation; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + + +/** + * HTTP API 签名注解 + * + * @author Zhougang + */ +@Inherited +@Documented +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiSignature { + + /** + * 同一个请求多长时间内有效 默认 60 秒 + */ + int timeout() default 60; + + /** + * 时间单位,默认为 SECONDS 秒 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + // ========================== 签名参数 ========================== + + /** + * 提示信息,签名失败的提示 + * + * @see GlobalErrorCodeConstants#BAD_REQUEST + */ + String message() default "签名不正确"; // 为空时,使用 BAD_REQUEST 错误提示 + + /** + * 签名字段:appId 应用ID + */ + String appId() default "appId"; + + /** + * 签名字段:timestamp 时间戳 + */ + String timestamp() default "timestamp"; + + /** + * 签名字段:nonce 随机数,10 位以上 + */ + String nonce() default "nonce"; + + /** + * sign 客户端签名 + */ + String sign() default "sign"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java new file mode 100644 index 0000000..fec3c74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java @@ -0,0 +1,169 @@ +package cn.iocoder.yudao.framework.signature.core.aop; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature; +import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; +import java.util.Objects; +import java.util.SortedMap; +import java.util.TreeMap; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; + +/** + * 拦截声明了 {@link ApiSignature} 注解的方法,实现签名 + * + * @author Zhougang + */ +@Aspect +@Slf4j +@AllArgsConstructor +public class ApiSignatureAspect { + + private final ApiSignatureRedisDAO signatureRedisDAO; + + @Before("@annotation(signature)") + public void beforePointCut(JoinPoint joinPoint, ApiSignature signature) { + // 1. 验证通过,直接结束 + if (verifySignature(signature, Objects.requireNonNull(ServletUtils.getRequest()))) { + return; + } + + // 2. 验证不通过,抛出异常 + log.error("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(), + joinPoint.getArgs()); + throw new ServiceException(BAD_REQUEST.getCode(), + StrUtil.blankToDefault(signature.message(), BAD_REQUEST.getMsg())); + } + + public boolean verifySignature(ApiSignature signature, HttpServletRequest request) { + // 1.1 校验 Header + if (!verifyHeaders(signature, request)) { + return false; + } + // 1.2 校验 appId 是否能获取到对应的 appSecret + String appId = request.getHeader(signature.appId()); + String appSecret = signatureRedisDAO.getAppSecret(appId); + Assert.notNull(appSecret, "[appId({})] 找不到对应的 appSecret", appId); + + // 2. 校验签名【重要!】 + String clientSignature = request.getHeader(signature.sign()); // 客户端签名 + String serverSignatureString = buildSignatureString(signature, request, appSecret); // 服务端签名字符串 + String serverSignature = DigestUtil.sha256Hex(serverSignatureString); // 服务端签名 + if (ObjUtil.notEqual(clientSignature, serverSignature)) { + return false; + } + + // 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 ) + String nonce = request.getHeader(signature.nonce()); + signatureRedisDAO.setNonce(nonce, signature.timeout() * 2, signature.timeUnit()); + return true; + } + + /** + * 校验请求头加签参数 + * + * 1. appId 是否为空 + * 2. timestamp 是否为空,请求是否已经超时,默认 10 分钟 + * 3. nonce 是否为空,随机数是否 10 位以上,是否在规定时间内已经访问过了 + * 4. sign 是否为空 + * + * @param signature signature + * @param request request + * @return 是否校验 Header 通过 + */ + private boolean verifyHeaders(ApiSignature signature, HttpServletRequest request) { + // 1. 非空校验 + String appId = request.getHeader(signature.appId()); + if (StrUtil.isBlank(appId)) { + return false; + } + String timestamp = request.getHeader(signature.timestamp()); + if (StrUtil.isBlank(timestamp)) { + return false; + } + String nonce = request.getHeader(signature.nonce()); + if (StrUtil.length(nonce) < 10) { + return false; + } + String sign = request.getHeader(signature.sign()); + if (StrUtil.isBlank(sign)) { + return false; + } + + // 2. 检查 timestamp 是否超出允许的范围 (重点一:此处需要取绝对值) + long expireTime = signature.timeUnit().toMillis(signature.timeout()); + long requestTimestamp = Long.parseLong(timestamp); + long timestampDisparity = Math.abs(System.currentTimeMillis() - requestTimestamp); + if (timestampDisparity > expireTime) { + return false; + } + + // 3. 检查 nonce 是否存在,有且仅能使用一次 + return signatureRedisDAO.getNonce(nonce) == null; + } + + /** + * 构建签名字符串 + * + * 格式为 = 请求参数 + 请求体 + 请求头 + 密钥 + * + * @param signature signature + * @param request request + * @param appSecret appSecret + * @return 签名字符串 + */ + private String buildSignatureString(ApiSignature signature, HttpServletRequest request, String appSecret) { + SortedMap parameterMap = getRequestParameterMap(request); // 请求头 + SortedMap headerMap = getRequestHeaderMap(signature, request); // 请求参数 + String requestBody = StrUtil.nullToDefault(ServletUtils.getBody(request), ""); // 请求体 + return MapUtil.join(parameterMap, "&", "=") + + requestBody + + MapUtil.join(headerMap, "&", "=") + + appSecret; + } + + /** + * 获取请求头加签参数 Map + * + * @param request 请求 + * @param signature 签名注解 + * @return signature params + */ + private static SortedMap getRequestHeaderMap(ApiSignature signature, HttpServletRequest request) { + SortedMap sortedMap = new TreeMap<>(); + sortedMap.put(signature.appId(), request.getHeader(signature.appId())); + sortedMap.put(signature.timestamp(), request.getHeader(signature.timestamp())); + sortedMap.put(signature.nonce(), request.getHeader(signature.nonce())); + return sortedMap; + } + + /** + * 获取请求参数 Map + * + * @param request 请求 + * @return queryParams + */ + private static SortedMap getRequestParameterMap(HttpServletRequest request) { + SortedMap sortedMap = new TreeMap<>(); + for (Map.Entry entry : request.getParameterMap().entrySet()) { + sortedMap.put(entry.getKey(), entry.getValue()[0]); + } + return sortedMap; + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java new file mode 100644 index 0000000..f4aa849 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.framework.signature.core.redis; + +import lombok.AllArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * HTTP API 签名 Redis DAO + * + * @author Zhougang + */ +@AllArgsConstructor +public class ApiSignatureRedisDAO { + + private final StringRedisTemplate stringRedisTemplate; + + /** + * 验签随机数 + * + * KEY 格式:signature_nonce:%s // 参数为 随机数 + * VALUE 格式:String + * 过期时间:不固定 + */ + private static final String SIGNATURE_NONCE = "api_signature_nonce:%s"; + + /** + * 签名密钥 + * + * HASH 结构 + * KEY 格式:%s // 参数为 appid + * VALUE 格式:String + * 过期时间:永不过期(预加载到 Redis) + */ + private static final String SIGNATURE_APPID = "api_signature_app"; + + // ========== 验签随机数 ========== + + public String getNonce(String nonce) { + return stringRedisTemplate.opsForValue().get(formatNonceKey(nonce)); + } + + public void setNonce(String nonce, int time, TimeUnit timeUnit) { + stringRedisTemplate.opsForValue().set(formatNonceKey(nonce), "", time, timeUnit); + } + + private static String formatNonceKey(String key) { + return String.format(SIGNATURE_NONCE, key); + } + + // ========== 签名密钥 ========== + + public String getAppSecret(String appId) { + return (String) stringRedisTemplate.opsForHash().get(SIGNATURE_APPID, appId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java new file mode 100644 index 0000000..4ebd87a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/package-info.java @@ -0,0 +1,6 @@ +/** + * HTTP API 签名,校验安全性 + * + * @see builder() + .put("v1", new String[]{"k1"}).put("k1", new String[]{"v1"}).build()); + when(request.getContentType()).thenReturn("application/json"); + when(request.getReader()).thenReturn(new BufferedReader(new StringReader("test"))); + // mock 方法 + when(signatureRedisDAO.getAppSecret(eq(appId))).thenReturn(appSecret); + + // 调用 + boolean result = apiSignatureAspect.verifySignature(apiSignature, request); + // 断言结果 + assertTrue(result); + // 断言调用 + verify(signatureRedisDAO).setNonce(eq(nonce), eq(120), eq(TimeUnit.SECONDS)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/pom.xml new file mode 100644 index 0000000..8f4e580 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/pom.xml @@ -0,0 +1,41 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-redis + jar + + ${project.artifactId} + Redis 封装拓展 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.redisson + redisson-spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-cache + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java new file mode 100644 index 0000000..9e84c4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.framework.redis.config; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.cache.CacheProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.BatchStrategies; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.util.StringUtils; + +import java.util.Objects; + +import static cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration.buildRedisSerializer; + +/** + * Cache 配置类,基于 Redis 实现 + */ +@AutoConfiguration +@EnableConfigurationProperties({CacheProperties.class, YudaoCacheProperties.class}) +@EnableCaching +public class YudaoCacheAutoConfiguration { + + /** + * RedisCacheConfiguration Bean + *

+ * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法 + */ + @Bean + @Primary + public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) { + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); + // 设置使用 : 单冒号,而不是双 :: 冒号,避免 Redis Desktop Manager 多余空格 + // 详细可见 https://blog.csdn.net/chuixue24/article/details/103928965 博客 + // 再次修复单冒号,而不是双 :: 冒号问题,Issues 详情:https://gitee.com/zhijiantianya/yudao-cloud/issues/I86VY2 + config = config.computePrefixWith(cacheName -> { + String keyPrefix = cacheProperties.getRedis().getKeyPrefix(); + if (StringUtils.hasText(keyPrefix)) { + keyPrefix = keyPrefix.lastIndexOf(StrUtil.COLON) == -1 ? keyPrefix + StrUtil.COLON : keyPrefix; + return keyPrefix + cacheName + StrUtil.COLON; + } + return cacheName + StrUtil.COLON; + }); + // 设置使用 JSON 序列化方式 + config = config.serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer(buildRedisSerializer())); + + // 设置 CacheProperties.Redis 的属性 + CacheProperties.Redis redisProperties = cacheProperties.getRedis(); + if (redisProperties.getTimeToLive() != null) { + config = config.entryTtl(redisProperties.getTimeToLive()); + } + if (!redisProperties.isCacheNullValues()) { + config = config.disableCachingNullValues(); + } + if (!redisProperties.isUseKeyPrefix()) { + config = config.disableKeyPrefix(); + } + return config; + } + + @Bean + public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate, + RedisCacheConfiguration redisCacheConfiguration, + YudaoCacheProperties yudaoCacheProperties) { + // 创建 RedisCacheWriter 对象 + RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); + RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, + BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize())); + // 创建 TenantRedisCacheManager 对象 + return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java new file mode 100644 index 0000000..c51219d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheProperties.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.redis.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +/** + * Cache 配置项 + * + * @author Wanwan + */ +@ConfigurationProperties("yudao.cache") +@Data +@Validated +public class YudaoCacheProperties { + + /** + * {@link #redisScanBatchSize} 默认值 + */ + private static final Integer REDIS_SCAN_BATCH_SIZE_DEFAULT = 30; + + /** + * redis scan 一次返回数量 + */ + private Integer redisScanBatchSize = REDIS_SCAN_BATCH_SIZE_DEFAULT; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java new file mode 100644 index 0000000..ff02c93 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.framework.redis.config; + +import cn.hutool.core.util.ReflectUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +/** + * Redis 配置类 + */ +@AutoConfiguration(before = RedissonAutoConfiguration.class) // 目的:使用自己定义的 RedisTemplate Bean +public class YudaoRedisAutoConfiguration { + + /** + * 创建 RedisTemplate Bean,使用 JSON 序列化方式 + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + // 创建 RedisTemplate 对象 + RedisTemplate template = new RedisTemplate<>(); + // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。 + template.setConnectionFactory(factory); + // 使用 String 序列化方式,序列化 KEY 。 + template.setKeySerializer(RedisSerializer.string()); + template.setHashKeySerializer(RedisSerializer.string()); + // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 + template.setValueSerializer(buildRedisSerializer()); + template.setHashValueSerializer(buildRedisSerializer()); + return template; + } + + public static RedisSerializer buildRedisSerializer() { + RedisSerializer json = RedisSerializer.json(); + // 解决 LocalDateTime 的序列化 + ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper"); + objectMapper.registerModules(new JavaTimeModule()); + return json; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java new file mode 100644 index 0000000..a835835 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.framework.redis.core; + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.redis.cache.RedisCache; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; + +import java.time.Duration; + +/** + * 支持自定义过期时间的 {@link RedisCacheManager} 实现类 + * + * 在 {@link Cacheable#cacheNames()} 格式为 "key#ttl" 时,# 后面的 ttl 为过期时间。 + * 单位为最后一个字母(支持的单位有:d 天,h 小时,m 分钟,s 秒),默认单位为 s 秒 + * + * @author 芋道源码 + */ +public class TimeoutRedisCacheManager extends RedisCacheManager { + + private static final String SPLIT = "#"; + + public TimeoutRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { + super(cacheWriter, defaultCacheConfiguration); + } + + @Override + protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { + if (StrUtil.isEmpty(name)) { + return super.createRedisCache(name, cacheConfig); + } + // 如果使用 # 分隔,大小不为 2,则说明不使用自定义过期时间 + String[] names = StrUtil.splitToArray(name, SPLIT); + if (names.length != 2) { + return super.createRedisCache(name, cacheConfig); + } + + // 核心:通过修改 cacheConfig 的过期时间,实现自定义过期时间 + if (cacheConfig != null) { + // 移除 # 后面的 : 以及后面的内容,避免影响解析 + String ttlStr = StrUtil.subBefore(names[1], StrUtil.COLON, false); // 获得 ttlStr 时间部分 + names[1] = StrUtil.subAfter(names[1], ttlStr, false); // 移除掉 ttlStr 时间部分 + // 解析时间 + Duration duration = parseDuration(ttlStr); + cacheConfig = cacheConfig.entryTtl(duration); + } + + // 创建 RedisCache 对象,需要忽略掉 ttlStr + return super.createRedisCache(names[0] + names[1], cacheConfig); + } + + /** + * 解析过期时间 Duration + * + * @param ttlStr 过期时间字符串 + * @return 过期时间 Duration + */ + private Duration parseDuration(String ttlStr) { + String timeUnit = StrUtil.subSuf(ttlStr, -1); + switch (timeUnit) { + case "d": + return Duration.ofDays(removeDurationSuffix(ttlStr)); + case "h": + return Duration.ofHours(removeDurationSuffix(ttlStr)); + case "m": + return Duration.ofMinutes(removeDurationSuffix(ttlStr)); + case "s": + return Duration.ofSeconds(removeDurationSuffix(ttlStr)); + default: + return Duration.ofSeconds(Long.parseLong(ttlStr)); + } + } + + /** + * 移除多余的后缀,返回具体的时间 + * + * @param ttlStr 过期时间字符串 + * @return 时间 + */ + private Long removeDurationSuffix(String ttlStr) { + return NumberUtil.parseLong(StrUtil.sub(ttlStr, 0, ttlStr.length() - 1)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java new file mode 100644 index 0000000..bd8a5d3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/package-info.java @@ -0,0 +1,4 @@ +/** + * 采用 Spring Data Redis 操作 Redis,底层使用 Redisson 作为客户端 + */ +package cn.iocoder.yudao.framework.redis; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..02d4a68 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration +cn.iocoder.yudao.framework.redis.config.YudaoCacheAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Cache 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Cache 入门》.md new file mode 100644 index 0000000..5c27083 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Cache 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Redis 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Redis 入门》.md new file mode 100644 index 0000000..80c5445 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-redis/《芋道 Spring Boot Redis 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/pom.xml new file mode 100644 index 0000000..e76e57e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/pom.xml @@ -0,0 +1,71 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-security + jar + + ${project.artifactId} + + 1. security:用户的认证、权限的校验,实现「谁」可以做「什么事」 + 2. operatelog:操作日志,实现「谁」在「什么时间」对「什么」做了「什么事」 + + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.boot + spring-boot-starter-security + + + + + com.google.guava + guava + + + + + + io.github.mouzt + bizlog-sdk + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java new file mode 100644 index 0000000..eda6a14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogConfiguration.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.operatelog.config; + +import cn.iocoder.yudao.framework.operatelog.core.service.LogRecordServiceImpl; +import com.mzt.logapi.service.ILogRecordService; +import com.mzt.logapi.starter.annotation.EnableLogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +/** + * 操作日志配置类 + * + * @author HUIHUI + */ +@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦 +@AutoConfiguration +@Slf4j +public class YudaoOperateLogConfiguration { + + @Bean + @Primary + public ILogRecordService iLogRecordServiceImpl() { + return new LogRecordServiceImpl(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java new file mode 100644 index 0000000..97ce4ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,无特殊作用 + */ +package cn.iocoder.yudao.framework.operatelog.core; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java new file mode 100644 index 0000000..765857e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.framework.operatelog.core.service; + +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import com.mzt.logapi.beans.LogRecord; +import com.mzt.logapi.service.ILogRecordService; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 操作日志 ILogRecordService 实现类 + * + * 基于 {@link OperateLogApi} 实现,记录操作日志 + * + * @author HUIHUI + */ +@Slf4j +public class LogRecordServiceImpl implements ILogRecordService { + + @Resource + private OperateLogApi operateLogApi; + + @Override + public void record(LogRecord logRecord) { + // 1. 补全通用字段 + OperateLogCreateReqDTO reqDTO = new OperateLogCreateReqDTO(); + reqDTO.setTraceId(TracerUtils.getTraceId()); + // 补充用户信息 + fillUserFields(reqDTO); + // 补全模块信息 + fillModuleFields(reqDTO, logRecord); + // 补全请求信息 + fillRequestFields(reqDTO); + + // 2. 异步记录日志 + operateLogApi.createOperateLog(reqDTO); + } + + private static void fillUserFields(OperateLogCreateReqDTO reqDTO) { + // 使用 SecurityFrameworkUtils。因为要考虑,rpc、mq、job,它其实不是 web; + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + return; + } + reqDTO.setUserId(loginUser.getId()); + reqDTO.setUserType(loginUser.getUserType()); + } + + public static void fillModuleFields(OperateLogCreateReqDTO reqDTO, LogRecord logRecord) { + reqDTO.setType(logRecord.getType()); // 大模块类型,例如:CRM 客户 + reqDTO.setSubType(logRecord.getSubType());// 操作名称,例如:转移客户 + reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 业务编号,例如:客户编号 + reqDTO.setAction(logRecord.getAction());// 操作内容,例如:修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + reqDTO.setExtra(logRecord.getExtra()); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"} + } + + private static void fillRequestFields(OperateLogCreateReqDTO reqDTO) { + // 获得 Request 对象 + HttpServletRequest request = ServletUtils.getRequest(); + if (request == null) { + return; + } + // 补全请求信息 + reqDTO.setRequestMethod(request.getMethod()); + reqDTO.setRequestUrl(request.getRequestURI()); + reqDTO.setUserIp(ServletUtils.getClientIP(request)); + reqDTO.setUserAgent(ServletUtils.getUserAgent(request)); + } + + @Override + public List queryLog(String bizNo, String type) { + throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询"); + } + + @Override + public List queryLogByBizNo(String bizNo, String type, String subType) { + throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询"); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java new file mode 100644 index 0000000..c90139b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java @@ -0,0 +1,7 @@ +/** + * 基于 mzt-log 框架 + * 实现操作日志功能 + * + * @author HUIHUI + */ +package cn.iocoder.yudao.framework.operatelog; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java new file mode 100644 index 0000000..5c86290 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/AuthorizeRequestsCustomizer.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.security.config; + +import cn.iocoder.yudao.framework.web.config.WebProperties; +import org.springframework.core.Ordered; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; + +import javax.annotation.Resource; + +/** + * 自定义的 URL 的安全配置 + * 目的:每个 Maven Module 可以自定义规则! + * + * @author 芋道源码 + */ +public abstract class AuthorizeRequestsCustomizer + implements Customizer.ExpressionInterceptUrlRegistry>, Ordered { + + @Resource + private WebProperties webProperties; + + protected String buildAdminApi(String url) { + return webProperties.getAdminApi().getPrefix() + url; + } + + protected String buildAppApi(String url) { + return webProperties.getAppApi().getPrefix() + url; + } + + @Override + public int getOrder() { + return 0; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java new file mode 100644 index 0000000..3d19f32 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.framework.security.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.List; + +@ConfigurationProperties(prefix = "yudao.security") +@Validated +@Data +public class SecurityProperties { + + /** + * HTTP 请求时,访问令牌的请求 Header + */ + @NotEmpty(message = "Token Header 不能为空") + private String tokenHeader = "Authorization"; + /** + * HTTP 请求时,访问令牌的请求参数 + * + * 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接 + */ + @NotEmpty(message = "Token Parameter 不能为空") + private String tokenParameter = "token"; + + /** + * mock 模式的开关 + */ + @NotNull(message = "mock 模式的开关不能为空") + private Boolean mockEnable = false; + /** + * mock 模式的密钥 + * 一定要配置密钥,保证安全性 + */ + @NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。 + private String mockSecret = "test"; + + /** + * 免登录的 URL 列表 + */ + private List permitAllUrls = Collections.emptyList(); + + /** + * PasswordEncoder 加密复杂度,越高开销越大 + */ + private Integer passwordEncoderLength = 4; +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java new file mode 100644 index 0000000..432b2ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.framework.security.config; + +import cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect; +import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy; +import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; +import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; +import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; +import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService; +import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkServiceImpl; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import org.springframework.beans.factory.config.MethodInvokingFactoryBean; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.AccessDeniedHandler; + +import javax.annotation.Resource; + +/** + * Spring Security 自动配置类,主要用于相关组件的配置 + * + * 注意,不能和 {@link YudaoWebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。 + * 参见 https://stackoverflow.com/questions/53847050/spring-boot-delegatebuilder-cannot-be-null-on-autowiring-authenticationmanager 文档。 + * + * @author 芋道源码 + */ +@AutoConfiguration +@AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 +@EnableConfigurationProperties(SecurityProperties.class) +public class YudaoSecurityAutoConfiguration { + + @Resource + private SecurityProperties securityProperties; + + /** + * 处理用户未登录拦截的切面的 Bean + */ + @Bean + public PreAuthenticatedAspect preAuthenticatedAspect() { + return new PreAuthenticatedAspect(); + } + + /** + * 认证失败处理类 Bean + */ + @Bean + public AuthenticationEntryPoint authenticationEntryPoint() { + return new AuthenticationEntryPointImpl(); + } + + /** + * 权限不够处理器 Bean + */ + @Bean + public AccessDeniedHandler accessDeniedHandler() { + return new AccessDeniedHandlerImpl(); + } + + /** + * Spring Security 加密器 + * 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器 + * + * @see Password Encoding with Spring Security + */ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(securityProperties.getPasswordEncoderLength()); + } + + /** + * Token 认证过滤器 Bean + */ + @Bean + public TokenAuthenticationFilter authenticationTokenFilter(GlobalExceptionHandler globalExceptionHandler, + OAuth2TokenApi oauth2TokenApi) { + return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi); + } + + @Bean("ss") // 使用 Spring Security 的缩写,方便使用 + public SecurityFrameworkService securityFrameworkService(PermissionApi permissionApi) { + return new SecurityFrameworkServiceImpl(permissionApi); + } + + /** + * 声明调用 {@link SecurityContextHolder#setStrategyName(String)} 方法, + * 设置使用 {@link TransmittableThreadLocalSecurityContextHolderStrategy} 作为 Security 的上下文策略 + */ + @Bean + public MethodInvokingFactoryBean securityContextHolderMethodInvokingFactoryBean() { + MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean(); + methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class); + methodInvokingFactoryBean.setTargetMethod("setStrategyName"); + methodInvokingFactoryBean.setArguments(TransmittableThreadLocalSecurityContextHolderStrategy.class.getName()); + return methodInvokingFactoryBean; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java new file mode 100644 index 0000000..90822de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -0,0 +1,220 @@ +package cn.iocoder.yudao.framework.security.config; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.pattern.PathPattern; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 自定义的 Spring Security 配置适配器实现 + * + * @author 芋道源码 + */ +@AutoConfiguration +@AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效 +@EnableMethodSecurity(securedEnabled = true) +public class YudaoWebSecurityConfigurerAdapter { + + @Resource + private WebProperties webProperties; + @Resource + private SecurityProperties securityProperties; + + /** + * 认证失败处理类 Bean + */ + @Resource + private AuthenticationEntryPoint authenticationEntryPoint; + /** + * 权限不够处理器 Bean + */ + @Resource + private AccessDeniedHandler accessDeniedHandler; + /** + * Token 认证过滤器 Bean + */ + @Resource + private TokenAuthenticationFilter authenticationTokenFilter; + + /** + * 自定义的权限映射 Bean 们 + * + * @see #filterChain(HttpSecurity) + */ + @Resource + private List authorizeRequestsCustomizers; + + @Resource + private ApplicationContext applicationContext; + + /** + * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 + * 通过覆写父类的该方法,添加 @Bean 注解,解决该问题 + */ + @Bean + public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + /** + * 配置 URL 的安全配置 + * + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 + */ + @Bean + protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + // 登出 + httpSecurity + // 开启跨域 + .cors(Customizer.withDefaults()) + // CSRF 禁用,因为不使用 Session + .csrf(AbstractHttpConfigurer::disable) + // 基于 token 机制,所以不需要 Session + .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .headers(c -> c.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + // 一堆自定义的 Spring Security 处理器 + .exceptionHandling(c -> c.authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler)); + // 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高 + + // 获得 @PermitAll 带来的 URL 列表,免登录 + Multimap permitAllUrls = getPermitAllUrlsFromAnnotations(); + // 设置每个请求的权限 + httpSecurity + // ①:全局共享规则 + .authorizeRequests() + // 1.1 静态资源,可匿名访问 + .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() + // 1.2 设置 @PermitAll 无需认证 + .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() + // 1.3 基于 yudao.security.permit-all-urls 无需认证 + .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll() + // 1.4 设置 App API 无需认证 + .antMatchers(buildAppApi("/**")).permitAll() + // 1.5 验证码captcha 允许匿名访问 + .antMatchers("/captcha/get", "/captcha/check").permitAll() + // ②:每个项目的自定义规则 + .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 + authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) + // ③:兜底规则,必须认证 + .authorizeRequests() + .anyRequest().authenticated(); + + // 添加 Token Filter + httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + return httpSecurity.build(); + } + + private String buildAppApi(String url) { + return webProperties.getAppApi().getPrefix() + url; + } + + private Multimap getPermitAllUrlsFromAnnotations() { + Multimap result = HashMultimap.create(); + // 获得接口对应的 HandlerMethod 集合 + RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) + applicationContext.getBean("requestMappingHandlerMapping"); + Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); + // 获得有 @PermitAll 注解的接口 + for (Map.Entry entry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = entry.getValue(); + if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) { + continue; + } + Set urls = new HashSet<>(); + if (entry.getKey().getPatternsCondition() != null) { + urls.addAll(entry.getKey().getPatternsCondition().getPatterns()); + } + if (entry.getKey().getPathPatternsCondition() != null) { + urls.addAll(convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString)); + } + if (urls.isEmpty()) { + continue; + } + + // 特殊:使用 @RequestMapping 注解,并且未写 method 属性,此时认为都需要免登录 + Set methods = entry.getKey().getMethodsCondition().getMethods(); + if (CollUtil.isEmpty(methods)) { + result.putAll(HttpMethod.GET, urls); + result.putAll(HttpMethod.POST, urls); + result.putAll(HttpMethod.PUT, urls); + result.putAll(HttpMethod.DELETE, urls); + result.putAll(HttpMethod.HEAD, urls); + result.putAll(HttpMethod.PATCH, urls); + continue; + } + // 根据请求方法,添加到 result 结果 + entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> { + switch (requestMethod) { + case GET: + result.putAll(HttpMethod.GET, urls); + break; + case POST: + result.putAll(HttpMethod.POST, urls); + break; + case PUT: + result.putAll(HttpMethod.PUT, urls); + break; + case DELETE: + result.putAll(HttpMethod.DELETE, urls); + break; + case HEAD: + result.putAll(HttpMethod.HEAD, urls); + break; + case PATCH: + result.putAll(HttpMethod.PATCH, urls); + break; + } + }); + } + return result; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java new file mode 100644 index 0000000..68d1c56 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.framework.security.core; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 登录用户信息 + * + * @author 芋道源码 + */ +@Data +public class LoginUser { + + public static final String INFO_KEY_NICKNAME = "nickname"; + public static final String INFO_KEY_DEPT_ID = "deptId"; + + /** + * 用户编号 + */ + private Long id; + /** + * 用户类型 + * + * 关联 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 额外的用户信息 + */ + private Map info; + /** + * 租户编号 + */ + private Long tenantId; + /** + * 授权范围 + */ + private List scopes; + + // ========== 上下文 ========== + /** + * 上下文字段,不进行持久化 + * + * 1. 用于基于 LoginUser 维度的临时缓存 + */ + @JsonIgnore + private Map context; + + public void setContext(String key, Object value) { + if (context == null) { + context = new HashMap<>(); + } + context.put(key, value); + } + + public T getContext(String key, Class type) { + return MapUtil.get(context, key, type); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java new file mode 100644 index 0000000..efc85c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/annotations/PreAuthenticated.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.framework.security.core.annotations; + +import java.lang.annotation.*; + +/** + * 声明用户需要登录 + * + * 为什么不使用 {@link org.springframework.security.access.prepost.PreAuthorize} 注解,原因是不通过时,抛出的是认证不通过,而不是未登录 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface PreAuthenticated { +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java new file mode 100644 index 0000000..808afc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.security.core.aop; + +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +@Aspect +@Slf4j +public class PreAuthenticatedAspect { + + @Around("@annotation(preAuthenticated)") + public Object around(ProceedingJoinPoint joinPoint, PreAuthenticated preAuthenticated) throws Throwable { + if (SecurityFrameworkUtils.getLoginUser() == null) { + throw exception(UNAUTHORIZED); + } + return joinPoint.proceed(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java new file mode 100644 index 0000000..1bdbe71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/context/TransmittableThreadLocalSecurityContextHolderStrategy.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.framework.security.core.context; + +import com.alibaba.ttl.TransmittableThreadLocal; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolderStrategy; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.util.Assert; + +/** + * 基于 TransmittableThreadLocal 实现的 Security Context 持有者策略 + * 目的是,避免 @Async 等异步执行时,原生 ThreadLocal 的丢失问题 + * + * @author 芋道源码 + */ +public class TransmittableThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy { + + /** + * 使用 TransmittableThreadLocal 作为上下文 + */ + private static final ThreadLocal CONTEXT_HOLDER = new TransmittableThreadLocal<>(); + + @Override + public void clearContext() { + CONTEXT_HOLDER.remove(); + } + + @Override + public SecurityContext getContext() { + SecurityContext ctx = CONTEXT_HOLDER.get(); + if (ctx == null) { + ctx = createEmptyContext(); + CONTEXT_HOLDER.set(ctx); + } + return ctx; + } + + @Override + public void setContext(SecurityContext context) { + Assert.notNull(context, "Only non-null SecurityContext instances are permitted"); + CONTEXT_HOLDER.set(context); + } + + @Override + public SecurityContext createEmptyContext() { + return new SecurityContextImpl(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java new file mode 100644 index 0000000..086ccd9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.framework.security.core.filter; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Token 过滤器,验证 token 的有效性 + * 验证通过后,获得 {@link LoginUser} 信息,并加入到 Spring Security 上下文 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class TokenAuthenticationFilter extends OncePerRequestFilter { + + private final SecurityProperties securityProperties; + + private final GlobalExceptionHandler globalExceptionHandler; + + private final OAuth2TokenApi oauth2TokenApi; + + @Override + @SuppressWarnings("NullableProblems") + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); + if (StrUtil.isNotEmpty(token)) { + Integer userType = WebFrameworkUtils.getLoginUserType(request); + try { + // 1.1 基于 token 构建登录用户 + LoginUser loginUser = buildLoginUserByToken(token, userType); + // 1.2 模拟 Login 功能,方便日常开发调试 + if (loginUser == null) { + loginUser = mockLoginUser(request, token, userType); + } + + // 2. 设置当前用户 + if (loginUser != null) { + SecurityFrameworkUtils.setLoginUser(loginUser, request); + } + } catch (Throwable ex) { + CommonResult result = globalExceptionHandler.allExceptionHandler(request, ex); + ServletUtils.writeJSON(response, result); + return; + } + } + + // 继续过滤链 + chain.doFilter(request, response); + } + + private LoginUser buildLoginUserByToken(String token, Integer userType) { + try { + OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token); + if (accessToken == null) { + return null; + } + // 用户类型不匹配,无权限 + // 注意:只有 /admin-api/* 和 /app-api/* 有 userType,才需要比对用户类型 + // 类似 WebSocket 的 /ws/* 连接地址,是不需要比对用户类型的 + if (userType != null + && ObjectUtil.notEqual(accessToken.getUserType(), userType)) { + throw new AccessDeniedException("错误的用户类型"); + } + // 构建登录用户 + return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) + .setInfo(accessToken.getUserInfo()) // 额外的用户信息 + .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()); + } catch (ServiceException serviceException) { + // 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可 + return null; + } + } + + /** + * 模拟登录用户,方便日常开发调试 + * + * 注意,在线上环境下,一定要关闭该功能!!! + * + * @param request 请求 + * @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号 + * @param userType 用户类型 + * @return 模拟的 LoginUser + */ + private LoginUser mockLoginUser(HttpServletRequest request, String token, Integer userType) { + if (!securityProperties.getMockEnable()) { + return null; + } + // 必须以 mockSecret 开头 + if (!token.startsWith(securityProperties.getMockSecret())) { + return null; + } + // 构建模拟用户 + Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length())); + return new LoginUser().setId(userId).setUserType(userType) + .setTenantId(WebFrameworkUtils.getTenantId(request)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java new file mode 100644 index 0000000..33f3f14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.security.core.handler; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; + +/** + * 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。 + * + * 补充:Spring Security 通过 {@link ExceptionTranslationFilter#handleAccessDeniedException(HttpServletRequest, HttpServletResponse, FilterChain, AccessDeniedException)} 方法,调用当前类 + * + * @author 芋道源码 + */ +@Slf4j +@SuppressWarnings("JavadocReference") +public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) + throws IOException, ServletException { + // 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏 + log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(), + SecurityFrameworkUtils.getLoginUserId(), e); + // 返回 403 + ServletUtils.writeJSON(response, CommonResult.error(FORBIDDEN)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java new file mode 100644 index 0000000..0a451e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.security.core.handler; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.ExceptionTranslationFilter; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED; + +/** + * 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页 + * + * 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类 + * + * @author ruoyi + */ +@Slf4j +@SuppressWarnings("JavadocReference") // 忽略文档引用报错 +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { + log.debug("[commence][访问 URL({}) 时,没有登录]", request.getRequestURI(), e); + // 返回 401 + ServletUtils.writeJSON(response, CommonResult.error(UNAUTHORIZED)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java new file mode 100644 index 0000000..bf2f7f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkService.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.framework.security.core.service; + +/** + * Security 框架 Service 接口,定义权限相关的校验操作 + * + * @author 芋道源码 + */ +public interface SecurityFrameworkService { + + /** + * 判断是否有权限 + * + * @param permission 权限 + * @return 是否 + */ + boolean hasPermission(String permission); + + /** + * 判断是否有权限,任一一个即可 + * + * @param permissions 权限 + * @return 是否 + */ + boolean hasAnyPermissions(String... permissions); + + /** + * 判断是否有角色 + * + * 注意,角色使用的是 SysRoleDO 的 code 标识 + * + * @param role 角色 + * @return 是否 + */ + boolean hasRole(String role); + + /** + * 判断是否有角色,任一一个即可 + * + * @param roles 角色数组 + * @return 是否 + */ + boolean hasAnyRoles(String... roles); + + /** + * 判断是否有授权 + * + * @param scope 授权 + * @return 是否 + */ + boolean hasScope(String scope); + + /** + * 判断是否有授权范围,任一一个即可 + * + * @param scope 授权范围数组 + * @return 是否 + */ + boolean hasAnyScopes(String... scope); +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java new file mode 100644 index 0000000..78caade --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/service/SecurityFrameworkServiceImpl.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.framework.security.core.service; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import lombok.AllArgsConstructor; + +import java.util.Arrays; + +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * 默认的 {@link SecurityFrameworkService} 实现类 + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class SecurityFrameworkServiceImpl implements SecurityFrameworkService { + + private final PermissionApi permissionApi; + + @Override + public boolean hasPermission(String permission) { + return hasAnyPermissions(permission); + } + + @Override + public boolean hasAnyPermissions(String... permissions) { + return permissionApi.hasAnyPermissions(getLoginUserId(), permissions); + } + + @Override + public boolean hasRole(String role) { + return hasAnyRoles(role); + } + + @Override + public boolean hasAnyRoles(String... roles) { + return permissionApi.hasAnyRoles(getLoginUserId(), roles); + } + + @Override + public boolean hasScope(String scope) { + return hasAnyScopes(scope); + } + + @Override + public boolean hasAnyScopes(String... scope) { + LoginUser user = SecurityFrameworkUtils.getLoginUser(); + if (user == null) { + return false; + } + return CollUtil.containsAny(user.getScopes(), Arrays.asList(scope)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java new file mode 100644 index 0000000..f85d77c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.framework.security.core.util; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.springframework.lang.Nullable; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; + +/** + * 安全服务工具类 + * + * @author 芋道源码 + */ +public class SecurityFrameworkUtils { + + /** + * HEADER 认证头 value 的前缀 + */ + public static final String AUTHORIZATION_BEARER = "Bearer"; + + private SecurityFrameworkUtils() {} + + /** + * 从请求中,获得认证 Token + * + * @param request 请求 + * @param headerName 认证 Token 对应的 Header 名字 + * @param parameterName 认证 Token 对应的 Parameter 名字 + * @return 认证 Token + */ + public static String obtainAuthorization(HttpServletRequest request, + String headerName, String parameterName) { + // 1. 获得 Token。优先级:Header > Parameter + String token = request.getHeader(headerName); + if (StrUtil.isEmpty(token)) { + token = request.getParameter(parameterName); + } + if (!StringUtils.hasText(token)) { + return null; + } + // 2. 去除 Token 中带的 Bearer + int index = token.indexOf(AUTHORIZATION_BEARER + " "); + return index >= 0 ? token.substring(index + 7).trim() : token; + } + + /** + * 获得当前认证信息 + * + * @return 认证信息 + */ + public static Authentication getAuthentication() { + SecurityContext context = SecurityContextHolder.getContext(); + if (context == null) { + return null; + } + return context.getAuthentication(); + } + + /** + * 获取当前用户 + * + * @return 当前用户 + */ + @Nullable + public static LoginUser getLoginUser() { + Authentication authentication = getAuthentication(); + if (authentication == null) { + return null; + } + return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null; + } + + /** + * 获得当前用户的编号,从上下文中 + * + * @return 用户编号 + */ + @Nullable + public static Long getLoginUserId() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? loginUser.getId() : null; + } + + /** + * 获得当前用户的昵称,从上下文中 + * + * @return 昵称 + */ + @Nullable + public static String getLoginUserNickname() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? MapUtil.getStr(loginUser.getInfo(), LoginUser.INFO_KEY_NICKNAME) : null; + } + + /** + * 获得当前用户的部门编号,从上下文中 + * + * @return 部门编号 + */ + @Nullable + public static Long getLoginUserDeptId() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? MapUtil.getLong(loginUser.getInfo(), LoginUser.INFO_KEY_DEPT_ID) : null; + } + + /** + * 设置当前用户 + * + * @param loginUser 登录用户 + * @param request 请求 + */ + public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) { + // 创建 Authentication,并设置到上下文 + Authentication authentication = buildAuthentication(loginUser, request); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号; + // 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息 + WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); + WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); + } + + private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) { + // 创建 UsernamePasswordAuthenticationToken 对象 + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + loginUser, null, Collections.emptyList()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + return authenticationToken; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java new file mode 100644 index 0000000..dc95b4e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java @@ -0,0 +1,7 @@ +/** + * 基于 Spring Security 框架 + * 实现安全认证功能 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.security; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..f5a1f81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +cn.iocoder.yudao.framework.security.config.YudaoSecurityAutoConfiguration +cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter +cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md new file mode 100644 index 0000000..b8a8931 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-security/《芋道 Spring Boot 安全框架 Spring Security 入门》.md @@ -0,0 +1,2 @@ +* 芋道 Spring Security 入门: +* Spring Security 基本概念: diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/pom.xml new file mode 100644 index 0000000..04576fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/pom.xml @@ -0,0 +1,60 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-test + jar + + ${project.artifactId} + 测试组件,用于单元测试、集成测试 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + org.mockito + mockito-inline + + + org.springframework.boot + spring-boot-starter-test + + + + com.h2database + h2 + + + + com.github.fppt + jedis-mock + + + + uk.co.jemos.podam + podam + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/RedisTestConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/RedisTestConfiguration.java new file mode 100644 index 0000000..4622291 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/RedisTestConfiguration.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.test.config; + +import com.github.fppt.jedismock.RedisServer; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +import java.io.IOException; + +/** + * Redis 测试 Configuration,主要实现内嵌 Redis 的启动 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +@Lazy(false) // 禁止延迟加载 +@EnableConfigurationProperties(RedisProperties.class) +public class RedisTestConfiguration { + + /** + * 创建模拟的 Redis Server 服务器 + */ + @Bean + public RedisServer redisServer(RedisProperties properties) throws IOException { + RedisServer redisServer = new RedisServer(properties.getPort()); + // 一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。 + try { + redisServer.start(); + } catch (Exception ignore) {} + return redisServer; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/SqlInitializationTestConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/SqlInitializationTestConfiguration.java new file mode 100644 index 0000000..abaec9d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/config/SqlInitializationTestConfiguration.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.test.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +import javax.sql.DataSource; + +/** + * SQL 初始化的测试 Configuration + * + * 为什么不使用 org.springframework.boot.autoconfigure.sql.init.DataSourceInitializationConfiguration 呢? + * 因为我们在单元测试会使用 spring.main.lazy-initialization 为 true,开启延迟加载。此时,会导致 DataSourceInitializationConfiguration 初始化 + * 不过呢,当前类的实现代码,基本是复制 DataSourceInitializationConfiguration 的哈! + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) +@ConditionalOnSingleCandidate(DataSource.class) +@ConditionalOnClass(name = "org.springframework.jdbc.datasource.init.DatabasePopulator") +@Lazy(value = false) // 禁止延迟加载 +@EnableConfigurationProperties(SqlInitializationProperties.class) +public class SqlInitializationTestConfiguration { + + @Bean + public DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, + SqlInitializationProperties initializationProperties) { + DatabaseInitializationSettings settings = createFrom(initializationProperties); + return new DataSourceScriptDatabaseInitializer(dataSource, settings); + } + + static DatabaseInitializationSettings createFrom(SqlInitializationProperties properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations(properties.getSchemaLocations()); + settings.setDataLocations(properties.getDataLocations()); + settings.setContinueOnError(properties.isContinueOnError()); + settings.setSeparator(properties.getSeparator()); + settings.setEncoding(properties.getEncoding()); + settings.setMode(properties.getMode()); + return settings; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java new file mode 100644 index 0000000..c4c0157 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.framework.test.core.ut; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.test.config.RedisTestConfiguration; +import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * 依赖内存 DB + Redis 的单元测试 + * + * 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis + * + * @author 芋道源码 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class) +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件 +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB +public class BaseDbAndRedisUnitTest { + + @Import({ + // DB 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类 + SqlInitializationTestConfiguration.class, // SQL 初始化 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + + // Redis 配置类 + RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + RedissonAutoConfiguration.class, // Redisson 自动配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbUnitTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbUnitTest.java new file mode 100644 index 0000000..316c4d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbUnitTest.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.test.core.ut; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +/** + * 依赖内存 DB 的单元测试 + * + * 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法 + * + * @author 芋道源码 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class) +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件 +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB +public class BaseDbUnitTest { + + @Import({ + // DB 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类 + SqlInitializationTestConfiguration.class, // SQL 初始化 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + MybatisPlusJoinAutoConfiguration.class, // MyBatis 的Join配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java new file mode 100644 index 0000000..2604869 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.framework.test.core.ut; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * 纯 Mockito 的单元测试 + * + * @author 芋道源码 + */ +@ExtendWith(MockitoExtension.class) +public class BaseMockitoUnitTest { +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseRedisUnitTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseRedisUnitTest.java new file mode 100644 index 0000000..7b84003 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseRedisUnitTest.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.test.core.ut; + +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.test.config.RedisTestConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +/** + * 依赖内存 Redis 的单元测试 + * + * 相比 {@link BaseDbUnitTest} 来说,从内存 DB 改成了内存 Redis + * + * @author 芋道源码 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisUnitTest.Application.class) +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件 +public class BaseRedisUnitTest { + + @Import({ + // Redis 配置类 + RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java new file mode 100644 index 0000000..bda7aad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java @@ -0,0 +1,4 @@ +/** + * 提供单元测试 Unit Test 的基类 + */ +package cn.iocoder.yudao.framework.test.core.ut; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java new file mode 100644 index 0000000..e98f498 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.framework.test.core.util; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * 单元测试,assert 断言工具类 + * + * @author 芋道源码 + */ +public class AssertUtils { + + /** + * 比对两个对象的属性是否一致 + * + * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 + * + * @param expected 期望对象 + * @param actual 实际对象 + * @param ignoreFields 忽略的属性数组 + */ + public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { + Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); + Arrays.stream(expectedFields).forEach(expectedField -> { + // 忽略 jacoco 自动生成的 $jacocoData 属性的情况 + if (expectedField.isSynthetic()) { + return; + } + // 如果是忽略的属性,则不进行比对 + if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { + return; + } + // 忽略不存在的属性 + Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); + if (actualField == null) { + return; + } + // 比对 + Assertions.assertEquals( + ReflectUtil.getFieldValue(expected, expectedField), + ReflectUtil.getFieldValue(actual, actualField), + String.format("Field(%s) 不匹配", expectedField.getName()) + ); + }); + } + + /** + * 比对两个对象的属性是否一致 + * + * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 + * + * @param expected 期望对象 + * @param actual 实际对象 + * @param ignoreFields 忽略的属性数组 + * @return 是否一致 + */ + public static boolean isPojoEquals(Object expected, Object actual, String... ignoreFields) { + Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); + return Arrays.stream(expectedFields).allMatch(expectedField -> { + // 如果是忽略的属性,则不进行比对 + if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { + return true; + } + // 忽略不存在的属性 + Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); + if (actualField == null) { + return true; + } + return Objects.equals(ReflectUtil.getFieldValue(expected, expectedField), + ReflectUtil.getFieldValue(actual, actualField)); + }); + } + + /** + * 执行方法,校验抛出的 Service 是否符合条件 + * + * @param executable 业务异常 + * @param errorCode 错误码对象 + * @param messageParams 消息参数 + */ + public static void assertServiceException(Executable executable, ErrorCode errorCode, Object... messageParams) { + // 调用方法 + ServiceException serviceException = assertThrows(ServiceException.class, executable); + // 校验错误码 + Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配"); + String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), messageParams); + Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java new file mode 100644 index 0000000..fbe6acf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.framework.test.core.util; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import uk.co.jemos.podam.api.PodamFactory; +import uk.co.jemos.podam.api.PodamFactoryImpl; +import uk.co.jemos.podam.common.AttributeStrategy; + +import javax.validation.constraints.Email; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 随机工具类 + * + * @author 芋道源码 + */ +public class RandomUtils { + + private static final int RANDOM_STRING_LENGTH = 10; + + private static final int TINYINT_MAX = 127; + + private static final int RANDOM_DATE_MAX = 30; + + private static final int RANDOM_COLLECTION_LENGTH = 5; + + private static final PodamFactory PODAM_FACTORY = new PodamFactoryImpl(); + + static { + // 字符串 + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(String.class, + (dataProviderStrategy, attributeMetadata, map) -> randomString()); + // Integer + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Integer.class, (dataProviderStrategy, attributeMetadata, map) -> { + // 如果是 status 的字段,返回 0 或 1 + if ("status".equals(attributeMetadata.getAttributeName())) { + return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); + } + // 如果是 type、status 结尾的字段,返回 tinyint 范围 + if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(), + "type", "status", "category", "scope", "result")) { + return RandomUtil.randomInt(0, TINYINT_MAX + 1); + } + return RandomUtil.randomInt(); + }); + // LocalDateTime + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class, + (dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime()); + // Boolean + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { + // 如果是 deleted 的字段,返回非删除 + if ("deleted".equals(attributeMetadata.getAttributeName())) { + return false; + } + return RandomUtil.randomBoolean(); + }); + } + + public static String randomString() { + return RandomUtil.randomString(RANDOM_STRING_LENGTH); + } + + public static Long randomLongId() { + return RandomUtil.randomLong(0, Long.MAX_VALUE); + } + + public static Integer randomInteger() { + return RandomUtil.randomInt(0, Integer.MAX_VALUE); + } + + public static Date randomDate() { + return RandomUtil.randomDay(0, RANDOM_DATE_MAX); + } + + public static LocalDateTime randomLocalDateTime() { + // 设置 Nano 为零的原因,避免 MySQL、H2 存储不到时间戳 + return LocalDateTimeUtil.of(randomDate()).withNano(0); + } + + public static Short randomShort() { + return (short) RandomUtil.randomInt(0, Short.MAX_VALUE); + } + + public static Set randomSet(Class clazz) { + return Stream.iterate(0, i -> i).limit(RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH)) + .map(i -> randomPojo(clazz)).collect(Collectors.toSet()); + } + + public static Integer randomCommonStatus() { + return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); + } + + public static String randomEmail() { + return randomString() + "@qq.com"; + } + + public static String randomURL() { + return "https://www.iocoder.cn/" + randomString(); + } + + @SafeVarargs + public static T randomPojo(Class clazz, Consumer... consumers) { + T pojo = PODAM_FACTORY.manufacturePojo(clazz); + // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 + if (ArrayUtil.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); + } + return pojo; + } + + @SafeVarargs + public static T randomPojo(Class clazz, Type type, Consumer... consumers) { + T pojo = PODAM_FACTORY.manufacturePojo(clazz, type); + // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 + if (ArrayUtil.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); + } + return pojo; + } + + @SafeVarargs + public static List randomPojoList(Class clazz, Consumer... consumers) { + int size = RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH); + return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers)) + .collect(Collectors.toList()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java new file mode 100644 index 0000000..3a17f51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java @@ -0,0 +1,4 @@ +/** + * 测试组件,用于单元测试、集成测试等等 + */ +package cn.iocoder.yudao.framework.test; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/《芋道 Spring Boot 单元测试 Test 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/《芋道 Spring Boot 单元测试 Test 入门》.md new file mode 100644 index 0000000..c6d0e9a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-test/《芋道 Spring Boot 单元测试 Test 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/pom.xml new file mode 100644 index 0000000..2ec8017 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/pom.xml @@ -0,0 +1,82 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-web + jar + + ${project.artifactId} + Web 框架,全局异常、API 日志、脱敏、错误码等 + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + com.github.xiaoymin + knife4j-openapi3-spring-boot-starter + + + org.springdoc + springdoc-openapi-ui + + + + org.springframework.security + spring-security-core + provided + + + + + cn.iocoder.boot + yudao-module-infra-api + ${revision} + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + org.jsoup + jsoup + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mockito + mockito-inline + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java new file mode 100644 index 0000000..2a0d8d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/config/YudaoApiLogAutoConfiguration.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.apilog.config; + +import cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter; +import cn.iocoder.yudao.framework.apilog.core.interceptor.ApiAccessLogInterceptor; +import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService; +import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkServiceImpl; +import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService; +import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkServiceImpl; +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration; +import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi; +import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.servlet.Filter; + +@AutoConfiguration(after = YudaoWebAutoConfiguration.class) +public class YudaoApiLogAutoConfiguration implements WebMvcConfigurer { + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public ApiAccessLogFrameworkService apiAccessLogFrameworkService(ApiAccessLogApi apiAccessLogApi) { + return new ApiAccessLogFrameworkServiceImpl(apiAccessLogApi); + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public ApiErrorLogFrameworkService apiErrorLogFrameworkService(ApiErrorLogApi apiErrorLogApi) { + return new ApiErrorLogFrameworkServiceImpl(apiErrorLogApi); + } + + /** + * 创建 ApiAccessLogFilter Bean,记录 API 请求日志 + */ + @Bean + @ConditionalOnProperty(prefix = "yudao.access-log", value = "enable", matchIfMissing = true) // 允许使用 yudao.access-log.enable=false 禁用访问日志 + public FilterRegistrationBean apiAccessLogFilter(WebProperties webProperties, + @Value("${spring.application.name}") String applicationName, + ApiAccessLogFrameworkService apiAccessLogFrameworkService) { + ApiAccessLogFilter filter = new ApiAccessLogFilter(webProperties, applicationName, apiAccessLogFrameworkService); + return createFilterBean(filter, WebFilterOrderEnum.API_ACCESS_LOG_FILTER); + } + + private static FilterRegistrationBean createFilterBean(T filter, Integer order) { + FilterRegistrationBean bean = new FilterRegistrationBean<>(filter); + bean.setOrder(order); + return bean; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new ApiAccessLogInterceptor()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java new file mode 100644 index 0000000..fe93ef6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.framework.apilog.core.annotation; + +import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 访问日志注解 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiAccessLog { + + // ========== 开关字段 ========== + + /** + * 是否记录访问日志 + */ + boolean enable() default true; + /** + * 是否记录请求参数 + * + * 默认记录,主要考虑请求数据一般不大。可手动设置为 false 进行关闭 + */ + boolean requestEnable() default true; + /** + * 是否记录响应结果 + * + * 默认不记录,主要考虑响应数据可能比较大。可手动设置为 true 进行打开 + */ + boolean responseEnable() default false; + /** + * 敏感参数数组 + * + * 添加后,请求参数、响应结果不会记录该参数 + */ + String[] sanitizeKeys() default {}; + + // ========== 模块字段 ========== + + /** + * 操作模块 + * + * 为空时,会尝试读取 {@link io.swagger.v3.oas.annotations.tags.Tag#name()} 属性 + */ + String operateModule() default ""; + /** + * 操作名 + * + * 为空时,会尝试读取 {@link io.swagger.v3.oas.annotations.Operation#summary()} 属性 + */ + String operateName() default ""; + /** + * 操作分类 + * + * 实际并不是数组,因为枚举不能设置 null 作为默认值 + */ + OperateTypeEnum[] operateType() default {}; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java new file mode 100644 index 0000000..a7f0055 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/enums/OperateTypeEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.framework.apilog.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 操作日志的操作类型 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum OperateTypeEnum { + + /** + * 查询 + */ + GET(1), + /** + * 新增 + */ + CREATE(2), + /** + * 修改 + */ + UPDATE(3), + /** + * 删除 + */ + DELETE(4), + /** + * 导出 + */ + EXPORT(5), + /** + * 导入 + */ + IMPORT(6), + /** + * 其它 + * + * 在无法归类时,可以选择使用其它。因为还有操作名可以进一步标识 + */ + OTHER(0); + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java new file mode 100644 index 0000000..1474d08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java @@ -0,0 +1,251 @@ +package cn.iocoder.yudao.framework.apilog.core.filter; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; +import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Iterator; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.interceptor.ApiAccessLogInterceptor.ATTRIBUTE_HANDLER_METHOD; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * API 访问日志 Filter + * + * 目的:记录 API 访问日志到数据库中 + * + * @author 芋道源码 + */ +@Slf4j +public class ApiAccessLogFilter extends ApiRequestFilter { + + private static final String[] SANITIZE_KEYS = new String[]{"password", "token", "accessToken", "refreshToken"}; + + private final String applicationName; + + private final ApiAccessLogFrameworkService apiAccessLogFrameworkService; + + public ApiAccessLogFilter(WebProperties webProperties, String applicationName, ApiAccessLogFrameworkService apiAccessLogFrameworkService) { + super(webProperties); + this.applicationName = applicationName; + this.apiAccessLogFrameworkService = apiAccessLogFrameworkService; + } + + @Override + @SuppressWarnings("NullableProblems") + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + // 获得开始时间 + LocalDateTime beginTime = LocalDateTime.now(); + // 提前获得参数,避免 XssFilter 过滤处理 + Map queryString = ServletUtils.getParamMap(request); + String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : null; + + try { + // 继续过滤器 + filterChain.doFilter(request, response); + // 正常执行,记录日志 + createApiAccessLog(request, beginTime, queryString, requestBody, null); + } catch (Exception ex) { + // 异常执行,记录日志 + createApiAccessLog(request, beginTime, queryString, requestBody, ex); + throw ex; + } + } + + private void createApiAccessLog(HttpServletRequest request, LocalDateTime beginTime, + Map queryString, String requestBody, Exception ex) { + ApiAccessLogCreateReqDTO accessLog = new ApiAccessLogCreateReqDTO(); + try { + boolean enable = buildApiAccessLog(accessLog, request, beginTime, queryString, requestBody, ex); + if (!enable) { + return; + } + apiAccessLogFrameworkService.createApiAccessLog(accessLog); + } catch (Throwable th) { + log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th); + } + } + + private boolean buildApiAccessLog(ApiAccessLogCreateReqDTO accessLog, HttpServletRequest request, LocalDateTime beginTime, + Map queryString, String requestBody, Exception ex) { + // 判断:是否要记录操作日志 + HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(ATTRIBUTE_HANDLER_METHOD); + ApiAccessLog accessLogAnnotation = null; + if (handlerMethod != null) { + accessLogAnnotation = handlerMethod.getMethodAnnotation(ApiAccessLog.class); + if (accessLogAnnotation != null && BooleanUtil.isFalse(accessLogAnnotation.enable())) { + return false; + } + } + + // 处理用户信息 + accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request)) + .setUserType(WebFrameworkUtils.getLoginUserType(request)); + // 设置访问结果 + CommonResult result = WebFrameworkUtils.getCommonResult(request); + if (result != null) { + accessLog.setResultCode(result.getCode()).setResultMsg(result.getMsg()); + } else if (ex != null) { + accessLog.setResultCode(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode()) + .setResultMsg(ExceptionUtil.getRootCauseMessage(ex)); + } else { + accessLog.setResultCode(GlobalErrorCodeConstants.SUCCESS.getCode()).setResultMsg(""); + } + // 设置请求字段 + accessLog.setTraceId(TracerUtils.getTraceId()).setApplicationName(applicationName) + .setRequestUrl(request.getRequestURI()).setRequestMethod(request.getMethod()) + .setUserAgent(ServletUtils.getUserAgent(request)).setUserIp(ServletUtils.getClientIP(request)); + String[] sanitizeKeys = accessLogAnnotation != null ? accessLogAnnotation.sanitizeKeys() : null; + Boolean requestEnable = accessLogAnnotation != null ? accessLogAnnotation.requestEnable() : Boolean.TRUE; + if (!BooleanUtil.isFalse(requestEnable)) { // 默认记录,所以判断 !false + Map requestParams = MapUtil.builder() + .put("query", sanitizeMap(queryString, sanitizeKeys)) + .put("body", sanitizeJson(requestBody, sanitizeKeys)).build(); + accessLog.setRequestParams(toJsonString(requestParams)); + } + Boolean responseEnable = accessLogAnnotation != null ? accessLogAnnotation.responseEnable() : Boolean.FALSE; + if (BooleanUtil.isTrue(responseEnable)) { // 默认不记录,默认强制要求 true + accessLog.setResponseBody(sanitizeJson(result, sanitizeKeys)); + } + // 持续时间 + accessLog.setBeginTime(beginTime).setEndTime(LocalDateTime.now()) + .setDuration((int) LocalDateTimeUtil.between(accessLog.getBeginTime(), accessLog.getEndTime(), ChronoUnit.MILLIS)); + + // 操作模块 + if (handlerMethod != null) { + Tag tagAnnotation = handlerMethod.getBeanType().getAnnotation(Tag.class); + Operation operationAnnotation = handlerMethod.getMethodAnnotation(Operation.class); + String operateModule = accessLogAnnotation != null ? accessLogAnnotation.operateModule() : + tagAnnotation != null ? StrUtil.nullToDefault(tagAnnotation.name(), tagAnnotation.description()) : null; + String operateName = accessLogAnnotation != null ? accessLogAnnotation.operateName() : + operationAnnotation != null ? operationAnnotation.summary() : null; + OperateTypeEnum operateType = accessLogAnnotation != null && accessLogAnnotation.operateType().length > 0 ? + accessLogAnnotation.operateType()[0] : parseOperateLogType(request); + accessLog.setOperateModule(operateModule).setOperateName(operateName).setOperateType(operateType.getType()); + } + return true; + } + + // ========== 解析 @ApiAccessLog、@Swagger 注解 ========== + + private static OperateTypeEnum parseOperateLogType(HttpServletRequest request) { + RequestMethod requestMethod = ArrayUtil.firstMatch(method -> + StrUtil.equalsAnyIgnoreCase(method.name(), request.getMethod()), RequestMethod.values()); + if (requestMethod == null) { + return OperateTypeEnum.OTHER; + } + switch (requestMethod) { + case GET: + return OperateTypeEnum.GET; + case POST: + return OperateTypeEnum.CREATE; + case PUT: + return OperateTypeEnum.UPDATE; + case DELETE: + return OperateTypeEnum.DELETE; + default: + return OperateTypeEnum.OTHER; + } + } + + // ========== 请求和响应的脱敏逻辑,移除类似 password、token 等敏感字段 ========== + + private static String sanitizeMap(Map map, String[] sanitizeKeys) { + if (CollUtil.isNotEmpty(map)) { + return null; + } + if (sanitizeKeys != null) { + MapUtil.removeAny(map, sanitizeKeys); + } + MapUtil.removeAny(map, SANITIZE_KEYS); + return JsonUtils.toJsonString(map); + } + + private static String sanitizeJson(String jsonString, String[] sanitizeKeys) { + if (StrUtil.isEmpty(jsonString)) { + return null; + } + try { + JsonNode rootNode = JsonUtils.parseTree(jsonString); + sanitizeJson(rootNode, sanitizeKeys); + return JsonUtils.toJsonString(rootNode); + } catch (Exception e) { + // 脱敏失败的情况下,直接忽略异常,避免影响用户请求 + log.error("[sanitizeJson][脱敏({}) 发生异常]", jsonString, e); + return jsonString; + } + } + + private static String sanitizeJson(CommonResult commonResult, String[] sanitizeKeys) { + if (commonResult == null) { + return null; + } + String jsonString = toJsonString(commonResult); + try { + JsonNode rootNode = JsonUtils.parseTree(jsonString); + sanitizeJson(rootNode.get("data"), sanitizeKeys); // 只处理 data 字段,不处理 code、msg 字段,避免错误被脱敏掉 + return JsonUtils.toJsonString(rootNode); + } catch (Exception e) { + // 脱敏失败的情况下,直接忽略异常,避免影响用户请求 + log.error("[sanitizeJson][脱敏({}) 发生异常]", jsonString, e); + return jsonString; + } + } + + private static void sanitizeJson(JsonNode node, String[] sanitizeKeys) { + // 情况一:数组,遍历处理 + if (node.isArray()) { + for (JsonNode childNode : node) { + sanitizeJson(childNode, sanitizeKeys); + } + return; + } + // 情况二:非 Object,只是某个值,直接返回 + if (!node.isObject()) { + return; + } + // 情况三:Object,遍历处理 + Iterator> iterator = node.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (ArrayUtil.contains(sanitizeKeys, entry.getKey()) + || ArrayUtil.contains(SANITIZE_KEYS, entry.getKey())) { + iterator.remove(); + continue; + } + sanitizeJson(entry.getValue(), sanitizeKeys); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java new file mode 100644 index 0000000..ef6ed5f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.framework.apilog.core.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StopWatch; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +/** + * API 访问日志 Interceptor + * + * 目的:在非 prod 环境时,打印 request 和 response 两条日志到日志文件(控制台)中。 + * + * @author 芋道源码 + */ +@Slf4j +public class ApiAccessLogInterceptor implements HandlerInterceptor { + + public static final String ATTRIBUTE_HANDLER_METHOD = "HANDLER_METHOD"; + + private static final String ATTRIBUTE_STOP_WATCH = "ApiAccessLogInterceptor.StopWatch"; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + // 记录 HandlerMethod,提供给 ApiAccessLogFilter 使用 + HandlerMethod handlerMethod = handler instanceof HandlerMethod ? (HandlerMethod) handler : null; + if (handlerMethod != null) { + request.setAttribute(ATTRIBUTE_HANDLER_METHOD, handlerMethod); + } + + // 打印 request 日志 + if (!SpringUtils.isProd()) { + Map queryString = ServletUtils.getParamMap(request); + String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : null; + if (CollUtil.isEmpty(queryString) && StrUtil.isEmpty(requestBody)) { + log.info("[preHandle][开始请求 URL({}) 无参数]", request.getRequestURI()); + } else { + log.info("[preHandle][开始请求 URL({}) 参数({})]", request.getRequestURI(), + StrUtil.blankToDefault(requestBody, queryString.toString())); + } + // 计时 + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch); + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + // 打印 response 日志 + if (!SpringUtils.isProd()) { + StopWatch stopWatch = (StopWatch) request.getAttribute(ATTRIBUTE_STOP_WATCH); + stopWatch.stop(); + log.info("[afterCompletion][完成请求 URL({}) 耗时({} ms)]", + request.getRequestURI(), stopWatch.getTotalTimeMillis()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkService.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkService.java new file mode 100644 index 0000000..2f3c78f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkService.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.apilog.core.service; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; + +/** + * API 访问日志 Framework Service 接口 + * + * @author 芋道源码 + */ +public interface ApiAccessLogFrameworkService { + + /** + * 创建 API 访问日志 + * + * @param reqDTO API 访问日志 + */ + void createApiAccessLog(ApiAccessLogCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkServiceImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkServiceImpl.java new file mode 100644 index 0000000..8f8e343 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLogFrameworkServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.apilog.core.service; + +import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; + +/** + * API 访问日志 Framework Service 实现类 + * + * 基于 {@link ApiAccessLogApi} 服务,记录访问日志 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class ApiAccessLogFrameworkServiceImpl implements ApiAccessLogFrameworkService { + + private final ApiAccessLogApi apiAccessLogApi; + + @Override + @Async + public void createApiAccessLog(ApiAccessLogCreateReqDTO reqDTO) { + apiAccessLogApi.createApiAccessLog(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkService.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkService.java new file mode 100644 index 0000000..33bebb7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkService.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.apilog.core.service; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; + +/** + * API 错误日志 Framework Service 接口 + * + * @author 芋道源码 + */ +public interface ApiErrorLogFrameworkService { + + /** + * 创建 API 错误日志 + * + * @param reqDTO API 错误日志 + */ + void createApiErrorLog(ApiErrorLogCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkServiceImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkServiceImpl.java new file mode 100644 index 0000000..32e4f80 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLogFrameworkServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.apilog.core.service; + +import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; + +/** + * API 错误日志 Framework Service 实现类 + * + * 基于 {@link ApiErrorLogApi} 服务,记录错误日志 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class ApiErrorLogFrameworkServiceImpl implements ApiErrorLogFrameworkService { + + private final ApiErrorLogApi apiErrorLogApi; + + @Override + @Async + public void createApiErrorLog(ApiErrorLogCreateReqDTO reqDTO) { + apiErrorLogApi.createApiErrorLog(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java new file mode 100644 index 0000000..cb93f3d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java @@ -0,0 +1,8 @@ +/** + * API 日志:包含两类 + * 1. API 访问日志:记录用户访问 API 的访问日志,定期归档历史日志。 + * 2. 异常日志:记录用户访问 API 的系统异常,方便日常排查问题与告警。 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.apilog; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java new file mode 100644 index 0000000..a8b6678 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/config/YudaoBannerAutoConfiguration.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.banner.config; + +import cn.iocoder.yudao.framework.banner.core.BannerApplicationRunner; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +/** + * Banner 的自动配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +public class YudaoBannerAutoConfiguration { + + @Bean + public BannerApplicationRunner bannerApplicationRunner() { + return new BannerApplicationRunner(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java new file mode 100644 index 0000000..bd931e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.banner.core; + +import cn.hutool.core.thread.ThreadUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.util.ClassUtils; + +import java.util.concurrent.TimeUnit; + +/** + * 项目启动成功后,提供文档相关的地址 + * + * @author 芋道源码 + */ +@Slf4j +public class BannerApplicationRunner implements ApplicationRunner { + + @Override + public void run(ApplicationArguments args) { + ThreadUtil.execute(() -> { + ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾 + log.info("\n----------------------------------------------------------\n\t" + + "项目启动成功!\n\t" + + "接口文档: \t{} \n\t" + + "开发文档: \t{} \n\t" + + "视频教程: \t{} \n" + + "----------------------------------------------------------", + "https://doc.iocoder.cn/api-doc/", + "https://doc.iocoder.cn", + "https://t.zsxq.com/02Yf6M7Qn"); + + // 数据报表 + if (isNotPresent("cn.iocoder.yudao.module.report.framework.security.config.SecurityConfiguration")) { + System.out.println("[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]"); + } + // 工作流 + if (isNotPresent("cn.iocoder.yudao.module.bpm.framework.flowable.config.BpmFlowableConfiguration")) { + System.out.println("[工作流模块 yudao-module-bpm - 已禁用][参考 https://doc.iocoder.cn/bpm/ 开启]"); + } + // 商城系统 + if (isNotPresent("cn.iocoder.yudao.module.trade.framework.web.config.TradeWebConfiguration")) { + System.out.println("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); + } + // ERP 系统 + if (isNotPresent("cn.iocoder.yudao.module.erp.framework.web.config.ErpWebConfiguration")) { + System.out.println("[ERP 系统 yudao-module-erp - 已禁用][参考 https://doc.iocoder.cn/erp/build/ 开启]"); + } + // CRM 系统 + if (isNotPresent("cn.iocoder.yudao.module.crm.framework.web.config.CrmWebConfiguration")) { + System.out.println("[CRM 系统 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]"); + } + // 微信公众号 + if (isNotPresent("cn.iocoder.yudao.module.mp.framework.mp.config.MpConfiguration")) { + System.out.println("[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]"); + } + // 支付平台 + if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) { + System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]"); + } + }); + } + + private static boolean isNotPresent(String className) { + return !ClassUtils.isPresent(className, ClassUtils.getDefaultClassLoader()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java new file mode 100644 index 0000000..aba7268 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/package-info.java @@ -0,0 +1,6 @@ +/** + * Banner 用于在 console 控制台,打印开发文档、接口文档等 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.banner; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java new file mode 100644 index 0000000..0166cb6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.desensitize.core.base.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; +import cn.iocoder.yudao.framework.desensitize.core.base.serializer.StringDesensitizeSerializer; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 顶级脱敏注解,自定义注解需要使用此注解 + * + * @author gaibu + */ +@Documented +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside // 此注解是其他所有 jackson 注解的元注解,打上了此注解的注解表明是 jackson 注解的一部分 +@JsonSerialize(using = StringDesensitizeSerializer.class) // 指定序列化器 +public @interface DesensitizeBy { + + /** + * 脱敏处理器 + */ + @SuppressWarnings("rawtypes") + Class handler(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java new file mode 100644 index 0000000..470a0be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/handler/DesensitizationHandler.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.desensitize.core.base.handler; + +import java.lang.annotation.Annotation; + +/** + * 脱敏处理器接口 + * + * @author gaibu + */ +public interface DesensitizationHandler { + + /** + * 脱敏 + * + * @param origin 原始字符串 + * @param annotation 注解信息 + * @return 脱敏后的字符串 + */ + String desensitize(String origin, T annotation); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java new file mode 100644 index 0000000..2c15a74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.framework.desensitize.core.base.serializer; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.lang.Singleton; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +/** + * 脱敏序列化器 + * + * 实现 JSON 返回数据时,使用 {@link DesensitizationHandler} 对声明脱敏注解的字段,进行脱敏处理。 + * + * @author gaibu + */ +@SuppressWarnings("rawtypes") +public class StringDesensitizeSerializer extends StdSerializer implements ContextualSerializer { + + @Getter + @Setter + private DesensitizationHandler desensitizationHandler; + + protected StringDesensitizeSerializer() { + super(String.class); + } + + @Override + public JsonSerializer createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) { + DesensitizeBy annotation = beanProperty.getAnnotation(DesensitizeBy.class); + if (annotation == null) { + return this; + } + // 创建一个 StringDesensitizeSerializer 对象,使用 DesensitizeBy 对应的处理器 + StringDesensitizeSerializer serializer = new StringDesensitizeSerializer(); + serializer.setDesensitizationHandler(Singleton.get(annotation.handler())); + return serializer; + } + + @Override + @SuppressWarnings("unchecked") + public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException { + if (StrUtil.isBlank(value)) { + gen.writeNull(); + return; + } + // 获取序列化字段 + Field field = getField(gen); + + // 自定义处理器 + DesensitizeBy[] annotations = AnnotationUtil.getCombinationAnnotations(field, DesensitizeBy.class); + if (ArrayUtil.isEmpty(annotations)) { + gen.writeString(value); + return; + } + for (Annotation annotation : field.getAnnotations()) { + if (AnnotationUtil.hasAnnotation(annotation.annotationType(), DesensitizeBy.class)) { + value = this.desensitizationHandler.desensitize(value, annotation); + gen.writeString(value); + return; + } + } + gen.writeString(value); + } + + /** + * 获取字段 + * + * @param generator JsonGenerator + * @return 字段 + */ + private Field getField(JsonGenerator generator) { + String currentName = generator.getOutputContext().getCurrentName(); + Object currentValue = generator.getCurrentValue(); + Class currentValueClass = currentValue.getClass(); + return ReflectUtil.getField(currentValueClass, currentName); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java new file mode 100644 index 0000000..227f254 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/EmailDesensitize.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.desensitize.core.regex.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.regex.handler.EmailDesensitizationHandler; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 邮箱脱敏注解 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = EmailDesensitizationHandler.class) +public @interface EmailDesensitize { + + /** + * 匹配的正则表达式 + */ + String regex() default "(^.)[^@]*(@.*$)"; + + /** + * 替换规则,邮箱; + * + * 比如:example@gmail.com 脱敏之后为 e****@gmail.com + */ + String replacer() default "$1****$2"; +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java new file mode 100644 index 0000000..4ab7c74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/annotation/RegexDesensitize.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.desensitize.core.regex.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 正则脱敏注解 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = DefaultRegexDesensitizationHandler.class) +public @interface RegexDesensitize { + + /** + * 匹配的正则表达式(默认匹配所有) + */ + String regex() default "^[\\s\\S]*$"; + + /** + * 替换规则,会将匹配到的字符串全部替换成 replacer + * + * 例如:regex=123; replacer=****** + * 原始字符串 123456789 + * 脱敏后字符串 ******456789 + */ + String replacer() default "******"; +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java new file mode 100644 index 0000000..f43431b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/AbstractRegexDesensitizationHandler.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.desensitize.core.regex.handler; + +import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; + +import java.lang.annotation.Annotation; + +/** + * 正则表达式脱敏处理器抽象类,已实现通用的方法 + * + * @author gaibu + */ +public abstract class AbstractRegexDesensitizationHandler + implements DesensitizationHandler { + + @Override + public String desensitize(String origin, T annotation) { + String regex = getRegex(annotation); + String replacer = getReplacer(annotation); + return origin.replaceAll(regex, replacer); + } + + /** + * 获取注解上的 regex 参数 + * + * @param annotation 注解信息 + * @return 正则表达式 + */ + abstract String getRegex(T annotation); + + /** + * 获取注解上的 replacer 参数 + * + * @param annotation 注解信息 + * @return 待替换的字符串 + */ + abstract String getReplacer(T annotation); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java new file mode 100644 index 0000000..f92414e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/DefaultRegexDesensitizationHandler.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.desensitize.core.regex.handler; + +import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.RegexDesensitize; + +/** + * {@link RegexDesensitize} 的正则脱敏处理器 + * + * @author gaibu + */ +public class DefaultRegexDesensitizationHandler extends AbstractRegexDesensitizationHandler { + + @Override + String getRegex(RegexDesensitize annotation) { + return annotation.regex(); + } + + @Override + String getReplacer(RegexDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java new file mode 100644 index 0000000..8d1867a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/regex/handler/EmailDesensitizationHandler.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.desensitize.core.regex.handler; + +import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.EmailDesensitize; + +/** + * {@link EmailDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class EmailDesensitizationHandler extends AbstractRegexDesensitizationHandler { + + @Override + String getRegex(EmailDesensitize annotation) { + return annotation.regex(); + } + + @Override + String getReplacer(EmailDesensitize annotation) { + return annotation.replacer(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java new file mode 100644 index 0000000..19ad54e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/BankCardDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.BankCardDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 银行卡号 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = BankCardDesensitization.class) +public @interface BankCardDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 6; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 2; + + /** + * 替换规则,银行卡号; 比如:9988002866797031 脱敏之后为 998800********31 + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java new file mode 100644 index 0000000..9000e1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/CarLicenseDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.CarLicenseDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 车牌号 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = CarLicenseDesensitization.class) +public @interface CarLicenseDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 3; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 1; + + /** + * 替换规则,车牌号;比如:粤A66666 脱敏之后为粤A6***6 + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java new file mode 100644 index 0000000..73a0d0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/ChineseNameDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.ChineseNameDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 中文名 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = ChineseNameDesensitization.class) +public @interface ChineseNameDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 1; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 0; + + /** + * 替换规则,中文名;比如:刘子豪脱敏之后为刘** + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java new file mode 100644 index 0000000..8622353 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/FixedPhoneDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.FixedPhoneDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 固定电话 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = FixedPhoneDesensitization.class) +public @interface FixedPhoneDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 4; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 2; + + /** + * 替换规则,固定电话;比如:01086551122 脱敏之后为 0108*****22 + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java new file mode 100644 index 0000000..8a654c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/IdCardDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.IdCardDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 身份证 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = IdCardDesensitization.class) +public @interface IdCardDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 6; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 2; + + /** + * 替换规则,身份证号码;比如:530321199204074611 脱敏之后为 530321**********11 + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java new file mode 100644 index 0000000..f0c42f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/MobileDesensitize.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.MobileDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 手机号 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = MobileDesensitization.class) +public @interface MobileDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 3; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 4; + + /** + * 替换规则,手机号;比如:13248765917 脱敏之后为 132****5917 + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java new file mode 100644 index 0000000..6a3b269 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/PasswordDesensitize.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.PasswordDesensitization; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 密码 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = PasswordDesensitization.class) +public @interface PasswordDesensitize { + + /** + * 前缀保留长度 + */ + int prefixKeep() default 0; + + /** + * 后缀保留长度 + */ + int suffixKeep() default 0; + + /** + * 替换规则,密码; + * + * 比如:123456 脱敏之后为 ****** + */ + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java new file mode 100644 index 0000000..ec79635 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/annotation/SliderDesensitize.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import cn.iocoder.yudao.framework.desensitize.core.slider.handler.DefaultDesensitizationHandler; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 滑动脱敏注解 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = DefaultDesensitizationHandler.class) +public @interface SliderDesensitize { + + /** + * 后缀保留长度 + */ + int suffixKeep() default 0; + + /** + * 替换规则,会将前缀后缀保留后,全部替换成 replacer + * + * 例如:prefixKeep = 1; suffixKeep = 2; replacer = "*"; + * 原始字符串 123456 + * 脱敏后 1***56 + */ + String replacer() default "*"; + + /** + * 前缀保留长度 + */ + int prefixKeep() default 0; +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java new file mode 100644 index 0000000..7dd2a7f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; + +import java.lang.annotation.Annotation; + +/** + * 滑动脱敏处理器抽象类,已实现通用的方法 + * + * @author gaibu + */ +public abstract class AbstractSliderDesensitizationHandler + implements DesensitizationHandler { + + @Override + public String desensitize(String origin, T annotation) { + int prefixKeep = getPrefixKeep(annotation); + int suffixKeep = getSuffixKeep(annotation); + String replacer = getReplacer(annotation); + int length = origin.length(); + + // 情况一:原始字符串长度小于等于保留长度,则原始字符串全部替换 + if (prefixKeep >= length || suffixKeep >= length) { + return buildReplacerByLength(replacer, length); + } + + // 情况二:原始字符串长度小于等于前后缀保留字符串长度,则原始字符串全部替换 + if ((prefixKeep + suffixKeep) >= length) { + return buildReplacerByLength(replacer, length); + } + + // 情况三:原始字符串长度大于前后缀保留字符串长度,则替换中间字符串 + int interval = length - prefixKeep - suffixKeep; + return origin.substring(0, prefixKeep) + + buildReplacerByLength(replacer, interval) + + origin.substring(prefixKeep + interval); + } + + /** + * 根据长度循环构建替换符 + * + * @param replacer 替换符 + * @param length 长度 + * @return 构建后的替换符 + */ + private String buildReplacerByLength(String replacer, int length) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length; i++) { + builder.append(replacer); + } + return builder.toString(); + } + + /** + * 前缀保留长度 + * + * @param annotation 注解信息 + * @return 前缀保留长度 + */ + abstract Integer getPrefixKeep(T annotation); + + /** + * 后缀保留长度 + * + * @param annotation 注解信息 + * @return 后缀保留长度 + */ + abstract Integer getSuffixKeep(T annotation); + + /** + * 替换符 + * + * @param annotation 注解信息 + * @return 替换符 + */ + abstract String getReplacer(T annotation); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java new file mode 100644 index 0000000..e1d90ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/BankCardDesensitization.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.BankCardDesensitize; + +/** + * {@link BankCardDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class BankCardDesensitization extends AbstractSliderDesensitizationHandler { + + @Override + Integer getPrefixKeep(BankCardDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(BankCardDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(BankCardDesensitize annotation) { + return annotation.replacer(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java new file mode 100644 index 0000000..34b3e9a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/CarLicenseDesensitization.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.CarLicenseDesensitize; + +/** + * {@link CarLicenseDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class CarLicenseDesensitization extends AbstractSliderDesensitizationHandler { + @Override + Integer getPrefixKeep(CarLicenseDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(CarLicenseDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(CarLicenseDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java new file mode 100644 index 0000000..f71dac0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/ChineseNameDesensitization.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.ChineseNameDesensitize; + +/** + * {@link ChineseNameDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class ChineseNameDesensitization extends AbstractSliderDesensitizationHandler { + + @Override + Integer getPrefixKeep(ChineseNameDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(ChineseNameDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(ChineseNameDesensitize annotation) { + return annotation.replacer(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java new file mode 100644 index 0000000..8b0adae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/DefaultDesensitizationHandler.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.SliderDesensitize; + +/** + * {@link SliderDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class DefaultDesensitizationHandler extends AbstractSliderDesensitizationHandler { + @Override + Integer getPrefixKeep(SliderDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(SliderDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(SliderDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java new file mode 100644 index 0000000..6e23261 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/FixedPhoneDesensitization.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.FixedPhoneDesensitize; + +/** + * {@link FixedPhoneDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHandler { + @Override + Integer getPrefixKeep(FixedPhoneDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(FixedPhoneDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(FixedPhoneDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java new file mode 100644 index 0000000..9d525b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/IdCardDesensitization.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.IdCardDesensitize; + +/** + * {@link IdCardDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class IdCardDesensitization extends AbstractSliderDesensitizationHandler { + @Override + Integer getPrefixKeep(IdCardDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(IdCardDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(IdCardDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java new file mode 100644 index 0000000..582900a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/MobileDesensitization.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.MobileDesensitize; + +/** + * {@link MobileDesensitize} 的脱敏处理器 + * + * @author gaibu + */ +public class MobileDesensitization extends AbstractSliderDesensitizationHandler { + + @Override + Integer getPrefixKeep(MobileDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(MobileDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(MobileDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java new file mode 100644 index 0000000..1bccaa2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/PasswordDesensitization.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.desensitize.core.slider.handler; + +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.PasswordDesensitize; + +/** + * {@link PasswordDesensitize} 的码脱敏处理器 + * + * @author gaibu + */ +public class PasswordDesensitization extends AbstractSliderDesensitizationHandler { + @Override + Integer getPrefixKeep(PasswordDesensitize annotation) { + return annotation.prefixKeep(); + } + + @Override + Integer getSuffixKeep(PasswordDesensitize annotation) { + return annotation.suffixKeep(); + } + + @Override + String getReplacer(PasswordDesensitize annotation) { + return annotation.replacer(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java new file mode 100644 index 0000000..bfe0187 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/package-info.java @@ -0,0 +1,4 @@ +/** + * 脱敏组件:支持 JSON 返回数据时,将邮箱、手机等字段进行脱敏 + */ +package cn.iocoder.yudao.framework.desensitize; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java new file mode 100644 index 0000000..4f94f16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.jackson.config; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.jackson.core.databind.NumberSerializer; +import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeDeserializer; +import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; + +@AutoConfiguration +@Slf4j +public class YudaoJacksonAutoConfiguration { + + @Bean + @SuppressWarnings("InstantiationOfUtilityClass") + public JsonUtils jsonUtils(List objectMappers) { + // 1.1 创建 SimpleModule 对象 + SimpleModule simpleModule = new SimpleModule(); + simpleModule + // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型 + .addSerializer(Long.class, NumberSerializer.INSTANCE) + .addSerializer(Long.TYPE, NumberSerializer.INSTANCE) + .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE) + .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE) + .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE) + .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE) + // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 + .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) + .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); + // 1.2 注册到 objectMapper + objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); + + // 2. 设置 objectMapper 到 JsonUtils + JsonUtils.init(CollUtil.getFirst(objectMappers)); + log.info("[init][初始化 JsonUtils 成功]"); + return new JsonUtils(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/NumberSerializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/NumberSerializer.java new file mode 100644 index 0000000..f6ddd3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/NumberSerializer.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.jackson.core.databind; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; + +import java.io.IOException; + +/** + * Long 序列化规则 + * + * 会将超长 long 值转换为 string,解决前端 JavaScript 最大安全整数是 2^53-1 的问题 + * + * @author 星语 + */ +@JacksonStdImpl +public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.NumberSerializer { + + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + public static final NumberSerializer INSTANCE = new NumberSerializer(Number.class); + + public NumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, serializers); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java new file mode 100644 index 0000000..71a480f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.jackson.core.databind; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +/** + * 基于时间戳的 LocalDateTime 反序列化器 + * + * @author 老五 + */ +public class TimestampLocalDateTimeDeserializer extends JsonDeserializer { + + public static final TimestampLocalDateTimeDeserializer INSTANCE = new TimestampLocalDateTimeDeserializer(); + + @Override + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // 将 Long 时间戳,转换为 LocalDateTime 对象 + return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java new file mode 100644 index 0000000..e72c47b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.jackson.core.databind; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; + +/** + * 基于时间戳的 LocalDateTime 序列化器 + * + * @author 老五 + */ +public class TimestampLocalDateTimeSerializer extends JsonSerializer { + + public static final TimestampLocalDateTimeSerializer INSTANCE = new TimestampLocalDateTimeSerializer(); + + @Override + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + // 将 LocalDateTime 对象,转换为 Long 时间戳 + gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java new file mode 100644 index 0000000..261b508 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.framework.jackson.core; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java new file mode 100644 index 0000000..2dc5316 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java @@ -0,0 +1,4 @@ +/** + * Web 框架,全局异常、API 日志等 + */ +package cn.iocoder.yudao.framework; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java new file mode 100644 index 0000000..13a1568 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/SwaggerProperties.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.swagger.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import javax.validation.constraints.NotEmpty; + +/** + * Swagger 配置属性 + * + * @author 芋道源码 + */ +@ConfigurationProperties("yudao.swagger") +@Data +public class SwaggerProperties { + + /** + * 标题 + */ + @NotEmpty(message = "标题不能为空") + private String title; + /** + * 描述 + */ + @NotEmpty(message = "描述不能为空") + private String description; + /** + * 作者 + */ + @NotEmpty(message = "作者不能为空") + private String author; + /** + * 版本 + */ + @NotEmpty(message = "版本不能为空") + private String version; + /** + * url + */ + @NotEmpty(message = "扫描的 package 不能为空") + private String url; + /** + * email + */ + @NotEmpty(message = "扫描的 email 不能为空") + private String email; + + /** + * license + */ + @NotEmpty(message = "扫描的 license 不能为空") + private String license; + + /** + * license-url + */ + @NotEmpty(message = "扫描的 license-url 不能为空") + private String licenseUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java new file mode 100644 index 0000000..a131d1f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.framework.swagger.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springdoc.core.*; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.providers.JavadocProvider; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.http.HttpHeaders; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * Swagger 自动配置类,基于 OpenAPI + Springdoc 实现。 + * + * 友情提示: + * 1. Springdoc 文档地址:仓库 + * 2. Swagger 规范,于 2015 更名为 OpenAPI 规范,本质是一个东西 + * + * @author 芋道源码 + */ +@AutoConfiguration +@ConditionalOnClass({OpenAPI.class}) +@EnableConfigurationProperties(SwaggerProperties.class) +@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用 +public class YudaoSwaggerAutoConfiguration { + + // ========== 全局 OpenAPI 配置 ========== + + @Bean + public OpenAPI createApi(SwaggerProperties properties) { + Map securitySchemas = buildSecuritySchemes(); + OpenAPI openAPI = new OpenAPI() + // 接口信息 + .info(buildInfo(properties)) + // 接口安全配置 + .components(new Components().securitySchemes(securitySchemas)) + .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION)); + securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key))); + return openAPI; + } + + /** + * API 摘要信息 + */ + private Info buildInfo(SwaggerProperties properties) { + return new Info() + .title(properties.getTitle()) + .description(properties.getDescription()) + .version(properties.getVersion()) + .contact(new Contact().name(properties.getAuthor()).url(properties.getUrl()).email(properties.getEmail())) + .license(new License().name(properties.getLicense()).url(properties.getLicenseUrl())); + } + + /** + * 安全模式,这里配置通过请求头 Authorization 传递 token 参数 + */ + private Map buildSecuritySchemes() { + Map securitySchemes = new HashMap<>(); + SecurityScheme securityScheme = new SecurityScheme() + .type(SecurityScheme.Type.APIKEY) // 类型 + .name(HttpHeaders.AUTHORIZATION) // 请求头的 name + .in(SecurityScheme.In.HEADER); // token 所在位置 + securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme); + return securitySchemes; + } + + /** + * 自定义 OpenAPI 处理器 + */ + @Bean + @Primary // 目的:以我们创建的 OpenAPIService Bean 为主,避免一键改包后,启动报错! + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, + PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, + propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + } + + // ========== 分组 OpenAPI 配置 ========== + + /** + * 所有模块的 API 分组 + */ + @Bean + public GroupedOpenApi allGroupedOpenApi() { + return buildGroupedOpenApi("all", ""); + } + + public static GroupedOpenApi buildGroupedOpenApi(String group) { + return buildGroupedOpenApi(group, group); + } + + public static GroupedOpenApi buildGroupedOpenApi(String group, String path) { + return GroupedOpenApi.builder() + .group(group) + .pathsToMatch("/admin-api/" + path + "/**", "/app-api/" + path + "/**") + .addOperationCustomizer((operation, handlerMethod) -> operation + .addParametersItem(buildTenantHeaderParameter()) + .addParametersItem(buildSecurityHeaderParameter())) + .build(); + } + + /** + * 构建 Tenant 租户编号请求头参数 + * + * @return 多租户参数 + */ + private static Parameter buildTenantHeaderParameter() { + return new Parameter() + .name(HEADER_TENANT_ID) // header 名 + .description("租户编号") // 描述 + .in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header + .schema(new IntegerSchema()._default(1L).name(HEADER_TENANT_ID).description("租户编号")); // 默认:使用租户编号为 1 + } + + /** + * 构建 Authorization 认证请求头参数 + * + * 解决 Knife4j Authorize 未生效,请求header里未包含参数 + * + * @return 认证参数 + */ + private static Parameter buildSecurityHeaderParameter() { + return new Parameter() + .name(HttpHeaders.AUTHORIZATION) // header 名 + .description("认证 Token") // 描述 + .in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header + .schema(new StringSchema()._default("Bearer test1").name(HEADER_TENANT_ID).description("认证 Token")); // 默认:使用用户编号为 1 + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java new file mode 100644 index 0000000..5eb7822 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/package-info.java @@ -0,0 +1,6 @@ +/** + * 基于 Swagger + Knife4j 实现 API 接口文档 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.framework.swagger; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java new file mode 100644 index 0000000..03f4d70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.framework.web.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@ConfigurationProperties(prefix = "yudao.web") +@Validated +@Data +public class WebProperties { + + @NotNull(message = "APP API 不能为空") + private Api appApi = new Api("/app-api", "**.controller.app.**"); + @NotNull(message = "Admin API 不能为空") + private Api adminApi = new Api("/admin-api", "**.controller.admin.**"); + + @NotNull(message = "Admin UI 不能为空") + private Ui adminUi; + + @Data + @AllArgsConstructor + @NoArgsConstructor + @Valid + public static class Api { + + /** + * API 前缀,实现所有 Controller 提供的 RESTFul API 的统一前缀 + * + * + * 意义:通过该前缀,避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部,带来安全性问题 + * 这样,Nginx 只需要配置转发到 /api/* 的所有接口即可。 + * + * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer) + */ + @NotEmpty(message = "API 前缀不能为空") + private String prefix; + + /** + * Controller 所在包的 Ant 路径规则 + * + * 主要目的是,给该 Controller 设置指定的 {@link #prefix} + */ + @NotEmpty(message = "Controller 所在包不能为空") + private String controller; + + } + + @Data + @Valid + public static class Ui { + + /** + * 访问地址 + */ + private String url; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java new file mode 100644 index 0000000..d875821 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.framework.web.config; + +import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService; +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter; +import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.springframework.beans.factory.annotation.Value; +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.client.RestTemplateAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.annotation.Resource; +import javax.servlet.Filter; + +@AutoConfiguration +@EnableConfigurationProperties(WebProperties.class) +public class YudaoWebAutoConfiguration implements WebMvcConfigurer { + + @Resource + private WebProperties webProperties; + /** + * 应用名 + */ + @Value("${spring.application.name}") + private String applicationName; + + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurePathMatch(configurer, webProperties.getAdminApi()); + configurePathMatch(configurer, webProperties.getAppApi()); + } + + /** + * 设置 API 前缀,仅仅匹配 controller 包下的 + * + * @param configurer 配置 + * @param api API 配置 + */ + private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) { + AntPathMatcher antPathMatcher = new AntPathMatcher("."); + configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class) + && antPathMatcher.match(api.getController(), clazz.getPackage().getName())); // 仅仅匹配 controller 包 + } + + @Bean + public GlobalExceptionHandler globalExceptionHandler(ApiErrorLogFrameworkService ApiErrorLogFrameworkService) { + return new GlobalExceptionHandler(applicationName, ApiErrorLogFrameworkService); + } + + @Bean + public GlobalResponseBodyHandler globalResponseBodyHandler() { + return new GlobalResponseBodyHandler(); + } + + @Bean + @SuppressWarnings("InstantiationOfUtilityClass") + public WebFrameworkUtils webFrameworkUtils(WebProperties webProperties) { + // 由于 WebFrameworkUtils 需要使用到 webProperties 属性,所以注册为一个 Bean + return new WebFrameworkUtils(webProperties); + } + + // ========== Filter 相关 ========== + + /** + * 创建 CorsFilter Bean,解决跨域问题 + */ + @Bean + public FilterRegistrationBean corsFilterBean() { + // 创建 CorsConfiguration 对象 + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOriginPattern("*"); // 设置访问源地址 + config.addAllowedHeader("*"); // 设置访问源请求头 + config.addAllowedMethod("*"); // 设置访问源请求方法 + // 创建 UrlBasedCorsConfigurationSource 对象 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); // 对接口配置跨域设置 + return createFilterBean(new CorsFilter(source), WebFilterOrderEnum.CORS_FILTER); + } + + /** + * 创建 RequestBodyCacheFilter Bean,可重复读取请求内容 + */ + @Bean + public FilterRegistrationBean requestBodyCacheFilter() { + return createFilterBean(new CacheRequestBodyFilter(), WebFilterOrderEnum.REQUEST_BODY_CACHE_FILTER); + } + + /** + * 创建 DemoFilter Bean,演示模式 + */ + @Bean + @ConditionalOnProperty(value = "yudao.demo", havingValue = "true") + public FilterRegistrationBean demoFilter() { + return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER); + } + + public static FilterRegistrationBean createFilterBean(T filter, Integer order) { + FilterRegistrationBean bean = new FilterRegistrationBean<>(filter); + bean.setOrder(order); + return bean; + } + + /** + * 创建 RestTemplate 实例 + * + * @param restTemplateBuilder {@link RestTemplateAutoConfiguration#restTemplateBuilder} + */ + @Bean + @ConditionalOnMissingBean + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { + return restTemplateBuilder.build(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java new file mode 100644 index 0000000..8e78a3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/ApiRequestFilter.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.web.core.filter; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import lombok.RequiredArgsConstructor; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.http.HttpServletRequest; + +/** + * 过滤 /admin-api、/app-api 等 API 请求的过滤器 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public abstract class ApiRequestFilter extends OncePerRequestFilter { + + protected final WebProperties webProperties; + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + // 只过滤 API 请求的地址 + return !StrUtil.startWithAny(request.getRequestURI(), webProperties.getAdminApi().getPrefix(), + webProperties.getAppApi().getPrefix()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java new file mode 100644 index 0000000..7051fc8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.web.core.filter; + +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Request Body 缓存 Filter,实现它的可重复读取 + * + * @author 芋道源码 + */ +public class CacheRequestBodyFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + filterChain.doFilter(new CacheRequestBodyWrapper(request), response); + } + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + // 只处理 json 请求内容 + return !ServletUtils.isJsonRequest(request); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java new file mode 100644 index 0000000..616a340 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.web.core.filter; + +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Request Body 缓存 Wrapper + * + * @author 芋道源码 + */ +public class CacheRequestBodyWrapper extends HttpServletRequestWrapper { + + /** + * 缓存的内容 + */ + private final byte[] body; + + public CacheRequestBodyWrapper(HttpServletRequest request) { + super(request); + body = ServletUtils.getBodyBytes(request); + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(this.getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream inputStream = new ByteArrayInputStream(body); + // 返回 ServletInputStream + return new ServletInputStream() { + + @Override + public int read() { + return inputStream.read(); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) {} + + @Override + public int available() { + return body.length; + } + + }; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java new file mode 100644 index 0000000..8e37247 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/DemoFilter.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.web.core.filter; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.DEMO_DENY; + +/** + * 演示 Filter,禁止用户发起写操作,避免影响测试数据 + * + * @author 芋道源码 + */ +public class DemoFilter extends OncePerRequestFilter { + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + String method = request.getMethod(); + return !StrUtil.equalsAnyIgnoreCase(method, "POST", "PUT", "DELETE") // 写操作时,不进行过滤率 + || WebFrameworkUtils.getLoginUserId(request) == null; // 非登录用户时,不进行过滤 + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { + // 直接返回 DEMO_DENY 的结果。即,请求不继续 + ServletUtils.writeJSON(response, CommonResult.error(DEMO_DENY)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..a997630 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -0,0 +1,334 @@ +package cn.iocoder.yudao.framework.web.core.handler; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.util.Assert; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.NoHandlerFoundException; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.ValidationException; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; + +/** + * 全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号 + * + * @author 芋道源码 + */ +@RestControllerAdvice +@AllArgsConstructor +@Slf4j +public class GlobalExceptionHandler { + + /** + * 忽略的 ServiceException 错误提示,避免打印过多 logger + */ + public static final Set IGNORE_ERROR_MESSAGES = SetUtils.asSet("无效的刷新令牌"); + + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + private final String applicationName; + + private final ApiErrorLogFrameworkService apiErrorLogFrameworkService; + + /** + * 处理所有异常,主要是提供给 Filter 使用 + * 因为 Filter 不走 SpringMVC 的流程,但是我们又需要兜底处理异常,所以这里提供一个全量的异常处理过程,保持逻辑统一。 + * + * @param request 请求 + * @param ex 异常 + * @return 通用返回 + */ + public CommonResult allExceptionHandler(HttpServletRequest request, Throwable ex) { + if (ex instanceof MissingServletRequestParameterException) { + return missingServletRequestParameterExceptionHandler((MissingServletRequestParameterException) ex); + } + if (ex instanceof MethodArgumentTypeMismatchException) { + return methodArgumentTypeMismatchExceptionHandler((MethodArgumentTypeMismatchException) ex); + } + if (ex instanceof MethodArgumentNotValidException) { + return methodArgumentNotValidExceptionExceptionHandler((MethodArgumentNotValidException) ex); + } + if (ex instanceof BindException) { + return bindExceptionHandler((BindException) ex); + } + if (ex instanceof ConstraintViolationException) { + return constraintViolationExceptionHandler((ConstraintViolationException) ex); + } + if (ex instanceof ValidationException) { + return validationException((ValidationException) ex); + } + if (ex instanceof NoHandlerFoundException) { + return noHandlerFoundExceptionHandler(request, (NoHandlerFoundException) ex); + } + if (ex instanceof HttpRequestMethodNotSupportedException) { + return httpRequestMethodNotSupportedExceptionHandler((HttpRequestMethodNotSupportedException) ex); + } + if (ex instanceof ServiceException) { + return serviceExceptionHandler((ServiceException) ex); + } + if (ex instanceof AccessDeniedException) { + return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); + } + return defaultExceptionHandler(request, ex); + } + + /** + * 处理 SpringMVC 请求参数缺失 + * + * 例如说,接口上设置了 @RequestParam("xx") 参数,结果并未传递 xx 参数 + */ + @ExceptionHandler(value = MissingServletRequestParameterException.class) + public CommonResult missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) { + log.warn("[missingServletRequestParameterExceptionHandler]", ex); + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数缺失:%s", ex.getParameterName())); + } + + /** + * 处理 SpringMVC 请求参数类型错误 + * + * 例如说,接口上设置了 @RequestParam("xx") 参数为 Integer,结果传递 xx 参数类型为 String + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public CommonResult methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException ex) { + log.warn("[missingServletRequestParameterExceptionHandler]", ex); + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", ex.getMessage())); + } + + /** + * 处理 SpringMVC 参数校验不正确 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public CommonResult methodArgumentNotValidExceptionExceptionHandler(MethodArgumentNotValidException ex) { + log.warn("[methodArgumentNotValidExceptionExceptionHandler]", ex); + FieldError fieldError = ex.getBindingResult().getFieldError(); + assert fieldError != null; // 断言,避免告警 + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数不正确:%s", fieldError.getDefaultMessage())); + } + + /** + * 处理 SpringMVC 参数绑定不正确,本质上也是通过 Validator 校验 + */ + @ExceptionHandler(BindException.class) + public CommonResult bindExceptionHandler(BindException ex) { + log.warn("[handleBindException]", ex); + FieldError fieldError = ex.getFieldError(); + assert fieldError != null; // 断言,避免告警 + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数不正确:%s", fieldError.getDefaultMessage())); + } + + /** + * 处理 Validator 校验不通过产生的异常 + */ + @ExceptionHandler(value = ConstraintViolationException.class) + public CommonResult constraintViolationExceptionHandler(ConstraintViolationException ex) { + log.warn("[constraintViolationExceptionHandler]", ex); + ConstraintViolation constraintViolation = ex.getConstraintViolations().iterator().next(); + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数不正确:%s", constraintViolation.getMessage())); + } + + /** + * 处理 Dubbo Consumer 本地参数校验时,抛出的 ValidationException 异常 + */ + @ExceptionHandler(value = ValidationException.class) + public CommonResult validationException(ValidationException ex) { + log.warn("[constraintViolationExceptionHandler]", ex); + // 无法拼接明细的错误信息,因为 Dubbo Consumer 抛出 ValidationException 异常时,是直接的字符串信息,且人类不可读 + return CommonResult.error(BAD_REQUEST); + } + + /** + * 处理 SpringMVC 请求地址不存在 + * + * 注意,它需要设置如下两个配置项: + * 1. spring.mvc.throw-exception-if-no-handler-found 为 true + * 2. spring.mvc.static-path-pattern 为 /statics/** + */ + @ExceptionHandler(NoHandlerFoundException.class) + public CommonResult noHandlerFoundExceptionHandler(HttpServletRequest req, NoHandlerFoundException ex) { + log.warn("[noHandlerFoundExceptionHandler]", ex); + return CommonResult.error(NOT_FOUND.getCode(), String.format("请求地址不存在:%s", ex.getRequestURL())); + } + + /** + * 处理 SpringMVC 请求方法不正确 + * + * 例如说,A 接口的方法为 GET 方式,结果请求方法为 POST 方式,导致不匹配 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public CommonResult httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException ex) { + log.warn("[httpRequestMethodNotSupportedExceptionHandler]", ex); + return CommonResult.error(METHOD_NOT_ALLOWED.getCode(), String.format("请求方法不正确:%s", ex.getMessage())); + } + + /** + * 处理 Spring Security 权限不足的异常 + * + * 来源是,使用 @PreAuthorize 注解,AOP 进行权限拦截 + */ + @ExceptionHandler(value = AccessDeniedException.class) + public CommonResult accessDeniedExceptionHandler(HttpServletRequest req, AccessDeniedException ex) { + log.warn("[accessDeniedExceptionHandler][userId({}) 无法访问 url({})]", WebFrameworkUtils.getLoginUserId(req), + req.getRequestURL(), ex); + return CommonResult.error(FORBIDDEN); + } + + /** + * 处理业务异常 ServiceException + * + * 例如说,商品库存不足,用户手机号已存在。 + */ + @ExceptionHandler(value = ServiceException.class) + public CommonResult serviceExceptionHandler(ServiceException ex) { + if (!IGNORE_ERROR_MESSAGES.contains(ex.getMessage())) { + // 不包含的时候,才进行打印,避免 ex 堆栈过多 + log.info("[serviceExceptionHandler]", ex); + } + return CommonResult.error(ex.getCode(), ex.getMessage()); + } + + /** + * 处理系统异常,兜底处理所有的一切 + */ + @ExceptionHandler(value = Exception.class) + public CommonResult defaultExceptionHandler(HttpServletRequest req, Throwable ex) { + // 情况一:处理表不存在的异常 + CommonResult tableNotExistsResult = handleTableNotExists(ex); + if (tableNotExistsResult != null) { + return tableNotExistsResult; + } + + // 情况二:处理异常 + log.error("[defaultExceptionHandler]", ex); + // 插入异常日志 + this.createExceptionLog(req, ex); + // 返回 ERROR CommonResult + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + } + + private void createExceptionLog(HttpServletRequest req, Throwable e) { + // 插入错误日志 + ApiErrorLogCreateReqDTO errorLog = new ApiErrorLogCreateReqDTO(); + try { + // 初始化 errorLog + buildExceptionLog(errorLog, req, e); + // 执行插入 errorLog + apiErrorLogFrameworkService.createApiErrorLog(errorLog); + } catch (Throwable th) { + log.error("[createExceptionLog][url({}) log({}) 发生异常]", req.getRequestURI(), JsonUtils.toJsonString(errorLog), th); + } + } + + private void buildExceptionLog(ApiErrorLogCreateReqDTO errorLog, HttpServletRequest request, Throwable e) { + // 处理用户信息 + errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); + errorLog.setUserType(WebFrameworkUtils.getLoginUserType(request)); + // 设置异常字段 + errorLog.setExceptionName(e.getClass().getName()); + errorLog.setExceptionMessage(ExceptionUtil.getMessage(e)); + errorLog.setExceptionRootCauseMessage(ExceptionUtil.getRootCauseMessage(e)); + errorLog.setExceptionStackTrace(ExceptionUtils.getStackTrace(e)); + StackTraceElement[] stackTraceElements = e.getStackTrace(); + Assert.notEmpty(stackTraceElements, "异常 stackTraceElements 不能为空"); + StackTraceElement stackTraceElement = stackTraceElements[0]; + errorLog.setExceptionClassName(stackTraceElement.getClassName()); + errorLog.setExceptionFileName(stackTraceElement.getFileName()); + errorLog.setExceptionMethodName(stackTraceElement.getMethodName()); + errorLog.setExceptionLineNumber(stackTraceElement.getLineNumber()); + // 设置其它字段 + errorLog.setTraceId(TracerUtils.getTraceId()); + errorLog.setApplicationName(applicationName); + errorLog.setRequestUrl(request.getRequestURI()); + Map requestParams = MapUtil.builder() + .put("query", ServletUtils.getParamMap(request)) + .put("body", ServletUtils.getBody(request)).build(); + errorLog.setRequestParams(JsonUtils.toJsonString(requestParams)); + errorLog.setRequestMethod(request.getMethod()); + errorLog.setUserAgent(ServletUtils.getUserAgent(request)); + errorLog.setUserIp(ServletUtils.getClientIP(request)); + errorLog.setExceptionTime(LocalDateTime.now()); + } + + /** + * 处理 Table 不存在的异常情况 + * + * @param ex 异常 + * @return 如果是 Table 不存在的异常,则返回对应的 CommonResult + */ + private CommonResult handleTableNotExists(Throwable ex) { + String message = ExceptionUtil.getRootCauseMessage(ex); + if (!message.contains("doesn't exist")) { + return null; + } + // 1. 数据报表 + if (message.contains("report_")) { + log.error("[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]"); + } + // 2. 工作流 + if (message.contains("bpm_")) { + log.error("[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]"); + } + // 3. 微信公众号 + if (message.contains("mp_")) { + log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]"); + } + // 4. 商城系统 + if (StrUtil.containsAny(message, "product_", "promotion_", "trade_")) { + log.error("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); + } + // 5. ERP 系统 + if (message.contains("erp_")) { + log.error("[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]"); + } + // 6. CRM 系统 + if (message.contains("crm_")) { + log.error("[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://doc.iocoder.cn/crm/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://doc.iocoder.cn/crm/build/ 开启]"); + } + // 7. 支付平台 + if (message.contains("pay_")) { + log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]"); + } + return null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java new file mode 100644 index 0000000..90da742 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.framework.web.core.handler; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +/** + * 全局响应结果(ResponseBody)处理器 + * + * 不同于在网上看到的很多文章,会选择自动将 Controller 返回结果包上 {@link CommonResult}, + * 在 onemall 中,是 Controller 在返回时,主动自己包上 {@link CommonResult}。 + * 原因是,GlobalResponseBodyHandler 本质上是 AOP,它不应该改变 Controller 返回的数据结构 + * + * 目前,GlobalResponseBodyHandler 的主要作用是,记录 Controller 的返回结果, + * 方便 {@link cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter} 记录访问日志 + */ +@ControllerAdvice +public class GlobalResponseBodyHandler implements ResponseBodyAdvice { + + @Override + @SuppressWarnings("NullableProblems") // 避免 IDEA 警告 + public boolean supports(MethodParameter returnType, Class converterType) { + if (returnType.getMethod() == null) { + return false; + } + // 只拦截返回结果为 CommonResult 类型 + return returnType.getMethod().getReturnType() == CommonResult.class; + } + + @Override + @SuppressWarnings("NullableProblems") // 避免 IDEA 警告 + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, + ServerHttpRequest request, ServerHttpResponse response) { + // 记录 Controller 结果 + WebFrameworkUtils.setCommonResult(((ServletServerHttpRequest) request).getServletRequest(), (CommonResult) body); + return body; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java new file mode 100644 index 0000000..b5a52c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.framework.web.core.util; + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +/** + * 专属于 web 包的工具类 + * + * @author 芋道源码 + */ +public class WebFrameworkUtils { + + private static final String REQUEST_ATTRIBUTE_LOGIN_USER_ID = "login_user_id"; + private static final String REQUEST_ATTRIBUTE_LOGIN_USER_TYPE = "login_user_type"; + + private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result"; + + public static final String HEADER_TENANT_ID = "tenant-id"; + + /** + * 终端的 Header + * + * @see cn.iocoder.yudao.framework.common.enums.TerminalEnum + */ + public static final String HEADER_TERMINAL = "terminal"; + + private static WebProperties properties; + + public WebFrameworkUtils(WebProperties webProperties) { + WebFrameworkUtils.properties = webProperties; + } + + /** + * 获得租户编号,从 header 中 + * 考虑到其它 framework 组件也会使用到租户编号,所以不得不放在 WebFrameworkUtils 统一提供 + * + * @param request 请求 + * @return 租户编号 + */ + public static Long getTenantId(HttpServletRequest request) { + String tenantId = request.getHeader(HEADER_TENANT_ID); + return NumberUtil.isNumber(tenantId) ? Long.valueOf(tenantId) : null; + } + + public static void setLoginUserId(ServletRequest request, Long userId) { + request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId); + } + + /** + * 设置用户类型 + * + * @param request 请求 + * @param userType 用户类型 + */ + public static void setLoginUserType(ServletRequest request, Integer userType) { + request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType); + } + + /** + * 获得当前用户的编号,从请求中 + * 注意:该方法仅限于 framework 框架使用!!! + * + * @param request 请求 + * @return 用户编号 + */ + public static Long getLoginUserId(HttpServletRequest request) { + if (request == null) { + return null; + } + return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID); + } + + /** + * 获得当前用户的类型 + * 注意:该方法仅限于 web 相关的 framework 组件使用!!! + * + * @param request 请求 + * @return 用户编号 + */ + public static Integer getLoginUserType(HttpServletRequest request) { + if (request == null) { + return null; + } + // 1. 优先,从 Attribute 中获取 + Integer userType = (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE); + if (userType != null) { + return userType; + } + // 2. 其次,基于 URL 前缀的约定 + if (request.getServletPath().startsWith(properties.getAdminApi().getPrefix())) { + return UserTypeEnum.ADMIN.getValue(); + } + if (request.getServletPath().startsWith(properties.getAppApi().getPrefix())) { + return UserTypeEnum.MEMBER.getValue(); + } + return null; + } + + public static Integer getLoginUserType() { + HttpServletRequest request = getRequest(); + return getLoginUserType(request); + } + + public static Long getLoginUserId() { + HttpServletRequest request = getRequest(); + return getLoginUserId(request); + } + + public static Integer getTerminal() { + HttpServletRequest request = getRequest(); + if (request == null) { + return TerminalEnum.UNKNOWN.getTerminal(); + } + String terminalValue = request.getHeader(HEADER_TERMINAL); + return NumberUtil.parseInt(terminalValue, TerminalEnum.UNKNOWN.getTerminal()); + } + + public static void setCommonResult(ServletRequest request, CommonResult result) { + request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result); + } + + public static CommonResult getCommonResult(ServletRequest request) { + return (CommonResult) request.getAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT); + } + + public static HttpServletRequest getRequest() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (!(requestAttributes instanceof ServletRequestAttributes)) { + return null; + } + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; + return servletRequestAttributes.getRequest(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java new file mode 100644 index 0000000..43b70eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * 针对 SpringMVC 的基础封装 + */ +package cn.iocoder.yudao.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java new file mode 100644 index 0000000..c914b04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/XssProperties.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.xss.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import java.util.Collections; +import java.util.List; + +/** + * Xss 配置属性 + * + * @author 芋道源码 + */ +@ConfigurationProperties(prefix = "yudao.xss") +@Validated +@Data +public class XssProperties { + + /** + * 是否开启,默认为 true + */ + private boolean enable = true; + /** + * 需要排除的 URL,默认为空 + */ + private List excludeUrls = Collections.emptyList(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java new file mode 100644 index 0000000..99b6a44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.xss.config; + +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.xss.core.clean.JsoupXssCleaner; +import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; +import cn.iocoder.yudao.framework.xss.core.filter.XssFilter; +import cn.iocoder.yudao.framework.xss.core.json.XssStringJsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.util.PathMatcher; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import static cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration.createFilterBean; + +@AutoConfiguration +@EnableConfigurationProperties(XssProperties.class) +@ConditionalOnProperty(prefix = "yudao.xss", name = "enable", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用 +public class YudaoXssAutoConfiguration implements WebMvcConfigurer { + + /** + * Xss 清理者 + * + * @return XssCleaner + */ + @Bean + @ConditionalOnMissingBean(XssCleaner.class) + public XssCleaner xssCleaner() { + return new JsoupXssCleaner(); + } + + /** + * 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤 + * + * @return Jackson2ObjectMapperBuilderCustomizer + */ + @Bean + @ConditionalOnMissingBean(name = "xssJacksonCustomizer") + @ConditionalOnBean(ObjectMapper.class) + @ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true") + public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssProperties properties, + PathMatcher pathMatcher, + XssCleaner xssCleaner) { + // 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer,在序列化时进行处理 + return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(properties, pathMatcher, xssCleaner)); + } + + /** + * 创建 XssFilter Bean,解决 Xss 安全问题 + */ + @Bean + @ConditionalOnBean(XssCleaner.class) + public FilterRegistrationBean xssFilter(XssProperties properties, PathMatcher pathMatcher, XssCleaner xssCleaner) { + return createFilterBean(new XssFilter(properties, pathMatcher, xssCleaner), WebFilterOrderEnum.XSS_FILTER); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java new file mode 100644 index 0000000..4cbc907 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/JsoupXssCleaner.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.xss.core.clean; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.safety.Safelist; + +/** + * 基于 JSONP 实现 XSS 过滤字符串 + */ +public class JsoupXssCleaner implements XssCleaner { + + private final Safelist safelist; + + /** + * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分) + */ + private final String baseUri; + + /** + * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表 + */ + public JsoupXssCleaner() { + this.safelist = buildSafelist(); + this.baseUri = ""; + } + + /** + * 构建一个 Xss 清理的 Safelist 规则。 + * 基于 Safelist#relaxed() 的基础上: + * 1. 扩展支持了 style 和 class 属性 + * 2. a 标签额外支持了 target 属性 + * 3. img 标签额外支持了 data 协议,便于支持 base64 + * + * @return Safelist + */ + private Safelist buildSafelist() { + // 使用 jsoup 提供的默认的 + Safelist relaxedSafelist = Safelist.relaxed(); + // 富文本编辑时一些样式是使用 style 来进行实现的 + // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性 + // 注意:style 属性会有注入风险 + relaxedSafelist.addAttributes(":all", "style", "class"); + // 保留 a 标签的 target 属性 + relaxedSafelist.addAttributes("a", "target"); + // 支持img 为base64 + relaxedSafelist.addProtocols("img", "src", "data"); + + // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除 + // WHITELIST.preserveRelativeLinks(false); + + // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如 + // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径 + // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto"); + // WHITELIST.removeProtocols("img", "src", "http", "https"); + return relaxedSafelist; + } + + @Override + public String clean(String html) { + return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false)); + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java new file mode 100644 index 0000000..529bc64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/clean/XssCleaner.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.framework.xss.core.clean; + +/** + * 对 html 文本中的有 Xss 风险的数据进行清理 + */ +public interface XssCleaner { + + /** + * 清理有 Xss 风险的文本 + * + * @param html 原 html + * @return 清理后的 html + */ + String clean(String html); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java new file mode 100644 index 0000000..5f2ce6e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssFilter.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.xss.core.filter; + +import cn.iocoder.yudao.framework.xss.config.XssProperties; +import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; +import lombok.AllArgsConstructor; +import org.springframework.util.PathMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Xss 过滤器 + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class XssFilter extends OncePerRequestFilter { + + /** + * 属性 + */ + private final XssProperties properties; + /** + * 路径匹配器 + */ + private final PathMatcher pathMatcher; + + private final XssCleaner xssCleaner; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + filterChain.doFilter(new XssRequestWrapper(request, xssCleaner), response); + } + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + // 如果关闭,则不过滤 + if (!properties.isEnable()) { + return true; + } + + // 如果匹配到无需过滤,则不过滤 + String uri = request.getRequestURI(); + return properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, uri)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java new file mode 100644 index 0000000..1466a97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/filter/XssRequestWrapper.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.framework.xss.core.filter; + +import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Xss 请求 Wrapper + * + * @author 芋道源码 + */ +public class XssRequestWrapper extends HttpServletRequestWrapper { + + private final XssCleaner xssCleaner; + + public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) { + super(request); + this.xssCleaner = xssCleaner; + } + + // ============================ parameter ============================ + @Override + public Map getParameterMap() { + Map map = new LinkedHashMap<>(); + Map parameters = super.getParameterMap(); + for (Map.Entry entry : parameters.entrySet()) { + String[] values = entry.getValue(); + for (int i = 0; i < values.length; i++) { + values[i] = xssCleaner.clean(values[i]); + } + map.put(entry.getKey(), values); + } + return map; + } + + @Override + public String[] getParameterValues(String name) { + String[] values = super.getParameterValues(name); + if (values == null) { + return null; + } + int count = values.length; + String[] encodedValues = new String[count]; + for (int i = 0; i < count; i++) { + encodedValues[i] = xssCleaner.clean(values[i]); + } + return encodedValues; + } + + @Override + public String getParameter(String name) { + String value = super.getParameter(name); + if (value == null) { + return null; + } + return xssCleaner.clean(value); + } + + // ============================ attribute ============================ + @Override + public Object getAttribute(String name) { + Object value = super.getAttribute(name); + if (value instanceof String) { + return xssCleaner.clean((String) value); + } + return value; + } + + // ============================ header ============================ + @Override + public String getHeader(String name) { + String value = super.getHeader(name); + if (value == null) { + return null; + } + return xssCleaner.clean(value); + } + + // ============================ queryString ============================ + @Override + public String getQueryString() { + String value = super.getQueryString(); + if (value == null) { + return null; + } + return xssCleaner.clean(value); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java new file mode 100644 index 0000000..0032443 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.framework.xss.core.json; + +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.xss.config.XssProperties; +import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.PathMatcher; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * XSS 过滤 jackson 反序列化器。 + * 在反序列化的过程中,会对字符串进行 XSS 过滤。 + * + * @author Hccake + */ +@Slf4j +@AllArgsConstructor +public class XssStringJsonDeserializer extends StringDeserializer { + + /** + * 属性 + */ + private final XssProperties properties; + /** + * 路径匹配器 + */ + private final PathMatcher pathMatcher; + + private final XssCleaner xssCleaner; + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // 1. 白名单 URL 的处理 + HttpServletRequest request = ServletUtils.getRequest(); + if (request != null) { + String uri = ServletUtils.getRequest().getRequestURI(); + if (properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, uri))) { + return p.getText(); + } + } + + // 2. 真正使用 xssCleaner 进行过滤 + if (p.hasToken(JsonToken.VALUE_STRING)) { + return xssCleaner.clean(p.getText()); + } + JsonToken t = p.currentToken(); + // [databind#381] + if (t == JsonToken.START_ARRAY) { + return _deserializeFromArray(p, ctxt); + } + // need to gracefully handle byte[] data, as base64 + if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { + Object ob = p.getEmbeddedObject(); + if (ob == null) { + return null; + } + if (ob instanceof byte[]) { + return ctxt.getBase64Variant().encode((byte[]) ob, false); + } + // otherwise, try conversion using toString()... + return ob.toString(); + } + // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML) + if (t == JsonToken.START_OBJECT) { + return ctxt.extractScalarFromObject(p, this, _valueClass); + } + + if (t.isScalarValue()) { + String text = p.getValueAsString(); + return xssCleaner.clean(text); + } + return (String) ctxt.handleUnexpectedToken(_valueClass, p); + } +} + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java new file mode 100644 index 0000000..c6e46f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/package-info.java @@ -0,0 +1,6 @@ +/** + * 针对 XSS 的基础封装 + * + * XSS 说明:https://tech.meituan.com/2018/09/27/fe-security.html + */ +package cn.iocoder.yudao.framework.xss; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..9cdcd09 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration +cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration +cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration +cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration +cn.iocoder.yudao.framework.xss.config.YudaoXssAutoConfiguration +cn.iocoder.yudao.framework.banner.config.YudaoBannerAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/banner.txt b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/banner.txt new file mode 100644 index 0000000..39a441d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/banner.txt @@ -0,0 +1,17 @@ +芋道源码 http://www.iocoder.cn +Application Version: ${yudao.info.version} +Spring Boot Version: ${spring-boot.version} + +.__ __. ______ .______ __ __ _______ +| \ | | / __ \ | _ \ | | | | / _____| +| \| | | | | | | |_) | | | | | | | __ +| . ` | | | | | | _ < | | | | | | |_ | +| |\ | | `--' | | |_) | | `--' | | |__| | +|__| \__| \______/ |______/ \______/ \______| + +███╗ ██╗ ██████╗ ██████╗ ██╗ ██╗ ██████╗ +████╗ ██║██╔═══██╗ ██╔══██╗██║ ██║██╔════╝ +██╔██╗ ██║██║ ██║ ██████╔╝██║ ██║██║ ███╗ +██║╚██╗██║██║ ██║ ██╔══██╗██║ ██║██║ ██║ +██║ ╚████║╚██████╔╝ ██████╔╝╚██████╔╝╚██████╔╝ +╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java new file mode 100644 index 0000000..dd214f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/DesensitizeTest.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.framework.desensitize.core; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.desensitize.core.annotation.Address; +import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.EmailDesensitize; +import cn.iocoder.yudao.framework.desensitize.core.regex.annotation.RegexDesensitize; +import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.*; +import lombok.Data; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link DesensitizeTest} 的单元测试 + */ +@ExtendWith(MockitoExtension.class) +public class DesensitizeTest { + + @Test + public void test() { + // 准备参数 + DesensitizeDemo desensitizeDemo = new DesensitizeDemo(); + desensitizeDemo.setNickname("芋道源码"); + desensitizeDemo.setBankCard("9988002866797031"); + desensitizeDemo.setCarLicense("粤A66666"); + desensitizeDemo.setFixedPhone("01086551122"); + desensitizeDemo.setIdCard("530321199204074611"); + desensitizeDemo.setPassword("123456"); + desensitizeDemo.setPhoneNumber("13248765917"); + desensitizeDemo.setSlider1("ABCDEFG"); + desensitizeDemo.setSlider2("ABCDEFG"); + desensitizeDemo.setSlider3("ABCDEFG"); + desensitizeDemo.setEmail("1@email.com"); + desensitizeDemo.setRegex("你好,我是芋道源码"); + desensitizeDemo.setAddress("北京市海淀区上地十街10号"); + desensitizeDemo.setOrigin("芋道源码"); + + // 调用 + DesensitizeDemo d = JsonUtils.parseObject(JsonUtils.toJsonString(desensitizeDemo), DesensitizeDemo.class); + // 断言 + assertNotNull(d); + assertEquals("芋***", d.getNickname()); + assertEquals("998800********31", d.getBankCard()); + assertEquals("粤A6***6", d.getCarLicense()); + assertEquals("0108*****22", d.getFixedPhone()); + assertEquals("530321**********11", d.getIdCard()); + assertEquals("******", d.getPassword()); + assertEquals("132****5917", d.getPhoneNumber()); + assertEquals("#######", d.getSlider1()); + assertEquals("ABC*EFG", d.getSlider2()); + assertEquals("*******", d.getSlider3()); + assertEquals("1****@email.com", d.getEmail()); + assertEquals("你好,我是*", d.getRegex()); + assertEquals("北京市海淀区上地十街10号*", d.getAddress()); + assertEquals("芋道源码", d.getOrigin()); + } + + @Data + public static class DesensitizeDemo { + + @ChineseNameDesensitize + private String nickname; + @BankCardDesensitize + private String bankCard; + @CarLicenseDesensitize + private String carLicense; + @FixedPhoneDesensitize + private String fixedPhone; + @IdCardDesensitize + private String idCard; + @PasswordDesensitize + private String password; + @MobileDesensitize + private String phoneNumber; + @SliderDesensitize(prefixKeep = 6, suffixKeep = 1, replacer = "#") + private String slider1; + @SliderDesensitize(prefixKeep = 3, suffixKeep = 3) + private String slider2; + @SliderDesensitize(prefixKeep = 10) + private String slider3; + @EmailDesensitize + private String email; + @RegexDesensitize(regex = "芋道源码", replacer = "*") + private String regex; + @Address + private String address; + private String origin; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java new file mode 100644 index 0000000..1301209 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/annotation/Address.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.framework.desensitize.core.annotation; + +import cn.iocoder.yudao.framework.desensitize.core.DesensitizeTest; +import cn.iocoder.yudao.framework.desensitize.core.handler.AddressHandler; +import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 地址 + * + * 用于 {@link DesensitizeTest} 测试使用 + * + * @author gaibu + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@DesensitizeBy(handler = AddressHandler.class) +public @interface Address { + + String replacer() default "*"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java new file mode 100644 index 0000000..7a8455f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/src/test/java/cn/iocoder/yudao/framework/desensitize/core/handler/AddressHandler.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.desensitize.core.handler; + +import cn.iocoder.yudao.framework.desensitize.core.DesensitizeTest; +import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; +import cn.iocoder.yudao.framework.desensitize.core.annotation.Address; + +/** + * {@link Address} 的脱敏处理器 + * + * 用于 {@link DesensitizeTest} 测试使用 + */ +public class AddressHandler implements DesensitizationHandler
{ + + @Override + public String desensitize(String origin, Address annotation) { + return origin + annotation.replacer(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md new file mode 100644 index 0000000..7ed5ebd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot API 接口文档 Swagger 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot SpringMVC 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot SpringMVC 入门》.md new file mode 100644 index 0000000..7c36a15 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-web/《芋道 Spring Boot SpringMVC 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/pom.xml b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/pom.xml new file mode 100644 index 0000000..b534f10 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/pom.xml @@ -0,0 +1,73 @@ + + + + cn.iocoder.boot + yudao-framework + ${revision} + + 4.0.0 + yudao-spring-boot-starter-websocket + jar + + ${project.artifactId} + WebSocket 框架,支持多节点的广播 + https://github.com/YunaiV/ruoyi-vue-pro + + + + + cn.iocoder.boot + yudao-common + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + provided + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + + + org.springframework.kafka + spring-kafka + true + + + org.springframework.amqp + spring-rabbit + true + + + org.apache.rocketmq + rocketmq-spring-boot-starter + true + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + provided + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java new file mode 100644 index 0000000..aa618fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/WebSocketProperties.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.websocket.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * WebSocket 配置项 + * + * @author xingyu4j + */ +@ConfigurationProperties("yudao.websocket") +@Data +@Validated +public class WebSocketProperties { + + /** + * WebSocket 的连接路径 + */ + @NotEmpty(message = "WebSocket 的连接路径不能为空") + private String path = "/ws"; + + /** + * 消息发送器的类型 + * + * 可选值:local、redis、rocketmq、kafka、rabbitmq + */ + @NotNull(message = "WebSocket 的消息发送者不能为空") + private String senderType = "local"; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java new file mode 100644 index 0000000..0f08b7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/config/YudaoWebSocketAutoConfiguration.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.framework.websocket.config; + +import cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration; +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.websocket.core.handler.JsonWebSocketMessageHandler; +import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import cn.iocoder.yudao.framework.websocket.core.security.LoginUserHandshakeInterceptor; +import cn.iocoder.yudao.framework.websocket.core.sender.kafka.KafkaWebSocketMessageConsumer; +import cn.iocoder.yudao.framework.websocket.core.sender.kafka.KafkaWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.local.LocalWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageConsumer; +import cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq.RabbitMQWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.redis.RedisWebSocketMessageConsumer; +import cn.iocoder.yudao.framework.websocket.core.sender.redis.RedisWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.rocketmq.RocketMQWebSocketMessageConsumer; +import cn.iocoder.yudao.framework.websocket.core.sender.rocketmq.RocketMQWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionHandlerDecorator; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManagerImpl; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Value; +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.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.List; + +/** + * WebSocket 自动配置 + * + * @author xingyu4j + */ +@AutoConfiguration(before = YudaoRedisMQConsumerAutoConfiguration.class) // before YudaoRedisMQConsumerAutoConfiguration 的原因是,需要保证 RedisWebSocketMessageConsumer 先创建,才能创建 RedisMessageListenerContainer +@EnableWebSocket // 开启 websocket +@ConditionalOnProperty(prefix = "yudao.websocket", value = "enable", matchIfMissing = true) // 允许使用 yudao.websocket.enable=false 禁用 websocket +@EnableConfigurationProperties(WebSocketProperties.class) +public class YudaoWebSocketAutoConfiguration { + + @Bean + public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor[] handshakeInterceptors, + WebSocketHandler webSocketHandler, + WebSocketProperties webSocketProperties) { + return registry -> registry + // 添加 WebSocketHandler + .addHandler(webSocketHandler, webSocketProperties.getPath()) + .addInterceptors(handshakeInterceptors) + // 允许跨域,否则前端连接会直接断开 + .setAllowedOriginPatterns("*"); + } + + @Bean + public HandshakeInterceptor handshakeInterceptor() { + return new LoginUserHandshakeInterceptor(); + } + + @Bean + public WebSocketHandler webSocketHandler(WebSocketSessionManager sessionManager, + List> messageListeners) { + // 1. 创建 JsonWebSocketMessageHandler 对象,处理消息 + JsonWebSocketMessageHandler messageHandler = new JsonWebSocketMessageHandler(messageListeners); + // 2. 创建 WebSocketSessionHandlerDecorator 对象,处理连接 + return new WebSocketSessionHandlerDecorator(messageHandler, sessionManager); + } + + @Bean + public WebSocketSessionManager webSocketSessionManager() { + return new WebSocketSessionManagerImpl(); + } + + // ==================== Sender 相关 ==================== + + @Configuration + @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "local", matchIfMissing = true) + public class LocalWebSocketMessageSenderConfiguration { + + @Bean + public LocalWebSocketMessageSender localWebSocketMessageSender(WebSocketSessionManager sessionManager) { + return new LocalWebSocketMessageSender(sessionManager); + } + + } + + @Configuration + @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "redis", matchIfMissing = true) + public class RedisWebSocketMessageSenderConfiguration { + + @Bean + public RedisWebSocketMessageSender redisWebSocketMessageSender(WebSocketSessionManager sessionManager, + RedisMQTemplate redisMQTemplate) { + return new RedisWebSocketMessageSender(sessionManager, redisMQTemplate); + } + + @Bean + public RedisWebSocketMessageConsumer redisWebSocketMessageConsumer( + RedisWebSocketMessageSender redisWebSocketMessageSender) { + return new RedisWebSocketMessageConsumer(redisWebSocketMessageSender); + } + + } + + @Configuration + @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "rocketmq", matchIfMissing = true) + public class RocketMQWebSocketMessageSenderConfiguration { + + @Bean + public RocketMQWebSocketMessageSender rocketMQWebSocketMessageSender( + WebSocketSessionManager sessionManager, RocketMQTemplate rocketMQTemplate, + @Value("${yudao.websocket.sender-rocketmq.topic}") String topic) { + return new RocketMQWebSocketMessageSender(sessionManager, rocketMQTemplate, topic); + } + + @Bean + public RocketMQWebSocketMessageConsumer rocketMQWebSocketMessageConsumer( + RocketMQWebSocketMessageSender rocketMQWebSocketMessageSender) { + return new RocketMQWebSocketMessageConsumer(rocketMQWebSocketMessageSender); + } + + } + + @Configuration + @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "rabbitmq", matchIfMissing = true) + public class RabbitMQWebSocketMessageSenderConfiguration { + + @Bean + public RabbitMQWebSocketMessageSender rabbitMQWebSocketMessageSender( + WebSocketSessionManager sessionManager, RabbitTemplate rabbitTemplate, + TopicExchange websocketTopicExchange) { + return new RabbitMQWebSocketMessageSender(sessionManager, rabbitTemplate, websocketTopicExchange); + } + + @Bean + public RabbitMQWebSocketMessageConsumer rabbitMQWebSocketMessageConsumer( + RabbitMQWebSocketMessageSender rabbitMQWebSocketMessageSender) { + return new RabbitMQWebSocketMessageConsumer(rabbitMQWebSocketMessageSender); + } + + /** + * 创建 Topic Exchange + */ + @Bean + public TopicExchange websocketTopicExchange(@Value("${yudao.websocket.sender-rabbitmq.exchange}") String exchange) { + return new TopicExchange(exchange, + true, // durable: 是否持久化 + false); // exclusive: 是否排它 + } + + } + + @Configuration + @ConditionalOnProperty(prefix = "yudao.websocket", name = "sender-type", havingValue = "kafka", matchIfMissing = true) + public class KafkaWebSocketMessageSenderConfiguration { + + @Bean + public KafkaWebSocketMessageSender kafkaWebSocketMessageSender( + WebSocketSessionManager sessionManager, KafkaTemplate kafkaTemplate, + @Value("${yudao.websocket.sender-kafka.topic}") String topic) { + return new KafkaWebSocketMessageSender(sessionManager, kafkaTemplate, topic); + } + + @Bean + public KafkaWebSocketMessageConsumer kafkaWebSocketMessageConsumer( + KafkaWebSocketMessageSender kafkaWebSocketMessageSender) { + return new KafkaWebSocketMessageConsumer(kafkaWebSocketMessageSender); + } + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java new file mode 100644 index 0000000..120f529 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.framework.websocket.core.handler; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.TypeUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; +import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * JSON 格式 {@link WebSocketHandler} 实现类 + * + * 基于 {@link JsonWebSocketMessage#getType()} 消息类型,调度到对应的 {@link WebSocketMessageListener} 监听器。 + * + * @author 芋道源码 + */ +@Slf4j +public class JsonWebSocketMessageHandler extends TextWebSocketHandler { + + /** + * type 与 WebSocketMessageListener 的映射 + */ + private final Map> listeners = new HashMap<>(); + + @SuppressWarnings({"rawtypes", "unchecked"}) + public JsonWebSocketMessageHandler(List listenersList) { + listenersList.forEach((Consumer) + listener -> listeners.put(listener.getType(), listener)); + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + // 1.1 空消息,跳过 + if (message.getPayloadLength() == 0) { + return; + } + // 1.2 ping 心跳消息,直接返回 pong 消息。 + if (message.getPayloadLength() == 4 && Objects.equals(message.getPayload(), "ping")) { + session.sendMessage(new TextMessage("pong")); + return; + } + + // 2.1 解析消息 + try { + JsonWebSocketMessage jsonMessage = JsonUtils.parseObject(message.getPayload(), JsonWebSocketMessage.class); + if (jsonMessage == null) { + log.error("[handleTextMessage][session({}) message({}) 解析为空]", session.getId(), message.getPayload()); + return; + } + if (StrUtil.isEmpty(jsonMessage.getType())) { + log.error("[handleTextMessage][session({}) message({}) 类型为空]", session.getId(), message.getPayload()); + return; + } + // 2.2 获得对应的 WebSocketMessageListener + WebSocketMessageListener messageListener = listeners.get(jsonMessage.getType()); + if (messageListener == null) { + log.error("[handleTextMessage][session({}) message({}) 监听器为空]", session.getId(), message.getPayload()); + return; + } + // 2.3 处理消息 + Type type = TypeUtil.getTypeArgument(messageListener.getClass(), 0); + Object messageObj = JsonUtils.parseObject(jsonMessage.getContent(), type); + Long tenantId = WebSocketFrameworkUtils.getTenantId(session); + TenantUtils.execute(tenantId, () -> messageListener.onMessage(session, messageObj)); + } catch (Throwable ex) { + log.error("[handleTextMessage][session({}) message({}) 处理异常]", session.getId(), message.getPayload()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java new file mode 100644 index 0000000..f3a62cc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/listener/WebSocketMessageListener.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.websocket.core.listener; + +import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; +import org.springframework.web.socket.WebSocketSession; + +/** + * WebSocket 消息监听器接口 + * + * 目的:前端发送消息给后端后,处理对应 {@link #getType()} 类型的消息 + * + * @param 泛型,消息类型 + */ +public interface WebSocketMessageListener { + + /** + * 处理消息 + * + * @param session Session + * @param message 消息 + */ + void onMessage(WebSocketSession session, T message); + + /** + * 获得消息类型 + * + * @see JsonWebSocketMessage#getType() + * @return 消息类型 + */ + String getType(); + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java new file mode 100644 index 0000000..0a55cd6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/message/JsonWebSocketMessage.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.websocket.core.message; + +import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import lombok.Data; + +import java.io.Serializable; + +/** + * JSON 格式的 WebSocket 消息帧 + * + * @author 芋道源码 + */ +@Data +public class JsonWebSocketMessage implements Serializable { + + /** + * 消息类型 + * + * 目的:用于分发到对应的 {@link WebSocketMessageListener} 实现类 + */ + private String type; + /** + * 消息内容 + * + * 要求 JSON 对象 + */ + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java new file mode 100644 index 0000000..3a31825 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.websocket.core.security; + +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.Map; + +/** + * 登录用户的 {@link HandshakeInterceptor} 实现类 + * + * 流程如下: + * 1. 前端连接 websocket 时,会通过拼接 ?token={token} 到 ws:// 连接后,这样它可以被 {@link TokenAuthenticationFilter} 所认证通过 + * 2. {@link LoginUserHandshakeInterceptor} 负责把 {@link LoginUser} 添加到 {@link WebSocketSession} 中 + * + * @author 芋道源码 + */ +public class LoginUserHandshakeInterceptor implements HandshakeInterceptor { + + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, + WebSocketHandler wsHandler, Map attributes) { + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser != null) { + WebSocketFrameworkUtils.setLoginUser(loginUser, attributes); + } + return true; + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, + WebSocketHandler wsHandler, Exception exception) { + // do nothing + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java new file mode 100644 index 0000000..5614f05 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/WebSocketAuthorizeRequestsCustomizer.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.framework.websocket.core.security; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import cn.iocoder.yudao.framework.websocket.config.WebSocketProperties; +import lombok.RequiredArgsConstructor; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; + +/** + * WebSocket 的权限自定义 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class WebSocketAuthorizeRequestsCustomizer extends AuthorizeRequestsCustomizer { + + private final WebSocketProperties webSocketProperties; + + @Override + public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) { + registry.antMatchers(webSocketProperties.getPath()).permitAll(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java new file mode 100644 index 0000000..4e0db44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.framework.websocket.core.sender; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.websocket.core.message.JsonWebSocketMessage; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * WebSocketMessageSender 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public abstract class AbstractWebSocketMessageSender implements WebSocketMessageSender { + + private final WebSocketSessionManager sessionManager; + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + send(null, userType, userId, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + send(null, userType, null, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + send(sessionId, null, null, messageType, messageContent); + } + + /** + * 发送消息 + * + * @param sessionId Session 编号 + * @param userType 用户类型 + * @param userId 用户编号 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + public void send(String sessionId, Integer userType, Long userId, String messageType, String messageContent) { + // 1. 获得 Session 列表 + List sessions = Collections.emptyList(); + if (StrUtil.isNotEmpty(sessionId)) { + WebSocketSession session = sessionManager.getSession(sessionId); + if (session != null) { + sessions = Collections.singletonList(session); + } + } else if (userType != null && userId != null) { + sessions = (List) sessionManager.getSessionList(userType, userId); + } else if (userType != null) { + sessions = (List) sessionManager.getSessionList(userType); + } + if (CollUtil.isEmpty(sessions)) { + log.info("[send][sessionId({}) userType({}) userId({}) messageType({}) messageContent({}) 未匹配到会话]", + sessionId, userType, userId, messageType, messageContent); + } + // 2. 执行发送 + doSend(sessions, messageType, messageContent); + } + + /** + * 发送消息的具体实现 + * + * @param sessions Session 列表 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + public void doSend(Collection sessions, String messageType, String messageContent) { + JsonWebSocketMessage message = new JsonWebSocketMessage().setType(messageType).setContent(messageContent); + String payload = JsonUtils.toJsonString(message); // 关键,使用 JSON 序列化 + sessions.forEach(session -> { + // 1. 各种校验,保证 Session 可以被发送 + if (session == null) { + log.error("[doSend][session 为空, message({})]", message); + return; + } + if (!session.isOpen()) { + log.error("[doSend][session({}) 已关闭, message({})]", session.getId(), message); + return; + } + // 2. 执行发送 + try { + session.sendMessage(new TextMessage(payload)); + log.info("[doSend][session({}) 发送消息成功,message({})]", session.getId(), message); + } catch (IOException ex) { + log.error("[doSend][session({}) 发送消息失败,message({})]", session.getId(), message, ex); + } + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java new file mode 100644 index 0000000..9f75ad5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/WebSocketMessageSender.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.websocket.core.sender; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; + +/** + * WebSocket 消息的发送器接口 + * + * @author 芋道源码 + */ +public interface WebSocketMessageSender { + + /** + * 发送消息给指定用户 + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(Integer userType, Long userId, String messageType, String messageContent); + + /** + * 发送消息给指定用户类型 + * + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(Integer userType, String messageType, String messageContent); + + /** + * 发送消息给指定 Session + * + * @param sessionId Session 编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(String sessionId, String messageType, String messageContent); + + default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) { + send(userType, userId, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(Integer userType, String messageType, Object messageContent) { + send(userType, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(String sessionId, String messageType, Object messageContent) { + send(sessionId, messageType, JsonUtils.toJsonString(messageContent)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java new file mode 100644 index 0000000..5a4cf53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessage.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.kafka; + +import lombok.Data; + +/** + * Kafka 广播 WebSocket 的消息 + * + * @author 芋道源码 + */ +@Data +public class KafkaWebSocketMessage { + + /** + * Session 编号 + */ + private String sessionId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 用户编号 + */ + private Long userId; + + /** + * 消息类型 + */ + private String messageType; + /** + * 消息内容 + */ + private String messageContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java new file mode 100644 index 0000000..201e65d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageConsumer.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.kafka; + +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.kafka.annotation.KafkaListener; + +/** + * {@link KafkaWebSocketMessage} 广播消息的消费者,真正把消息发送出去 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class KafkaWebSocketMessageConsumer { + + private final KafkaWebSocketMessageSender rabbitMQWebSocketMessageSender; + + @RabbitHandler + @KafkaListener( + topics = "${yudao.websocket.sender-kafka.topic}", + // 在 Group 上,使用 UUID 生成其后缀。这样,启动的 Consumer 的 Group 不同,以达到广播消费的目的 + groupId = "${yudao.websocket.sender-kafka.consumer-group}" + "-" + "#{T(java.util.UUID).randomUUID()}") + public void onMessage(KafkaWebSocketMessage message) { + rabbitMQWebSocketMessageSender.send(message.getSessionId(), + message.getUserType(), message.getUserId(), + message.getMessageType(), message.getMessageContent()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java new file mode 100644 index 0000000..47bb598 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/kafka/KafkaWebSocketMessageSender.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.kafka; + +import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; + +import java.util.concurrent.ExecutionException; + +/** + * 基于 Kafka 的 {@link WebSocketMessageSender} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class KafkaWebSocketMessageSender extends AbstractWebSocketMessageSender { + + private final KafkaTemplate kafkaTemplate; + + private final String topic; + + public KafkaWebSocketMessageSender(WebSocketSessionManager sessionManager, + KafkaTemplate kafkaTemplate, + String topic) { + super(sessionManager); + this.kafkaTemplate = kafkaTemplate; + this.topic = topic; + } + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + sendKafkaMessage(null, userId, userType, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + sendKafkaMessage(null, null, userType, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + sendKafkaMessage(sessionId, null, null, messageType, messageContent); + } + + /** + * 通过 Kafka 广播消息 + * + * @param sessionId Session 编号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + private void sendKafkaMessage(String sessionId, Long userId, Integer userType, + String messageType, String messageContent) { + KafkaWebSocketMessage mqMessage = new KafkaWebSocketMessage() + .setSessionId(sessionId).setUserId(userId).setUserType(userType) + .setMessageType(messageType).setMessageContent(messageContent); + try { + kafkaTemplate.send(topic, mqMessage).get(); + } catch (InterruptedException | ExecutionException e) { + log.error("[sendKafkaMessage][发送消息({}) 到 Kafka 失败]", mqMessage, e); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java new file mode 100644 index 0000000..66640ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/local/LocalWebSocketMessageSender.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.local; + +import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; + +/** + * 本地的 {@link WebSocketMessageSender} 实现类 + * + * 注意:仅仅适合单机场景!!! + * + * @author 芋道源码 + */ +public class LocalWebSocketMessageSender extends AbstractWebSocketMessageSender { + + public LocalWebSocketMessageSender(WebSocketSessionManager sessionManager) { + super(sessionManager); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java new file mode 100644 index 0000000..80a4bc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessage.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; + +import lombok.Data; + +import java.io.Serializable; + +/** + * RabbitMQ 广播 WebSocket 的消息 + * + * @author 芋道源码 + */ +@Data +public class RabbitMQWebSocketMessage implements Serializable { + + /** + * Session 编号 + */ + private String sessionId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 用户编号 + */ + private Long userId; + + /** + * 消息类型 + */ + private String messageType; + /** + * 消息内容 + */ + private String messageContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java new file mode 100644 index 0000000..59e3824 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageConsumer.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; + +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.core.ExchangeTypes; +import org.springframework.amqp.rabbit.annotation.*; + +/** + * {@link RabbitMQWebSocketMessage} 广播消息的消费者,真正把消息发送出去 + * + * @author 芋道源码 + */ +@RabbitListener( + bindings = @QueueBinding( + value = @Queue( + // 在 Queue 的名字上,使用 UUID 生成其后缀。这样,启动的 Consumer 的 Queue 不同,以达到广播消费的目的 + name = "${yudao.websocket.sender-rabbitmq.queue}" + "-" + "#{T(java.util.UUID).randomUUID()}", + // Consumer 关闭时,该队列就可以被自动删除了 + autoDelete = "true" + ), + exchange = @Exchange( + name = "${yudao.websocket.sender-rabbitmq.exchange}", + type = ExchangeTypes.TOPIC, + declare = "false" + ) + ) +) +@RequiredArgsConstructor +public class RabbitMQWebSocketMessageConsumer { + + private final RabbitMQWebSocketMessageSender rabbitMQWebSocketMessageSender; + + @RabbitHandler + public void onMessage(RabbitMQWebSocketMessage message) { + rabbitMQWebSocketMessageSender.send(message.getSessionId(), + message.getUserType(), message.getUserId(), + message.getMessageType(), message.getMessageContent()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java new file mode 100644 index 0000000..065a5d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rabbitmq/RabbitMQWebSocketMessageSender.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rabbitmq; + +import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.rabbit.core.RabbitTemplate; + +/** + * 基于 RabbitMQ 的 {@link WebSocketMessageSender} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class RabbitMQWebSocketMessageSender extends AbstractWebSocketMessageSender { + + private final RabbitTemplate rabbitTemplate; + + private final TopicExchange topicExchange; + + public RabbitMQWebSocketMessageSender(WebSocketSessionManager sessionManager, + RabbitTemplate rabbitTemplate, + TopicExchange topicExchange) { + super(sessionManager); + this.rabbitTemplate = rabbitTemplate; + this.topicExchange = topicExchange; + } + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + sendRabbitMQMessage(null, userId, userType, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + sendRabbitMQMessage(null, null, userType, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + sendRabbitMQMessage(sessionId, null, null, messageType, messageContent); + } + + /** + * 通过 RabbitMQ 广播消息 + * + * @param sessionId Session 编号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + private void sendRabbitMQMessage(String sessionId, Long userId, Integer userType, + String messageType, String messageContent) { + RabbitMQWebSocketMessage mqMessage = new RabbitMQWebSocketMessage() + .setSessionId(sessionId).setUserId(userId).setUserType(userType) + .setMessageType(messageType).setMessageContent(messageContent); + rabbitTemplate.convertAndSend(topicExchange.getName(), null, mqMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java new file mode 100644 index 0000000..fb9ea0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessage.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.redis; + +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage; +import lombok.Data; + +/** + * Redis 广播 WebSocket 的消息 + */ +@Data +public class RedisWebSocketMessage extends AbstractRedisChannelMessage { + + /** + * Session 编号 + */ + private String sessionId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 用户编号 + */ + private Long userId; + + /** + * 消息类型 + */ + private String messageType; + /** + * 消息内容 + */ + private String messageContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java new file mode 100644 index 0000000..abce006 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageConsumer.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.redis; + +import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener; +import lombok.RequiredArgsConstructor; + +/** + * {@link RedisWebSocketMessage} 广播消息的消费者,真正把消息发送出去 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +public class RedisWebSocketMessageConsumer extends AbstractRedisChannelMessageListener { + + private final RedisWebSocketMessageSender redisWebSocketMessageSender; + + @Override + public void onMessage(RedisWebSocketMessage message) { + redisWebSocketMessageSender.send(message.getSessionId(), + message.getUserType(), message.getUserId(), + message.getMessageType(), message.getMessageContent()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java new file mode 100644 index 0000000..d6004ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/redis/RedisWebSocketMessageSender.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.redis; + +import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate; +import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import lombok.extern.slf4j.Slf4j; + +/** + * 基于 Redis 的 {@link WebSocketMessageSender} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender { + + private final RedisMQTemplate redisMQTemplate; + + public RedisWebSocketMessageSender(WebSocketSessionManager sessionManager, + RedisMQTemplate redisMQTemplate) { + super(sessionManager); + this.redisMQTemplate = redisMQTemplate; + } + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + sendRedisMessage(null, userId, userType, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + sendRedisMessage(null, null, userType, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + sendRedisMessage(sessionId, null, null, messageType, messageContent); + } + + /** + * 通过 Redis 广播消息 + * + * @param sessionId Session 编号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + private void sendRedisMessage(String sessionId, Long userId, Integer userType, + String messageType, String messageContent) { + RedisWebSocketMessage mqMessage = new RedisWebSocketMessage() + .setSessionId(sessionId).setUserId(userId).setUserType(userType) + .setMessageType(messageType).setMessageContent(messageContent); + redisMQTemplate.send(mqMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java new file mode 100644 index 0000000..91570e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessage.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; + +import lombok.Data; + +/** + * RocketMQ 广播 WebSocket 的消息 + * + * @author 芋道源码 + */ +@Data +public class RocketMQWebSocketMessage { + + /** + * Session 编号 + */ + private String sessionId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 用户编号 + */ + private Long userId; + + /** + * 消息类型 + */ + private String messageType; + /** + * 消息内容 + */ + private String messageContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java new file mode 100644 index 0000000..ab2e2c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageConsumer.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; + +import lombok.RequiredArgsConstructor; +import org.apache.rocketmq.spring.annotation.MessageModel; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; + +/** + * {@link RocketMQWebSocketMessage} 广播消息的消费者,真正把消息发送出去 + * + * @author 芋道源码 + */ +@RocketMQMessageListener( // 重点:添加 @RocketMQMessageListener 注解,声明消费的 topic + topic = "${yudao.websocket.sender-rocketmq.topic}", + consumerGroup = "${yudao.websocket.sender-rocketmq.consumer-group}", + messageModel = MessageModel.BROADCASTING // 设置为广播模式,保证每个实例都能收到消息 +) +@RequiredArgsConstructor +public class RocketMQWebSocketMessageConsumer implements RocketMQListener { + + private final RocketMQWebSocketMessageSender rocketMQWebSocketMessageSender; + + @Override + public void onMessage(RocketMQWebSocketMessage message) { + rocketMQWebSocketMessageSender.send(message.getSessionId(), + message.getUserType(), message.getUserId(), + message.getMessageType(), message.getMessageContent()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java new file mode 100644 index 0000000..ed059ba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/rocketmq/RocketMQWebSocketMessageSender.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.framework.websocket.core.sender.rocketmq; + +import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.core.RocketMQTemplate; + +/** + * 基于 RocketMQ 的 {@link WebSocketMessageSender} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class RocketMQWebSocketMessageSender extends AbstractWebSocketMessageSender { + + private final RocketMQTemplate rocketMQTemplate; + + private final String topic; + + public RocketMQWebSocketMessageSender(WebSocketSessionManager sessionManager, + RocketMQTemplate rocketMQTemplate, + String topic) { + super(sessionManager); + this.rocketMQTemplate = rocketMQTemplate; + this.topic = topic; + } + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + sendRocketMQMessage(null, userId, userType, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + sendRocketMQMessage(null, null, userType, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + sendRocketMQMessage(sessionId, null, null, messageType, messageContent); + } + + /** + * 通过 RocketMQ 广播消息 + * + * @param sessionId Session 编号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容 + */ + private void sendRocketMQMessage(String sessionId, Long userId, Integer userType, + String messageType, String messageContent) { + RocketMQWebSocketMessage mqMessage = new RocketMQWebSocketMessage() + .setSessionId(sessionId).setUserId(userId).setUserType(userType) + .setMessageType(messageType).setMessageContent(messageContent); + rocketMQTemplate.syncSend(topic, mqMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java new file mode 100644 index 0000000..600a4dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionHandlerDecorator.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.framework.websocket.core.session; + +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator; +import org.springframework.web.socket.handler.WebSocketHandlerDecorator; + +/** + * {@link WebSocketHandler} 的装饰类,实现了以下功能: + * + * 1. {@link WebSocketSession} 连接或关闭时,使用 {@link #sessionManager} 进行管理 + * 2. 封装 {@link WebSocketSession} 支持并发操作 + * + * @author 芋道源码 + */ +public class WebSocketSessionHandlerDecorator extends WebSocketHandlerDecorator { + + /** + * 发送时间的限制,单位:毫秒 + */ + private static final Integer SEND_TIME_LIMIT = 1000 * 5; + /** + * 发送消息缓冲上线,单位:bytes + */ + private static final Integer BUFFER_SIZE_LIMIT = 1024 * 100; + + private final WebSocketSessionManager sessionManager; + + public WebSocketSessionHandlerDecorator(WebSocketHandler delegate, + WebSocketSessionManager sessionManager) { + super(delegate); + this.sessionManager = sessionManager; + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) { + // 实现 session 支持并发,可参考 https://blog.csdn.net/abu935009066/article/details/131218149 + session = new ConcurrentWebSocketSessionDecorator(session, SEND_TIME_LIMIT, BUFFER_SIZE_LIMIT); + // 添加到 WebSocketSessionManager 中 + sessionManager.addSession(session); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) { + sessionManager.removeSession(session); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java new file mode 100644 index 0000000..ad1de23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManager.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.framework.websocket.core.session; + +import org.springframework.web.socket.WebSocketSession; + +import java.util.Collection; + +/** + * {@link WebSocketSession} 管理器的接口 + * + * @author 芋道源码 + */ +public interface WebSocketSessionManager { + + /** + * 添加 Session + * + * @param session Session + */ + void addSession(WebSocketSession session); + + /** + * 移除 Session + * + * @param session Session + */ + void removeSession(WebSocketSession session); + + /** + * 获得指定编号的 Session + * + * @param id Session 编号 + * @return Session + */ + WebSocketSession getSession(String id); + + /** + * 获得指定用户类型的 Session 列表 + * + * @param userType 用户类型 + * @return Session 列表 + */ + Collection getSessionList(Integer userType); + + /** + * 获得指定用户编号的 Session 列表 + * + * @param userType 用户类型 + * @param userId 用户编号 + * @return Session 列表 + */ + Collection getSessionList(Integer userType, Long userId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java new file mode 100644 index 0000000..6dba898 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/session/WebSocketSessionManagerImpl.java @@ -0,0 +1,125 @@ +package cn.iocoder.yudao.framework.websocket.core.session; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import org.springframework.web.socket.WebSocketSession; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * 默认的 {@link WebSocketSessionManager} 实现类 + * + * @author 芋道源码 + */ +public class WebSocketSessionManagerImpl implements WebSocketSessionManager { + + /** + * id 与 WebSocketSession 映射 + * + * key:Session 编号 + */ + private final ConcurrentMap idSessions = new ConcurrentHashMap<>(); + + /** + * user 与 WebSocketSession 映射 + * + * key1:用户类型 + * key2:用户编号 + */ + private final ConcurrentMap>> userSessions + = new ConcurrentHashMap<>(); + + @Override + public void addSession(WebSocketSession session) { + // 添加到 idSessions 中 + idSessions.put(session.getId(), session); + // 添加到 userSessions 中 + LoginUser user = WebSocketFrameworkUtils.getLoginUser(session); + if (user == null) { + return; + } + ConcurrentMap> userSessionsMap = userSessions.get(user.getUserType()); + if (userSessionsMap == null) { + userSessionsMap = new ConcurrentHashMap<>(); + if (userSessions.putIfAbsent(user.getUserType(), userSessionsMap) != null) { + userSessionsMap = userSessions.get(user.getUserType()); + } + } + CopyOnWriteArrayList sessions = userSessionsMap.get(user.getId()); + if (sessions == null) { + sessions = new CopyOnWriteArrayList<>(); + if (userSessionsMap.putIfAbsent(user.getId(), sessions) != null) { + sessions = userSessionsMap.get(user.getId()); + } + } + sessions.add(session); + } + + @Override + public void removeSession(WebSocketSession session) { + // 移除从 idSessions 中 + idSessions.remove(session.getId()); + // 移除从 idSessions 中 + LoginUser user = WebSocketFrameworkUtils.getLoginUser(session); + if (user == null) { + return; + } + ConcurrentMap> userSessionsMap = userSessions.get(user.getUserType()); + if (userSessionsMap == null) { + return; + } + CopyOnWriteArrayList sessions = userSessionsMap.get(user.getId()); + sessions.removeIf(session0 -> session0.getId().equals(session.getId())); + if (CollUtil.isEmpty(sessions)) { + userSessionsMap.remove(user.getId(), sessions); + } + } + + @Override + public WebSocketSession getSession(String id) { + return idSessions.get(id); + } + + @Override + public Collection getSessionList(Integer userType) { + ConcurrentMap> userSessionsMap = userSessions.get(userType); + if (CollUtil.isEmpty(userSessionsMap)) { + return new ArrayList<>(); + } + LinkedList result = new LinkedList<>(); // 避免扩容 + Long contextTenantId = TenantContextHolder.getTenantId(); + for (List sessions : userSessionsMap.values()) { + if (CollUtil.isEmpty(sessions)) { + continue; + } + // 特殊:如果租户不匹配,则直接排除 + if (contextTenantId != null) { + Long userTenantId = WebSocketFrameworkUtils.getTenantId(sessions.get(0)); + if (!contextTenantId.equals(userTenantId)) { + continue; + } + } + result.addAll(sessions); + } + return result; + } + + @Override + public Collection getSessionList(Integer userType, Long userId) { + ConcurrentMap> userSessionsMap = userSessions.get(userType); + if (CollUtil.isEmpty(userSessionsMap)) { + return new ArrayList<>(); + } + CopyOnWriteArrayList sessions = userSessionsMap.get(userId); + return CollUtil.isNotEmpty(sessions) ? new ArrayList<>(sessions) : new ArrayList<>(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java new file mode 100644 index 0000000..58cdedc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/util/WebSocketFrameworkUtils.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.framework.websocket.core.util; + +import cn.iocoder.yudao.framework.security.core.LoginUser; +import org.springframework.web.socket.WebSocketSession; + +import java.util.Map; + +/** + * 专属于 web 包的工具类 + * + * @author 芋道源码 + */ +public class WebSocketFrameworkUtils { + + public static final String ATTRIBUTE_LOGIN_USER = "LOGIN_USER"; + + /** + * 设置当前用户 + * + * @param loginUser 登录用户 + * @param attributes Session + */ + public static void setLoginUser(LoginUser loginUser, Map attributes) { + attributes.put(ATTRIBUTE_LOGIN_USER, loginUser); + } + + /** + * 获取当前用户 + * + * @return 当前用户 + */ + public static LoginUser getLoginUser(WebSocketSession session) { + return (LoginUser) session.getAttributes().get(ATTRIBUTE_LOGIN_USER); + } + + /** + * 获得当前用户的编号 + * + * @return 用户编号 + */ + public static Long getLoginUserId(WebSocketSession session) { + LoginUser loginUser = getLoginUser(session); + return loginUser != null ? loginUser.getId() : null; + } + + /** + * 获得当前用户的类型 + * + * @return 用户编号 + */ + public static Integer getLoginUserType(WebSocketSession session) { + LoginUser loginUser = getLoginUser(session); + return loginUser != null ? loginUser.getUserType() : null; + } + + /** + * 获得当前用户的租户编号 + * + * @param session Session + * @return 租户编号 + */ + public static Long getTenantId(WebSocketSession session) { + LoginUser loginUser = getLoginUser(session); + return loginUser != null ? loginUser.getTenantId() : null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java new file mode 100644 index 0000000..97bc5f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/package-info.java @@ -0,0 +1,4 @@ +/** + * WebSocket 框架,支持多节点的广播 + */ +package cn.iocoder.yudao.framework.websocket; diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6260e40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.websocket.config.YudaoWebSocketAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/《芋道 Spring Boot WebSocket 入门》.md b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/《芋道 Spring Boot WebSocket 入门》.md new file mode 100644 index 0000000..8df5a77 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-framework/yudao-spring-boot-starter-websocket/《芋道 Spring Boot WebSocket 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/pom.xml b/ruoyi-vue-pro-master/yudao-module-bpm/pom.xml new file mode 100644 index 0000000..95b7989 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/pom.xml @@ -0,0 +1,27 @@ + + + + yudao + cn.iocoder.boot + ${revision} + + 4.0.0 + + yudao-module-bpm-api + yudao-module-bpm-biz + + yudao-module-bpm + pom + + ${project.artifactId} + + bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能。 + 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 + bpm 解释:https://baike.baidu.com/item/BPM/1933 + + 工作流基于 Flowable 6 实现,分成流程定义、流程表单、流程实例、流程任务等功能模块。 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/pom.xml new file mode 100644 index 0000000..06554d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-bpm + ${revision} + + 4.0.0 + yudao-module-bpm-api + jar + + ${project.artifactId} + + bpm 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java new file mode 100644 index 0000000..37a9221 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * bpm API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.bpm.api; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java new file mode 100644 index 0000000..e94a2c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.api.task; + +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; + +import javax.validation.Valid; + +/** + * 流程实例 Api 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessInstanceApi { + + /** + * 创建流程实例(提供给内部) + * + * @param userId 用户编号 + * @param reqDTO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java new file mode 100644 index 0000000..1735c04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.api.task.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; +import java.util.Map; + +/** + * 流程实例的创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class BpmProcessInstanceCreateReqDTO { + + /** + * 流程定义的标识 + */ + @NotEmpty(message = "流程定义的标识不能为空") + private String processDefinitionKey; + /** + * 变量实例(动态表单) + */ + private Map variables; + + /** + * 业务的唯一标识 + * + * 例如说,请假申请的编号。通过它,可以查询到对应的实例 + */ + @NotEmpty(message = "业务的唯一标识") + private String businessKey; + + /** + * 发起人自选审批人 Map + * + * key:taskKey 任务编码 + * value:审批人的数组 + * 例如:{ taskKey1 :[1, 2] },则表示 taskKey1 这个任务,提前设定了,由 userId 为 1,2 的用户进行审批 + */ + private Map> startUserSelectAssignees; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java new file mode 100644 index 0000000..7abb3e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.bpm.enums; + +/** + * BPM 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型 + String TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..ec16771 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.bpm.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Bpm 错误码枚举类 + *

+ * bpm 系统,使用 1-009-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 通用流程处理 模块 1-009-000-000 ========== + + // ========== OA 流程模块 1-009-001-000 ========== + ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1_009_001_001, "请假申请不存在"); + + // ========== 流程模型 1-009-002-000 ========== + ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程"); + ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1_009_002_001, "流程模型不存在"); + ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"); + ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); + ErrorCode MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + + "原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置"); + ErrorCode MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS = new ErrorCode(1_009_002_005, "部署流程失败,原因:BPMN 流程图中,没有开始事件"); + ErrorCode MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS = new ErrorCode(1_009_002_006, "部署流程失败,原因:BPMN 流程图中,用户任务({})的名字不存在"); + + // ========== 流程定义 1-009-003-000 ========== + ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1_009_003_000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图"); + ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1_009_003_001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图"); + ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_009_003_002, "流程定义不存在"); + ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1_009_003_003, "流程定义处于挂起状态"); + + // ========== 流程实例 1-009-004-000 ========== + ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1_009_004_000, "流程实例不存在"); + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1_009_004_001, "流程取消失败,流程不处于运行中"); + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1_009_004_002, "流程取消失败,该流程不是你发起的"); + ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_003, "审批任务({})的审批人未配置"); + ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS = new ErrorCode(1_009_004_004, "审批任务({})的审批人({})不存在"); + + // ========== 流程任务 1-009-005-000 ========== + ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你"); + ErrorCode TASK_NOT_EXISTS = new ErrorCode(1_009_005_002, "流程任务不存在"); + ErrorCode TASK_IS_PENDING = new ErrorCode(1_009_005_003, "当前任务处于挂起状态,不能操作"); + ErrorCode TASK_TARGET_NODE_NOT_EXISTS = new ErrorCode(1_009_005_004, " 目标节点不存在"); + ErrorCode TASK_RETURN_FAIL_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_006, "回退任务失败,目标节点是在并行网关上或非同一路线上,不可跳转"); + ErrorCode TASK_DELEGATE_FAIL_USER_REPEAT = new ErrorCode(1_009_005_007, "任务委派失败,委派人和当前审批人为同一人"); + ErrorCode TASK_DELEGATE_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_008, "任务委派失败,被委派人不存在"); + ErrorCode TASK_SIGN_CREATE_USER_NOT_EXIST = new ErrorCode(1_009_005_009, "任务加签:选择的用户不存在"); + ErrorCode TASK_SIGN_CREATE_TYPE_ERROR = new ErrorCode(1_009_005_010, "任务加签:当前任务已经{},不能{}"); + ErrorCode TASK_SIGN_CREATE_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); + ErrorCode TASK_SIGN_DELETE_NO_PARENT = new ErrorCode(1_009_005_012, "任务减签失败,被减签的任务必须是通过加签生成的任务"); + ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); + ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); + ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); + + // ========== 动态表单模块 1-009-010-000 ========== + ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); + ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1_009_010_001, "表单项({}) 和 ({}) 使用了相同的字段名({})"); + + // ========== 用户组模块 1-009-011-000 ========== + ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1_009_011_000, "用户分组不存在"); + ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1_009_011_001, "名字为【{}】的用户分组已被禁用"); + + // ========== 用户组模块 1-009-012-000 ========== + ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在"); + ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); + ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); + + // ========== BPM 流程监听器 1-009-013-000 ========== + ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在"); + ErrorCode PROCESS_LISTENER_CLASS_NOT_FOUND = new ErrorCode(1_009_013_001, "流程监听器类({})不存在"); + ErrorCode PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR = new ErrorCode(1_009_013_002, "流程监听器类({})没有实现接口({})"); + ErrorCode PROCESS_LISTENER_EXPRESSION_INVALID = new ErrorCode(1_009_013_003, "流程监听器表达式({})不合法"); + + // ========== BPM 流程表达式 1-009-014-000 ========== + ErrorCode PROCESS_EXPRESSION_NOT_EXISTS = new ErrorCode(1_009_014_000, "流程表达式不存在"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java new file mode 100644 index 0000000..3bca6c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * BPM 模型的表单类型的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmModelFormTypeEnum implements IntArrayValuable { + + NORMAL(10, "流程表单"), // 对应 BpmFormDO + CUSTOM(20, "业务表单") // 业务自己定义的表单,自己进行数据的存储 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmModelFormTypeEnum::getType).toArray(); + + private final Integer type; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java new file mode 100644 index 0000000..3dde5df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 流程监听器的类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessListenerType { + + EXECUTION("execution", "执行监听器"), + TASK("task", "任务执行器"); + + private final String type; + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java new file mode 100644 index 0000000..63e23af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 流程监听器的值类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessListenerValueType { + + CLASS("class", "Java 类"), + DELEGATE_EXPRESSION("delegateExpression", "代理表达式"), + EXPRESSION("expression", "表达式"); + + private final String type; + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java new file mode 100644 index 0000000..79001fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.enums.message; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Bpm 消息的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum BpmMessageEnum { + + PROCESS_INSTANCE_APPROVE("bpm_process_instance_approve"), // 流程任务被审批通过时,发送给申请人 + PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时,发送给申请人 + TASK_ASSIGNED("bpm_task_assigned"); // 任务被分配时,发送给审批人 + + /** + * 短信模板的标识 + * + * 关联 SmsTemplateDO 的 code 属性 + */ + private final String smsTemplateCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java new file mode 100644 index 0000000..8b7b7ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程任务的 Comment 评论类型枚举 + * + * @author kehaiyou + */ +@Getter +@AllArgsConstructor +public enum BpmCommentTypeEnum { + + APPROVE("1", "审批通过", "审批通过,原因是:{}"), + REJECT("2", "不通过", "审批不通过:原因是:{}"), + CANCEL("3", "已取消", "系统自动取消,原因是:{}"), + RETURN("4", "退回", "任务被退回,原因是:{}"), + DELEGATE_START("5", "委派发起", "[{}]将任务委派给[{}],委派理由为:{}"), + DELEGATE_END("6", "委派完成", "[{}]完成委派任务,任务重新回到[{}]手中,审批建议为:{}"), + TRANSFER("7", "转派", "[{}]将任务转派给[{}],转派理由为:{}"), + ADD_SIGN("8", "加签", "[{}]{}给了[{}],理由为:{}"), + SUB_SIGN("9", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), + ; + + /** + * 操作类型 + * + * 由于 BPM Comment 类型为 String,所以这里就不使用 Integer + */ + private final String type; + /** + * 操作名字 + */ + private final String name; + /** + * 操作描述 + */ + private final String comment; + + public String formatComment(Object... params) { + return StrUtil.format(comment, params); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java new file mode 100644 index 0000000..802b9d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例/任务的删除原因枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmDeleteReasonEnum { + + // ========== 流程实例的独有原因 ========== + + REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法 + CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 + CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程 + + // ========== 流程任务的独有原因 ========== + + CANCEL_BY_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等 + ; + + private final String reason; + + /** + * 格式化理由 + * + * @param args 参数 + * @return 理由 + */ + public String format(Object... args) { + return StrUtil.format(reason, args); + } + + // ========== 逻辑 ========== + + public static boolean isRejectReason(String reason) { + return StrUtil.startWith(reason, "审批不通过任务,原因:"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java new file mode 100644 index 0000000..82a4119 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 流程实例 ProcessInstance 的状态 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessInstanceStatusEnum implements IntArrayValuable { + + RUNNING(1, "审批中"), + APPROVE(2, "审批通过"), + REJECT(3, "审批不通过"), + CANCEL(4, "已取消"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmProcessInstanceStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 描述 + */ + private final String desc; + + @Override + public int[] array() { + return new int[0]; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java new file mode 100644 index 0000000..b01153d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程任务的加签类型枚举 + * + * @author kehaiyou + */ +@Getter +@AllArgsConstructor +public enum BpmTaskSignTypeEnum { + + /** + * 向前加签,需要前置任务审批完成,才回到原审批人 + */ + BEFORE("before", "向前加签"), + /** + * 向后加签,需要后置任务全部审批完,才会通过原审批人节点 + */ + AFTER("after", "向后加签"); + + /** + * 类型 + */ + private final String type; + /** + * 名字 + */ + private final String name; + + public static String nameOfType(String type) { + for (BpmTaskSignTypeEnum value : values()) { + if (value.type.equals(type)) { + return value.name; + } + } + return null; + } + + public static BpmTaskSignTypeEnum of(String type) { + return ArrayUtil.firstMatch(value -> value.getType().equals(type), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java new file mode 100644 index 0000000..40a385a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程任务 Task 的状态枚举 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum BpmTaskStatusEnum { + + RUNNING(1, "审批中"), + APPROVE(2, "审批通过"), + REJECT(3, "审批不通过"), + CANCEL(4, "已取消"), + + RETURN(5, "已退回"), + DELEGATE(6, "委派中"), + + /** + * 使用场景: + * 1. 任务被向后【加签】时,它在审批通过后,会变成 APPROVING 这个状态,然后等到【加签】出来的任务都被审批后,才会变成 APPROVE 审批通过 + */ + APPROVING(7, "审批通过中"), + /** + * 使用场景: + * 1. 任务被向前【加签】时,它会变成 WAIT 状态,需要等待【加签】出来的任务被审批后,它才能继续变为 RUNNING 继续审批 + * 2. 任务被向后【加签】时,【加签】出来的任务处于 WAIT 状态,它们需要等待该任务被审批后,它们才能继续变为 RUNNING 继续审批 + */ + WAIT(0, "待审批"); + + /** + * 状态 + *

+ * 如果新增时,注意 {@link #isEndStatus(Integer)} 是否需要变更 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + /** + * 判断该状态是否已经处于 End 最终状态 + *

+ * 主要用于一些状态更新的逻辑,如果已经是最终状态,就不再进行更新 + * + * @param status 状态 + * @return 是否 + */ + public static boolean isEndStatus(Integer status) { + return ObjectUtils.equalsAny(status, + APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus(), + RETURN.getStatus(), APPROVING.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java new file mode 100644 index 0000000..474a865 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.event; + +import lombok.Data; +import org.springframework.context.ApplicationEvent; + +import javax.validation.constraints.NotNull; + +/** + * 流程实例的状态(结果)发生变化的 Event + * + * @author 芋道源码 + */ +@SuppressWarnings("ALL") +@Data +public class BpmProcessInstanceStatusEvent extends ApplicationEvent { + + /** + * 流程实例的编号 + */ + @NotNull(message = "流程实例的编号不能为空") + private String id; + /** + * 流程实例的 key + */ + @NotNull(message = "流程实例的 key 不能为空") + private String processDefinitionKey; + /** + * 流程实例的结果 + */ + @NotNull(message = "流程实例的状态不能为空") + private Integer status; + /** + * 流程实例对应的业务标识 + * 例如说,请假 + */ + private String businessKey; + + public BpmProcessInstanceStatusEvent(Object source) { + super(source); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java new file mode 100644 index 0000000..f8b1863 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.event; + +import cn.hutool.core.util.StrUtil; +import org.springframework.context.ApplicationListener; + +/** + * {@link BpmProcessInstanceStatusEvent} 的监听器 + * + * @author 芋道源码 + */ +public abstract class BpmProcessInstanceStatusEventListener + implements ApplicationListener { + + @Override + public final void onApplicationEvent(BpmProcessInstanceStatusEvent event) { + if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) { + return; + } + onEvent(event); + } + + /** + * @return 返回监听的流程定义 Key + */ + protected abstract String getProcessDefinitionKey(); + + /** + * 处理事件 + * + * @param event 事件 + */ + protected abstract void onEvent(BpmProcessInstanceStatusEvent event); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/pom.xml new file mode 100644 index 0000000..207b166 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/pom.xml @@ -0,0 +1,79 @@ + + + + cn.iocoder.boot + yudao-module-bpm + ${revision} + + 4.0.0 + yudao-module-bpm-biz + + ${project.artifactId} + + bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能,基于 Flowable 6 版本实现。 + 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 + + + + cn.iocoder.boot + yudao-module-bpm-api + ${revision} + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-data-permission + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + + org.flowable + flowable-spring-boot-starter-process + + + org.flowable + flowable-spring-boot-starter-actuator + + + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java new file mode 100644 index 0000000..2137e22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * bpm API 实现类,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.bpm.api; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java new file mode 100644 index 0000000..596c998 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.api.task; + +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * Flowable 流程实例 Api 实现类 + * + * @author 芋道源码 + * @author jason + */ +@Service +@Validated +public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi { + + @Resource + private BpmProcessInstanceService processInstanceService; + + @Override + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) { + return processInstanceService.createProcessInstance(userId, reqDTO); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java new file mode 100644 index 0000000..a787905 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - BPM 流程分类") +@RestController +@RequestMapping("/bpm/category") +@Validated +public class BpmCategoryController { + + @Resource + private BpmCategoryService categoryService; + + @PostMapping("/create") + @Operation(summary = "创建流程分类") + @PreAuthorize("@ss.hasPermission('bpm:category:create')") + public CommonResult createCategory(@Valid @RequestBody BpmCategorySaveReqVO createReqVO) { + return success(categoryService.createCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程分类") + @PreAuthorize("@ss.hasPermission('bpm:category:update')") + public CommonResult updateCategory(@Valid @RequestBody BpmCategorySaveReqVO updateReqVO) { + categoryService.updateCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:category:delete')") + public CommonResult deleteCategory(@RequestParam("id") Long id) { + categoryService.deleteCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:category:query')") + public CommonResult getCategory(@RequestParam("id") Long id) { + BpmCategoryDO category = categoryService.getCategory(id); + return success(BeanUtils.toBean(category, BpmCategoryRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程分类分页") + @PreAuthorize("@ss.hasPermission('bpm:category:query')") + public CommonResult> getCategoryPage(@Valid BpmCategoryPageReqVO pageReqVO) { + PageResult pageResult = categoryService.getCategoryPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmCategoryRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取流程分类的精简信息列表", description = "只包含被开启的分类,主要用于前端的下拉选项") + public CommonResult> getCategorySimpleList() { + List list = categoryService.getCategoryListByStatus(CommonStatusEnum.ENABLE.getStatus()); + list.sort(Comparator.comparingInt(BpmCategoryDO::getSort)); + return success(convertList(list, category -> new BpmCategoryRespVO().setId(category.getId()) + .setName(category.getName()).setCode(category.getCode()))); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java new file mode 100644 index 0000000..4ec3776 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 动态表单") +@RestController +@RequestMapping("/bpm/form") +@Validated +public class BpmFormController { + + @Resource + private BpmFormService formService; + + @PostMapping("/create") + @Operation(summary = "创建动态表单") + @PreAuthorize("@ss.hasPermission('bpm:form:create')") + public CommonResult createForm(@Valid @RequestBody BpmFormSaveReqVO createReqVO) { + return success(formService.createForm(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新动态表单") + @PreAuthorize("@ss.hasPermission('bpm:form:update')") + public CommonResult updateForm(@Valid @RequestBody BpmFormSaveReqVO updateReqVO) { + formService.updateForm(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除动态表单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:form:delete')") + public CommonResult deleteForm(@RequestParam("id") Long id) { + formService.deleteForm(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得动态表单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:form:query')") + public CommonResult getForm(@RequestParam("id") Long id) { + BpmFormDO form = formService.getForm(id); + return success(BeanUtils.toBean(form, BpmFormRespVO.class)); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获得动态表单的精简列表", description = "用于表单下拉框") + public CommonResult> getFormSimpleList() { + List list = formService.getFormList(); + return success(convertList(list, formDO -> // 只返回 id、name 字段 + new BpmFormRespVO().setId(formDO.getId()).setName(formDO.getName()))); + } + + @GetMapping("/page") + @Operation(summary = "获得动态表单分页") + @PreAuthorize("@ss.hasPermission('bpm:form:query')") + public CommonResult> getFormPage(@Valid BpmFormPageReqVO pageVO) { + PageResult pageResult = formService.getFormPage(pageVO); + return success(BeanUtils.toBean(pageResult, BpmFormRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java new file mode 100644 index 0000000..4095450 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.io.IoUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 流程模型") +@RestController +@RequestMapping("/bpm/model") +@Validated +public class BpmModelController { + + @Resource + private BpmModelService modelService; + @Resource + private BpmFormService formService; + @Resource + private BpmCategoryService categoryService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + + @GetMapping("/page") + @Operation(summary = "获得模型分页") + public CommonResult> getModelPage(BpmModelPageReqVO pageVO) { + PageResult pageResult = modelService.getModelPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + // 获得 Form 表单 + Set formIds = convertSet(pageResult.getList(), model -> { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + return metaInfo != null ? metaInfo.getFormId() : null; + }); + Map formMap = formService.getFormMap(formIds); + // 获得 Category Map + Map categoryMap = categoryService.getCategoryMap( + convertSet(pageResult.getList(), Model::getCategory)); + // 获得 Deployment Map + Set deploymentIds = new HashSet<>(); + pageResult.getList().forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId())); + Map deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds); + // 获得 ProcessDefinition Map + List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds); + Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); + return success(BpmModelConvert.INSTANCE.buildModelPage(pageResult, formMap, categoryMap, deploymentMap, processDefinitionMap)); + } + + @GetMapping("/get") + @Operation(summary = "获得模型") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:model:query')") + public CommonResult getModel(@RequestParam("id") String id) { + Model model = modelService.getModel(id); + if (model == null) { + return null; + } + byte[] bpmnBytes = modelService.getModelBpmnXML(id); + return success(BpmModelConvert.INSTANCE.buildModel(model, bpmnBytes)); + } + + @PostMapping("/create") + @Operation(summary = "新建模型") + @PreAuthorize("@ss.hasPermission('bpm:model:create')") + public CommonResult createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) { + return success(modelService.createModel(createRetVO, null)); + } + + @PutMapping("/update") + @Operation(summary = "修改模型") + @PreAuthorize("@ss.hasPermission('bpm:model:update')") + public CommonResult updateModel(@Valid @RequestBody BpmModelUpdateReqVO modelVO) { + modelService.updateModel(modelVO); + return success(true); + } + + @PostMapping("/import") + @Operation(summary = "导入模型") + @PreAuthorize("@ss.hasPermission('bpm:model:import')") + public CommonResult importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException { + BpmModelCreateReqVO createReqVO = BeanUtils.toBean(importReqVO, BpmModelCreateReqVO.class); + // 读取文件 + String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false); + return success(modelService.createModel(createReqVO, bpmnXml)); + } + + @PostMapping("/deploy") + @Operation(summary = "部署模型") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:model:deploy')") + public CommonResult deployModel(@RequestParam("id") String id) { + modelService.deployModel(id); + return success(true); + } + + @PutMapping("/update-state") + @Operation(summary = "修改模型的状态", description = "实际更新的部署的流程定义的状态") + @PreAuthorize("@ss.hasPermission('bpm:model:update')") + public CommonResult updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) { + modelService.updateModelState(reqVO.getId(), reqVO.getState()); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除模型") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:model:delete')") + public CommonResult deleteModel(@RequestParam("id") String id) { + modelService.deleteModel(id); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java new file mode 100644 index 0000000..ee23c63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 流程定义") +@RestController +@RequestMapping("/bpm/process-definition") +@Validated +public class BpmProcessDefinitionController { + + @Resource + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmFormService formService; + @Resource + private BpmCategoryService categoryService; + + @GetMapping("/page") + @Operation(summary = "获得流程定义分页") + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult> getProcessDefinitionPage( + BpmProcessDefinitionPageReqVO pageReqVO) { + PageResult pageResult = processDefinitionService.getProcessDefinitionPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 获得 Category Map + Map categoryMap = categoryService.getCategoryMap( + convertSet(pageResult.getList(), ProcessDefinition::getCategory)); + // 获得 Deployment Map + Map deploymentMap = processDefinitionService.getDeploymentMap( + convertSet(pageResult.getList(), ProcessDefinition::getDeploymentId)); + // 获得 BpmProcessDefinitionInfoDO Map + Map processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap( + convertSet(pageResult.getList(), ProcessDefinition::getId)); + // 获得 Form Map + Map formMap = formService.getFormMap( + convertSet(processDefinitionMap.values(), BpmProcessDefinitionInfoDO::getFormId)); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionPage( + pageResult, deploymentMap, processDefinitionMap, formMap, categoryMap)); + } + + @GetMapping ("/list") + @Operation(summary = "获得流程定义列表") + @Parameter(name = "suspensionState", description = "挂起状态", required = true, example = "1") // 参见 Flowable SuspensionState 枚举 + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult> getProcessDefinitionList( + @RequestParam("suspensionState") Integer suspensionState) { + List list = processDefinitionService.getProcessDefinitionListBySuspensionState(suspensionState); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + // 获得 BpmProcessDefinitionInfoDO Map + Map processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap( + convertSet(list, ProcessDefinition::getId)); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList( + list, null, processDefinitionMap, null, null)); + } + + @GetMapping ("/get") + @Operation(summary = "获得流程定义") + @Parameter(name = "id", description = "流程编号", required = true, example = "1024") + @Parameter(name = "key", description = "流程定义标识", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult getProcessDefinition( + @RequestParam(value = "id", required = false) String id, + @RequestParam(value = "key", required = false) String key) { + ProcessDefinition processDefinition = id != null ? processDefinitionService.getProcessDefinition(id) + : processDefinitionService.getActiveProcessDefinition(key); + if (processDefinition == null) { + return success(null); + } + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); + List userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition( + processDefinition, null, null, null, null, bpmnModel, userTaskList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java new file mode 100644 index 0000000..a6e11a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessExpressionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - BPM 流程表达式") +@RestController +@RequestMapping("/bpm/process-expression") +@Validated +public class BpmProcessExpressionController { + + @Resource + private BpmProcessExpressionService processExpressionService; + + @PostMapping("/create") + @Operation(summary = "创建流程表达式") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:create')") + public CommonResult createProcessExpression(@Valid @RequestBody BpmProcessExpressionSaveReqVO createReqVO) { + return success(processExpressionService.createProcessExpression(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程表达式") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:update')") + public CommonResult updateProcessExpression(@Valid @RequestBody BpmProcessExpressionSaveReqVO updateReqVO) { + processExpressionService.updateProcessExpression(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程表达式") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-expression:delete')") + public CommonResult deleteProcessExpression(@RequestParam("id") Long id) { + processExpressionService.deleteProcessExpression(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程表达式") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:query')") + public CommonResult getProcessExpression(@RequestParam("id") Long id) { + BpmProcessExpressionDO processExpression = processExpressionService.getProcessExpression(id); + return success(BeanUtils.toBean(processExpression, BpmProcessExpressionRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程表达式分页") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:query')") + public CommonResult> getProcessExpressionPage( + @Valid BpmProcessExpressionPageReqVO pageReqVO) { + PageResult pageResult = processExpressionService.getProcessExpressionPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmProcessExpressionRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java new file mode 100644 index 0000000..c6cc391 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessListenerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - BPM 流程监听器") +@RestController +@RequestMapping("/bpm/process-listener") +@Validated +public class BpmProcessListenerController { + + @Resource + private BpmProcessListenerService processListenerService; + + @PostMapping("/create") + @Operation(summary = "创建流程监听器") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:create')") + public CommonResult createProcessListener(@Valid @RequestBody BpmProcessListenerSaveReqVO createReqVO) { + return success(processListenerService.createProcessListener(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程监听器") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:update')") + public CommonResult updateProcessListener(@Valid @RequestBody BpmProcessListenerSaveReqVO updateReqVO) { + processListenerService.updateProcessListener(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程监听器") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-listener:delete')") + public CommonResult deleteProcessListener(@RequestParam("id") Long id) { + processListenerService.deleteProcessListener(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程监听器") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:query')") + public CommonResult getProcessListener(@RequestParam("id") Long id) { + BpmProcessListenerDO processListener = processListenerService.getProcessListener(id); + return success(BeanUtils.toBean(processListener, BpmProcessListenerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程监听器分页") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:query')") + public CommonResult> getProcessListenerPage( + @Valid BpmProcessListenerPageReqVO pageReqVO) { + PageResult pageResult = processListenerService.getProcessListenerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmProcessListenerRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java new file mode 100644 index 0000000..fca7d5b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 用户组") +@RestController +@RequestMapping("/bpm/user-group") +@Validated +public class BpmUserGroupController { + + @Resource + private BpmUserGroupService userGroupService; + + @PostMapping("/create") + @Operation(summary = "创建用户组") + @PreAuthorize("@ss.hasPermission('bpm:user-group:create')") + public CommonResult createUserGroup(@Valid @RequestBody BpmUserGroupSaveReqVO createReqVO) { + return success(userGroupService.createUserGroup(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新用户组") + @PreAuthorize("@ss.hasPermission('bpm:user-group:update')") + public CommonResult updateUserGroup(@Valid @RequestBody BpmUserGroupSaveReqVO updateReqVO) { + userGroupService.updateUserGroup(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户组") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:user-group:delete')") + public CommonResult deleteUserGroup(@RequestParam("id") Long id) { + userGroupService.deleteUserGroup(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得用户组") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") + public CommonResult getUserGroup(@RequestParam("id") Long id) { + BpmUserGroupDO userGroup = userGroupService.getUserGroup(id); + return success(BeanUtils.toBean(userGroup, BpmUserGroupRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得用户组分页") + @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") + public CommonResult> getUserGroupPage(@Valid BpmUserGroupPageReqVO pageVO) { + PageResult pageResult = userGroupService.getUserGroupPage(pageVO); + return success(BeanUtils.toBean(pageResult, BpmUserGroupRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取用户组精简信息列表", description = "只包含被开启的用户组,主要用于前端的下拉选项") + public CommonResult> getUserGroupSimpleList() { + List list = userGroupService.getUserGroupListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, group -> new BpmUserGroupRespVO().setId(group.getId()).setName(group.getName()))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java new file mode 100644 index 0000000..b76e96c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM 流程分类分页 Request VO") +@Data +public class BpmCategoryPageReqVO extends PageParam { + + @Schema(description = "分类名", example = "王五") + private String name; + + @Schema(description = "分类标志", example = "OA") + private String code; + + @Schema(description = "分类状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java new file mode 100644 index 0000000..7ada55a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程分类 Response VO") +@Data +public class BpmCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + private Long id; + + @Schema(description = "分类名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "分类标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "OA") + private String code; + + @Schema(description = "分类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String description; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer sort; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java new file mode 100644 index 0000000..d4865e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - BPM 流程分类新增/修改 Request VO") +@Data +public class BpmCategorySaveReqVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + private Long id; + + @Schema(description = "分类名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "分类名不能为空") + private String name; + + @Schema(description = "分类描述", example = "你猜") + private String description; + + @Schema(description = "分类标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "OA") + @NotEmpty(message = "分类标志不能为空") + private String code; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "分类状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "分类排序不能为空") + private Integer sort; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java new file mode 100644 index 0000000..37b02f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM 流程表达式分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessExpressionPageReqVO extends PageParam { + + @Schema(description = "表达式名字", example = "李四") + private String name; + + @Schema(description = "表达式状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java new file mode 100644 index 0000000..d877f60 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程表达式 Response VO") +@Data +public class BpmProcessExpressionRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3870") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "表达式名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("表达式名字") + private String name; + + @Schema(description = "表达式状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "表达式", requiredMode = Schema.RequiredMode.REQUIRED) + private String expression; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java new file mode 100644 index 0000000..2755bf8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - BPM 流程表达式新增/修改 Request VO") +@Data +public class BpmProcessExpressionSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3870") + private Long id; + + @Schema(description = "表达式名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "表达式名字不能为空") + private String name; + + @Schema(description = "表达式状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表达式状态不能为空") + private Integer status; + + @Schema(description = "表达式", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "表达式不能为空") + private String expression; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java new file mode 100644 index 0000000..1657f02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 动态表单分页 Request VO") +@Data +public class BpmFormPageReqVO extends PageParam { + + @Schema(description = "表单名称", example = "芋道") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java new file mode 100644 index 0000000..832d4d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 动态表单 Response VO") +@Data +public class BpmFormRespVO { + + @Schema(description = "表单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表单名称不能为空") + private String name; + + @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单的配置不能为空") + private String conf; + + @Schema(description = "表单项的数组-JSON 字符串的数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单项的数组不能为空") + private List fields; + + @Schema(description = "表单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表单状态不能为空") + private Integer status; // 参见 CommonStatusEnum 枚举 + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java new file mode 100644 index 0000000..c890859 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 动态表单创建/更新 Request VO") +@Data +public class BpmFormSaveReqVO { + + @Schema(description = "表单编号", example = "1024") + private Long id; + + @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表单名称不能为空") + private String name; + + @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单的配置不能为空") + private String conf; + + @Schema(description = "表单项的数组-JSON 字符串的数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单项的数组不能为空") + private List fields; + + @Schema(description = "表单状态-参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表单状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java new file mode 100644 index 0000000..234ff28 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 用户组分页 Request VO") +@Data +public class BpmUserGroupPageReqVO extends PageParam { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "组名", example = "芋道") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java new file mode 100644 index 0000000..f20722a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 用户组 Response VO") +@Data +public class BpmUserGroupRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "组名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String description; + + @Schema(description = "成员编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + private Set userIds; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java new file mode 100644 index 0000000..470eb0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 用户组创建/修改 Request VO") +@Data +public class BpmUserGroupSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "组名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "组名不能为空") + private String name; + + @Schema(description = "描述", example = "芋道源码") + private String description; + + @Schema(description = "成员编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + @NotNull(message = "成员编号数组不能为空") + private Set userIds; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java new file mode 100644 index 0000000..d3b9746 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - BPM 流程监听器分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessListenerPageReqVO extends PageParam { + + @Schema(description = "监听器名字", example = "赵六") + private String name; + + @Schema(description = "监听器类型", example = "execution") + private String type; + + @Schema(description = "监听事件", example = "start") + private String event; + + @Schema(description = "状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java new file mode 100644 index 0000000..f7a4842 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程监听器 Response VO") +@Data +public class BpmProcessListenerRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13089") + private Long id; + + @Schema(description = "监听器名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "监听器类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "execution") + private String type; + + @Schema(description = "监听器状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "监听事件", requiredMode = Schema.RequiredMode.REQUIRED, example = "start") + private String event; + + @Schema(description = "监听器值类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "class") + private String valueType; + + @Schema(description = "监听器值", requiredMode = Schema.RequiredMode.REQUIRED) + private String value; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java new file mode 100644 index 0000000..ef022b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - BPM 流程监听器新增/修改 Request VO") +@Data +public class BpmProcessListenerSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13089") + private Long id; + + @Schema(description = "监听器名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "监听器名字不能为空") + private String name; + + @Schema(description = "监听器类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "execution") + @NotEmpty(message = "监听器类型不能为空") + private String type; + + @Schema(description = "监听器状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "监听器状态不能为空") + private Integer status; + + @Schema(description = "监听事件", requiredMode = Schema.RequiredMode.REQUIRED, example = "start") + @NotEmpty(message = "监听事件不能为空") + private String event; + + @Schema(description = "监听器值类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "class") + @NotEmpty(message = "监听器值类型不能为空") + private String valueType; + + @Schema(description = "监听器值", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "监听器值不能为空") + private String value; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java new file mode 100644 index 0000000..0b549ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 流程模型的导入 Request VO 相比流程模型的新建来说,只是多了一个 bpmnFile 文件") +@Data +public class BpmModeImportReqVO extends BpmModelCreateReqVO { + + @Schema(description = "BPMN 文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "BPMN 文件不能为空") + private MultipartFile bpmnFile; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java new file mode 100644 index 0000000..39e4844 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 流程模型的创建 Request VO") +@Data +public class BpmModelCreateReqVO { + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_yudao") + @NotEmpty(message = "流程标识不能为空") + private String key; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotEmpty(message = "流程名称不能为空") + private String name; + + @Schema(description = "流程描述", example = "我是描述") + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java new file mode 100644 index 0000000..ec14b1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@Schema(description = "管理后台 - 流程模型分页 Request VO") +@Data +public class BpmModelPageReqVO extends PageParam { + + @Schema(description = "标识,精准匹配", example = "process1641042089407") + private String key; + + @Schema(description = "名字,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "流程分类", example = "1") + private String category; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java new file mode 100644 index 0000000..aad2015 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程模型 Response VO") +@Data +public class BpmModelRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_yudao") + private String key; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + + @Schema(description = "流程描述", example = "我是描述") + private String description; + + @Schema(description = "流程分类编码", example = "1") + private String category; + @Schema(description = "流程分类名字", example = "请假") + private String categoryName; + + @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + + @Schema(description = "表单编号", example = "1024") + private Long formId; // 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 + @Schema(description = "表单名字", example = "请假表单") + private String formName; + + @Schema(description = "自定义表单的提交路径", example = "/bpm/oa/leave/create") + private String formCustomCreatePath; // 使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 + @Schema(description = "自定义表单的查看路径", example = "/bpm/oa/leave/view") + private String formCustomViewPath; // ,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) + private String bpmnXml; + + /** + * 最新部署的流程定义 + */ + private BpmProcessDefinitionRespVO processDefinition; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java new file mode 100644 index 0000000..231ead1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 流程模型的更新 Request VO") +@Data +public class BpmModelUpdateReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "编号不能为空") + private String id; + + @Schema(description = "流程名称", example = "芋道") + private String name; + + @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") + @URL(message = "流程图标格式不正确") + private String icon; + + @Schema(description = "流程描述", example = "我是描述") + private String description; + + @Schema(description = "流程分类", example = "1") + private String category; + + @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) + private String bpmnXml; + + @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") + @InEnum(BpmModelFormTypeEnum.class) + private Integer formType; + @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") + private Long formId; + @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/create") + private String formCustomCreatePath; + @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/view") + private String formCustomViewPath; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java new file mode 100644 index 0000000..6ef20c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 流程模型更新状态 Request VO") +@Data +public class BpmModelUpdateStateReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private String id; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer state; // 参见 Flowable SuspensionState 枚举 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java new file mode 100644 index 0000000..828654f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 流程定义分页 Request VO") +@Data +public class BpmProcessDefinitionPageReqVO extends PageParam { + + @Schema(description = "标识-精准匹配", example = "process1641042089407") + private String key; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java new file mode 100644 index 0000000..2fb8dd4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 流程定义 Response VO") +@Data +public class BpmProcessDefinitionRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer version; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String key; + + @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + + @Schema(description = "流程描述", example = "我是描述") + private String description; + + @Schema(description = "流程分类", example = "1") + private String category; + @Schema(description = "流程分类名字", example = "请假") + private String categoryName; + + @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") + private Long formId; + @Schema(description = "表单名字", example = "请假表单") + private String formName; + @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) + private String formConf; + @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) + private List formFields; + @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/create") + private String formCustomCreatePath; + @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/view") + private String formCustomViewPath; + + @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer suspensionState; // 参见 SuspensionState 枚举 + + @Schema(description = "部署时间") + private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取,非必须返回 + + @Schema(description = "BPMN XML") + private String bpmnXml; // 需要从对应的 BpmnModel 读取,非必须返回 + + @Schema(description = "发起用户需要选择审批人的任务数组") + private List startUserSelectTasks; // 需要从对应的 BpmnModel 读取,非必须返回 + + @Schema(description = "BPMN UserTask 用户任务") + @Data + public static class UserTask { + + @Schema(description = "任务标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "sudo") + private String id; + + @Schema(description = "任务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http new file mode 100644 index 0000000..96bbf96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http @@ -0,0 +1,12 @@ +### 请求 /bpm/oa/leave/create 接口 => 成功 +POST {{baseUrl}}/bpm/oa/leave/create +Content-Type: application/json +tenant-id: 1 +Authorization: Bearer {{token}} + +{ + "startTime": "2022-03-01", + "endTime": "2022-03-05", + "type": 1, + "reason": "我要请假啦啦啦!" +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java new file mode 100644 index 0000000..47a7280 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * OA 请假申请 Controller,用于演示自己存储数据,接入工作流的例子 + * + * @author jason + * @author 芋道源码 + */ +@Tag(name = "管理后台 - OA 请假申请") +@RestController +@RequestMapping("/bpm/oa/leave") +@Validated +public class BpmOALeaveController { + + @Resource + private BpmOALeaveService leaveService; + + @PostMapping("/create") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:create')") + @Operation(summary = "创建请求申请") + public CommonResult createLeave(@Valid @RequestBody BpmOALeaveCreateReqVO createReqVO) { + return success(leaveService.createLeave(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')") + @Operation(summary = "获得请假申请") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getLeave(@RequestParam("id") Long id) { + BpmOALeaveDO leave = leaveService.getLeave(id); + return success(BeanUtils.toBean(leave, BpmOALeaveRespVO.class)); + } + + @GetMapping("/page") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')") + @Operation(summary = "获得请假申请分页") + public CommonResult> getLeavePage(@Valid BpmOALeavePageReqVO pageVO) { + PageResult pageResult = leaveService.getLeavePage(getLoginUserId(), pageVO); + return success(BeanUtils.toBean(pageResult, BpmOALeaveRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java new file mode 100644 index 0000000..7028708 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java @@ -0,0 +1,5 @@ +/** + * OA 示例,用于演示外部业务接入 BPM 工作流的示例 + * 一般的接入方式,只需要调用 接口,后续 Admin 用户在管理后台的【待办事务】进行审批 + */ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java new file mode 100644 index 0000000..f843059 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 请假申请创建 Request VO") +@Data +public class BpmOALeaveCreateReqVO { + + @Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "请假类型-参见 bpm_oa_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") + private String reason; + + @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") + private Map> startUserSelectAssignees; + + @AssertTrue(message = "结束时间,需要在开始时间之后") + public boolean isEndTimeValid() { + return !getEndTime().isBefore(getStartTime()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java new file mode 100644 index 0000000..3777564 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 请假申请分页 Request VO") +@Data +public class BpmOALeavePageReqVO extends PageParam { + + @Schema(description = "状态", example = "1") + private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 + + @Schema(description = "请假类型,参见 bpm_oa_type", example = "1") + private Integer type; + + @Schema(description = "原因,模糊匹配", example = "阅读芋道源码") + private String reason; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "申请时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java new file mode 100644 index 0000000..dbfe9d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 请假申请 Response VO") +@Data +public class BpmOALeaveRespVO { + + @Schema(description = "请假表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "请假类型,参见 bpm_oa_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") + private String reason; + + @Schema(description = "申请时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "流程编号") + private String processInstanceId; + + @Schema(description = "审批结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java new file mode 100644 index 0000000..44d0373 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 流程活动实例") +@RestController +@RequestMapping("/bpm/activity") +@Validated +public class BpmActivityController { + + @Resource + private BpmActivityService activityService; + + @GetMapping("/list") + @Operation(summary = "生成指定流程实例的高亮流程图", + description = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成") + @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getActivityList( + @RequestParam("processInstanceId") String processInstanceId) { + return success(activityService.getActivityListByProcessInstanceId(processInstanceId)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java new file mode 100644 index 0000000..52198fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.task.api.Task; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” +@RestController +@RequestMapping("/bpm/process-instance") +@Validated +public class BpmProcessInstanceController { + + @Resource + private BpmProcessInstanceService processInstanceService; + @Resource + private BpmTaskService taskService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmCategoryService categoryService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @GetMapping("/my-page") + @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult> getProcessInstanceMyPage( + @Valid BpmProcessInstancePageReqVO pageReqVO) { + PageResult pageResult = processInstanceService.getProcessInstancePage( + getLoginUserId(), pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + Map> taskMap = taskService.getTaskMapByProcessInstanceIds( + convertList(pageResult.getList(), HistoricProcessInstance::getId)); + Map processDefinitionMap = processDefinitionService.getProcessDefinitionMap( + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); + Map categoryMap = categoryService.getCategoryMap( + convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, + processDefinitionMap, categoryMap, taskMap, null, null)); + } + + @GetMapping("/manager-page") + @Operation(summary = "获得管理流程实例的分页列表", description = "在【流程实例】菜单中,进行调用") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:manager-query')") + public CommonResult> getProcessInstanceManagerPage( + @Valid BpmProcessInstancePageReqVO pageReqVO) { + PageResult pageResult = processInstanceService.getProcessInstancePage( + null, pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + Map> taskMap = taskService.getTaskMapByProcessInstanceIds( + convertList(pageResult.getList(), HistoricProcessInstance::getId)); + Map processDefinitionMap = processDefinitionService.getProcessDefinitionMap( + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); + Map categoryMap = categoryService.getCategoryMap( + convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); + // 发起人信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId()))); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, + processDefinitionMap, categoryMap, taskMap, userMap, deptMap)); + } + + @PostMapping("/create") + @Operation(summary = "新建流程实例") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { + return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @Operation(summary = "获得指定流程实例", description = "在【流程详细】界面中,进行调用") + @Parameter(name = "id", description = "流程实例的编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult getProcessInstance(@RequestParam("id") String id) { + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(id); + if (processInstance == null) { + return success(null); + } + + // 拼接返回 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + processInstance.getProcessDefinitionId()); + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( + processInstance.getProcessDefinitionId()); + String bpmnXml = BpmnModelUtils.getBpmnXml( + processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId())); + AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); + DeptRespDTO dept = null; + if (startUser != null) { + dept = deptApi.getDept(startUser.getDeptId()); + } + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstance(processInstance, + processDefinition, processDefinitionInfo, bpmnXml, startUser, dept)); + } + + @DeleteMapping("/cancel-by-start-user") + @Operation(summary = "用户取消流程实例", description = "取消发起的流程") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") + public CommonResult cancelProcessInstanceByStartUser( + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { + processInstanceService.cancelProcessInstanceByStartUser(getLoginUserId(), cancelReqVO); + return success(true); + } + + @DeleteMapping("/cancel-by-admin") + @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel-by-admin')") + public CommonResult cancelProcessInstanceByManager( + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { + processInstanceService.cancelProcessInstanceByAdmin(getLoginUserId(), cancelReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java new file mode 100644 index 0000000..cfd2f96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.flowable.engine.history.HistoricProcessInstance; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 流程实例抄送") +@RestController +@RequestMapping("/bpm/process-instance/copy") +@Validated +public class BpmProcessInstanceCopyController { + + @Resource + private BpmProcessInstanceCopyService processInstanceCopyService; + @Resource + private BpmProcessInstanceService processInstanceService; + @Resource + private BpmTaskService taskService; + + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/page") + @Operation(summary = "获得抄送流程分页列表") + @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')") + public CommonResult> getProcessInstanceCopyPage( + @Valid BpmProcessInstanceCopyPageReqVO pageReqVO) { + PageResult pageResult = processInstanceCopyService.getProcessInstanceCopyPage( + getLoginUserId(), pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + + // 拼接返回 + Map taskNameMap = taskService.getTaskNameByTaskIds( + convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getTaskId)); + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId)); + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), + copy -> Stream.of(copy.getStartUserId(), Long.parseLong(copy.getCreator())))); + return success(BeanUtils.toBean(pageResult, BpmProcessInstanceCopyRespVO.class, copyVO -> { + MapUtils.findAndThen(userMap, Long.valueOf(copyVO.getCreator()), user -> copyVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, copyVO.getStartUserId(), user -> copyVO.setStartUserName(user.getNickname())); + MapUtils.findAndThen(taskNameMap, copyVO.getTaskId(), copyVO::setTaskName); + MapUtils.findAndThen(processInstanceMap, copyVO.getProcessInstanceId(), + processInstance -> copyVO.setProcessInstanceStartTime(DateUtils.of(processInstance.getStartTime()))); + })); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java new file mode 100644 index 0000000..d299fd6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -0,0 +1,224 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 流程任务实例") +@RestController +@RequestMapping("/bpm/task") +@Validated +public class BpmTaskController { + + @Resource + private BpmTaskService taskService; + @Resource + private BpmProcessInstanceService processInstanceService; + @Resource + private BpmFormService formService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @GetMapping("todo-page") + @Operation(summary = "获取 Todo 待办任务分页") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskTodoPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskTodoPage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 拼接数据 + Map processInstanceMap = processInstanceService.getProcessInstanceMap( + convertSet(pageResult.getList(), Task::getProcessInstanceId)); + Map userMap = adminUserApi.getUserMap( + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + return success(BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap)); + } + + @GetMapping("done-page") + @Operation(summary = "获取 Done 已办任务分页") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskDonePage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskDonePage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 拼接数据 + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); + Map userMap = adminUserApi.getUserMap( + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null)); + } + + @GetMapping("manager-page") + @Operation(summary = "获取全部任务的分页", description = "用于【流程任务】菜单") + @PreAuthorize("@ss.hasPermission('bpm:task:mananger-query')") + public CommonResult> getTaskManagerPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskPage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 拼接数据 + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); + // 获得 User 和 Dept Map + Set userIds = convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())); + userIds.addAll(convertSet(pageResult.getList(), task -> NumberUtils.parseLong(task.getAssignee()))); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap)); + } + + @GetMapping("/list-by-process-instance-id") + @Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的") + @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskListByProcessInstanceId( + @RequestParam("processInstanceId") String processInstanceId) { + List taskList = taskService.getTaskListByProcessInstanceId(processInstanceId); + if (CollUtil.isEmpty(taskList)) { + return success(Collections.emptyList()); + } + + // 拼接数据 + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); + // 获得 User 和 Dept Map + Set userIds = convertSetByFlatMap(taskList, task -> + Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); + userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 获得 Form Map + Map formMap = formService.getFormMap( + convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); + return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, + formMap, userMap, deptMap)); + } + + @PutMapping("/approve") + @Operation(summary = "通过任务") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) { + taskService.approveTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/reject") + @Operation(summary = "不通过任务") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) { + taskService.rejectTask(getLoginUserId(), reqVO); + return success(true); + } + + @GetMapping("/list-by-return") + @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") + @Parameter(name = "taskId", description = "当前任务ID", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult> getTaskListByReturn(@RequestParam("id") String id) { + List userTaskList = taskService.getUserTaskListByReturn(id); + return success(convertList(userTaskList, userTask -> // 只返回 id 和 name + new BpmTaskRespVO().setName(userTask.getName()).setTaskDefinitionKey(userTask.getId()))); + } + + @PutMapping("/return") + @Operation(summary = "回退任务", description = "用于【流程详情】的【回退】按钮") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult returnTask(@Valid @RequestBody BpmTaskReturnReqVO reqVO) { + taskService.returnTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/delegate") + @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult delegateTask(@Valid @RequestBody BpmTaskDelegateReqVO reqVO) { + taskService.delegateTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/transfer") + @Operation(summary = "转派任务", description = "用于【流程详情】的【转派】按钮") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult transferTask(@Valid @RequestBody BpmTaskTransferReqVO reqVO) { + taskService.transferTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/create-sign") + @Operation(summary = "加签", description = "before 前加签,after 后加签") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult createSignTask(@Valid @RequestBody BpmTaskSignCreateReqVO reqVO) { + taskService.createSignTask(getLoginUserId(), reqVO); + return success(true); + } + + @DeleteMapping("/delete-sign") + @Operation(summary = "减签") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult deleteSignTask(@Valid @RequestBody BpmTaskSignDeleteReqVO reqVO) { + taskService.deleteSignTask(getLoginUserId(), reqVO); + return success(true); + } + + @GetMapping("/list-by-parent-task-id") + @Operation(summary = "获得指定父级任务的子任务列表") // 目前用于,减签的时候,获得子任务列表 + @Parameter(name = "parentTaskId", description = "父级任务编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskListByParentTaskId(@RequestParam("parentTaskId") String parentTaskId) { + List taskList = taskService.getTaskListByParentTaskId(parentTaskId); + if (CollUtil.isEmpty(taskList)) { + return success(Collections.emptyList()); + } + // 拼接数据 + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(taskList, + user -> Stream.of(NumberUtils.parseLong(user.getAssignee()), NumberUtils.parseLong(user.getOwner())))); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmTaskConvert.INSTANCE.buildTaskListByParentTaskId(taskList, userMap, deptMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java new file mode 100644 index 0000000..8f959e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程活动的 Response VO") +@Data +public class BpmActivityRespVO { + + @Schema(description = "流程活动的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String key; + @Schema(description = "流程活动的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartEvent") + private String type; + + @Schema(description = "流程活动的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + @Schema(description = "流程活动的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "关联的流程任务的编号", example = "2048") + private String taskId; // 关联的流程任务,只有 UserTask 等类型才有 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java new file mode 100644 index 0000000..4b397fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO") +@Data +public class BpmProcessInstanceCopyRespVO { + + @Schema(description = "抄送主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "发起人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long startUserId; + @Schema(description = "发起人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String startUserName; + + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "A233") + private String processInstanceId; + @Schema(description = "流程实例的名称") + private String processInstanceName; + @Schema(description = "流程实例的发起时间") + private LocalDateTime processInstanceStartTime; + + @Schema(description = "发起抄送的任务编号") + private String taskId; + @Schema(description = "发起抄送的任务名称") + private String taskName; + + @Schema(description = "抄送人") + private String creator; + @Schema(description = "抄送人昵称") + private String creatorName; + + @Schema(description = "抄送时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java new file mode 100644 index 0000000..496c72c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 流程实例的取消 Request VO") +@Data +public class BpmProcessInstanceCancelReqVO { + + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "流程实例的编号不能为空") + private String id; + + @Schema(description = "取消原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不请假了!") + @NotEmpty(message = "取消原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java new file mode 100644 index 0000000..b702afd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 流程实例抄送的分页 Request VO") +@Data +public class BpmProcessInstanceCopyPageReqVO extends PageParam { + + @Schema(description = "流程名称", example = "芋道") + private String processInstanceName; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java new file mode 100644 index 0000000..207daee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 流程实例的创建 Request VO") +@Data +public class BpmProcessInstanceCreateReqVO { + + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "流程定义编号不能为空") + private String processDefinitionId; + + @Schema(description = "变量实例(动态表单)") + private Map variables; + + @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") + private Map> startUserSelectAssignees; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java new file mode 100644 index 0000000..bc658eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 流程实例分页 Request VO") +@Data +public class BpmProcessInstancePageReqVO extends PageParam { + + @Schema(description = "流程名称", example = "芋道") + private String name; + + @Schema(description = "流程定义的编号", example = "2048") + private String processDefinitionId; + + @Schema(description = "流程实例的状态", example = "1") + @InEnum(BpmProcessInstanceStatusEnum.class) + private Integer status; + + @Schema(description = "流程分类", example = "1") + private String category; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "发起用户编号", example = "1024") + private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java new file mode 100644 index 0000000..ac6b90c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 流程实例的 Response VO") +@Data +public class BpmProcessInstanceRespVO { + + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String category; + @Schema(description = "流程分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假") + private String categoryName; + + @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 + + @Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "持续时间", example = "1000") + private Long durationInMillis; + + @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) + private Map formVariables; + + @Schema(description = "业务的唯一标识-例如说,请假申请的编号", example = "1") + private String businessKey; + + /** + * 发起流程的用户 + */ + private User startUser; + + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String processDefinitionId; + /** + * 流程定义 + */ + private BpmProcessDefinitionRespVO processDefinition; + + /** + * 当前审批中的任务 + */ + private List tasks; // 仅在流程实例分页才返回 + + @Schema(description = "用户信息") + @Data + public static class User { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long deptId; + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String deptName; + + } + + @Schema(description = "流程任务") + @Data + public static class Task { + + @Schema(description = "流程任务的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java new file mode 100644 index 0000000..5d35a0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Collection; +import java.util.Map; + +@Schema(description = "管理后台 - 通过流程任务的 Request VO") +@Data +public class BpmTaskApproveReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "审批意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "不错不错!") + @NotEmpty(message = "审批意见不能为空") + private String reason; + + @Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2") + private Collection copyUserIds; + + @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) + private Map variables; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java new file mode 100644 index 0000000..96c42de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 委派流程任务的 Request VO") +@Data +public class BpmTaskDelegateReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "被委派人 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "被委派人 ID 不能为空") + private Long delegateUserId; + + @Schema(description = "委派原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "做不了决定,需要你先帮忙瞅瞅") + @NotEmpty(message = "委派原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java new file mode 100644 index 0000000..d90eb63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程任务的的分页 Request VO") // 待办、已办,都使用该分页 +@Data +public class BpmTaskPageReqVO extends PageParam { + + @Schema(description = "流程任务名", example = "芋道") + private String name; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java new file mode 100644 index 0000000..ebbc0fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 不通过流程任务的 Request VO") +@Data +public class BpmTaskRejectReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "审批意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "不错不错!") + @NotEmpty(message = "审批意见不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java new file mode 100644 index 0000000..7f5177b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 流程任务 Response VO") +@Data +public class BpmTaskRespVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "任务名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "持续时间", example = "1000") + private Long durationInMillis; + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer status; // 参见 BpmTaskStatusEnum 枚举 + + @Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String reason; + + /** + * 负责人的用户信息 + */ + private BpmProcessInstanceRespVO.User ownerUser; + /** + * 审核的用户信息 + */ + private BpmProcessInstanceRespVO.User assigneeUser; + + @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one") + private String taskDefinitionKey; + + @Schema(description = "所属流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8888") + private String processInstanceId; + /** + * 所属流程实例 + */ + private ProcessInstance processInstance; + + @Schema(description = "父任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String parentTaskId; + @Schema(description = "子任务列表(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask") + private List children; + + @Schema(description = "表单编号", example = "1024") + private Long formId; + @Schema(description = "表单名字", example = "请假表单") + private String formName; + @Schema(description = "表单的配置-JSON 字符串") + private String formConf; + @Schema(description = "表单项的数组") + private List formFields; + @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) + private Map formVariables; + + @Data + @Schema(description = "流程实例") + public static class ProcessInstance { + + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "流程实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String processDefinitionId; + + /** + * 发起人的用户信息 + */ + private BpmProcessInstanceRespVO.User startUser; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java new file mode 100644 index 0000000..49a2316 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 回退流程任务的 Request VO") +@Data +public class BpmTaskReturnReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "回退到的任务 Key", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "回退到的任务 Key 不能为空") + private String targetTaskDefinitionKey; + + @Schema(description = "回退意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "我就是想驳回") + @NotEmpty(message = "回退意见不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java new file mode 100644 index 0000000..e2a1532 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Set; + +@Schema(description = "管理后台 - 加签任务的创建(加签) Request VO") +@Data +public class BpmTaskSignCreateReqVO { + + @Schema(description = "需要加签的任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "加签的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotEmpty(message = "加签用户不能为空") + private Set userIds; + + @Schema(description = "加签类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "before") + @NotEmpty(message = "加签类型不能为空") + private String type; // 参见 BpmTaskSignTypeEnum 枚举 + + @Schema(description = "加签原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "需要加签") + @NotEmpty(message = "加签原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java new file mode 100644 index 0000000..721968c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 加签任务的删除(减签) Request VO") +@Data +public class BpmTaskSignDeleteReqVO { + + @Schema(description = "被减签的任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "加签原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "需要减签") + @NotEmpty(message = "加签原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java new file mode 100644 index 0000000..79f0af4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 流程任务的转办 Request VO") +@Data +public class BpmTaskTransferReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "新审批人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "新审批人的用户编号不能为空") + private Long assigneeUserId; + + @Schema(description = "转办原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "做不了决定,需要你先帮忙瞅瞅") + @NotEmpty(message = "转办原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java new file mode 100644 index 0000000..e8d285e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.bpm.controller.app; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java new file mode 100644 index 0000000..d1930bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.bpm.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java new file mode 100644 index 0000000..3fe5cc0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 流程模型 Convert + * + * @author yunlongn + */ +@Mapper +public interface BpmModelConvert { + + BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class); + + default PageResult buildModelPage(PageResult pageResult, + Map formMap, + Map categoryMap, Map deploymentMap, + Map processDefinitionMap) { + List list = CollectionUtils.convertList(pageResult.getList(), model -> { + BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); + BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; + BpmCategoryDO category = categoryMap.get(model.getCategory()); + Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; + ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null; + return buildModel0(model, metaInfo, form, category, deployment, processDefinition); + }); + return new PageResult<>(list, pageResult.getTotal()); + } + + default BpmModelRespVO buildModel(Model model, + byte[] bpmnBytes) { + BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); + BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); + if (ArrayUtil.isNotEmpty(bpmnBytes)) { + modelVO.setBpmnXml(new String(bpmnBytes)); + } + return modelVO; + } + + default BpmModelRespVO buildModel0(Model model, + BpmModelMetaInfoRespDTO metaInfo, BpmFormDO form, BpmCategoryDO category, + Deployment deployment, ProcessDefinition processDefinition) { + BpmModelRespVO modelRespVO = new BpmModelRespVO().setId(model.getId()).setName(model.getName()) + .setKey(model.getKey()).setCategory(model.getCategory()) + .setCreateTime(DateUtils.of(model.getCreateTime())); + // Form + if (metaInfo != null) { + modelRespVO.setFormType(metaInfo.getFormType()).setFormId(metaInfo.getFormId()) + .setFormCustomCreatePath(metaInfo.getFormCustomCreatePath()) + .setFormCustomViewPath(metaInfo.getFormCustomViewPath()); + modelRespVO.setIcon(metaInfo.getIcon()).setDescription(metaInfo.getDescription()); + } + if (form != null) { + modelRespVO.setFormId(form.getId()).setFormName(form.getName()); + } + // Category + if (category != null) { + modelRespVO.setCategoryName(category.getName()); + } + // ProcessDefinition + if (processDefinition != null) { + modelRespVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class)); + modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ? + SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + if (deployment != null) { + modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime())); + } + } + return modelRespVO; + } + + default void copyToCreateModel(Model model, BpmModelCreateReqVO bean) { + model.setName(bean.getName()); + model.setKey(bean.getKey()); + model.setMetaInfo(buildMetaInfoStr(null, + null, bean.getDescription(), + null, null, null, null)); + } + + default void copyToUpdateModel(Model model, BpmModelUpdateReqVO bean) { + model.setName(bean.getName()); + model.setCategory(bean.getCategory()); + model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), + bean.getIcon(), bean.getDescription(), + bean.getFormType(), bean.getFormId(), bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); + } + + default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, + String icon, String description, + Integer formType, Long formId, String formCustomCreatePath, String formCustomViewPath) { + if (metaInfo == null) { + metaInfo = new BpmModelMetaInfoRespDTO(); + } + // 只有非空,才进行设置,避免更新时的覆盖 + if (StrUtil.isNotEmpty(icon)) { + metaInfo.setIcon(icon); + } + if (StrUtil.isNotEmpty(description)) { + metaInfo.setDescription(description); + } + if (Objects.nonNull(formType)) { + metaInfo.setFormType(formType); + metaInfo.setFormId(formId); + metaInfo.setFormCustomCreatePath(formCustomCreatePath); + metaInfo.setFormCustomViewPath(formCustomViewPath); + } + return JsonUtils.toJsonString(metaInfo); + } + + default BpmModelMetaInfoRespDTO buildMetaInfo(Model model) { + return JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java new file mode 100644 index 0000000..0e767d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * Bpm 流程定义的 Convert + * + * @author yunlong.li + */ +@Mapper +public interface BpmProcessDefinitionConvert { + + BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class); + + default PageResult buildProcessDefinitionPage(PageResult page, + Map deploymentMap, + Map processDefinitionInfoMap, + Map formMap, + Map categoryMap) { + List list = buildProcessDefinitionList(page.getList(), deploymentMap, processDefinitionInfoMap, formMap, categoryMap); + return new PageResult<>(list, page.getTotal()); + } + + default List buildProcessDefinitionList(List list, + Map deploymentMap, + Map processDefinitionInfoMap, + Map formMap, + Map categoryMap) { + return CollectionUtils.convertList(list, definition -> { + Deployment deployment = MapUtil.get(deploymentMap, definition.getDeploymentId(), Deployment.class); + BpmProcessDefinitionInfoDO processDefinitionInfo = MapUtil.get(processDefinitionInfoMap, definition.getId(), BpmProcessDefinitionInfoDO.class); + BpmFormDO form = null; + if (processDefinitionInfo != null) { + form = MapUtil.get(formMap, processDefinitionInfo.getFormId(), BpmFormDO.class); + } + BpmCategoryDO category = MapUtil.get(categoryMap, definition.getCategory(), BpmCategoryDO.class); + return buildProcessDefinition(definition, deployment, processDefinitionInfo, form, category, null, null); + }); + } + + default BpmProcessDefinitionRespVO buildProcessDefinition(ProcessDefinition definition, + Deployment deployment, + BpmProcessDefinitionInfoDO processDefinitionInfo, + BpmFormDO form, + BpmCategoryDO category, + BpmnModel bpmnModel, + List startUserSelectUserTaskList) { + BpmProcessDefinitionRespVO respVO = BeanUtils.toBean(definition, BpmProcessDefinitionRespVO.class); + respVO.setSuspensionState(definition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + // Deployment + if (deployment != null) { + respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime())); + } + // BpmProcessDefinitionInfoDO + if (processDefinitionInfo != null) { + copyTo(processDefinitionInfo, respVO); + // Form + if (form != null) { + respVO.setFormName(form.getName()); + } + } + // Category + if (category != null) { + respVO.setCategoryName(category.getName()); + } + // BpmnModel + if (bpmnModel != null) { + respVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnModel)); + respVO.setStartUserSelectTasks(BeanUtils.toBean(startUserSelectUserTaskList, BpmProcessDefinitionRespVO.UserTask.class)); + } + return respVO; + } + + @Mapping(source = "from.id", target = "to.id", ignore = true) + void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java new file mode 100644 index 0000000..99b7beb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.convert.message; + +import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Map; + +@Mapper +public interface BpmMessageConvert { + + BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class); + + @Mapping(target = "mobile", ignore = true) + @Mapping(source = "userId", target = "userId") + @Mapping(source = "templateCode", target = "templateCode") + @Mapping(source = "templateParams", target = "templateParams") + SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map templateParams); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java new file mode 100644 index 0000000..6db6ebc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.bpm.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java new file mode 100644 index 0000000..3cb674c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import org.flowable.engine.history.HistoricActivityInstance; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * BPM 活动 Convert + * + * @author 芋道源码 + */ +@Mapper(uses = DateUtils.class) +public interface BpmActivityConvert { + + BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class); + + List convertList(List list); + + @Mappings({ + @Mapping(source = "activityId", target = "key"), + @Mapping(source = "activityType", target = "type") + }) + BpmActivityRespVO convert(HistoricActivityInstance bean); +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java new file mode 100644 index 0000000..7981b9d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessInstanceConvert { + + BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); + + default PageResult buildProcessInstancePage(PageResult pageResult, + Map processDefinitionMap, + Map categoryMap, + Map> taskMap, + Map userMap, + Map deptMap) { + PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstanceRespVO.class); + for (int i = 0; i < pageResult.getList().size(); i++) { + BpmProcessInstanceRespVO respVO = vpPageResult.getList().get(i); + respVO.setStatus(FlowableUtils.getProcessInstanceStatus(pageResult.getList().get(i))); + MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), + processDefinition -> respVO.setCategory(processDefinition.getCategory())); + MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); + respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class)); + // user + if (userMap != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId())); + if (startUser != null) { + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); + } + } + } + return vpPageResult; + } + + default BpmProcessInstanceRespVO buildProcessInstance(HistoricProcessInstance processInstance, + ProcessDefinition processDefinition, + BpmProcessDefinitionInfoDO processDefinitionExt, + String bpmnXml, + AdminUserRespDTO startUser, + DeptRespDTO dept) { + BpmProcessInstanceRespVO respVO = BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class); + respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)); + respVO.setFormVariables(FlowableUtils.getProcessInstanceFormVariable(processInstance)); + // definition + respVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class)); + copyTo(processDefinitionExt, respVO.getProcessDefinition()); + respVO.getProcessDefinition().setBpmnXml(bpmnXml); + // user + if (startUser != null) { + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + if (dept != null) { + respVO.getStartUser().setDeptName(dept.getName()); + } + } + return respVO; + } + + @Mapping(source = "from.id", target = "to.id", ignore = true) + void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); + + default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, HistoricProcessInstance instance, Integer status) { + return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status) + .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey()); + } + + default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {; + return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status) + .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey()); + } + + default BpmMessageSendWhenProcessInstanceApproveReqDTO buildProcessInstanceApproveMessage(ProcessInstance instance) { + return new BpmMessageSendWhenProcessInstanceApproveReqDTO() + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())) + .setProcessInstanceId(instance.getId()) + .setProcessInstanceName(instance.getName()); + } + + default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) { + return new BpmMessageSendWhenProcessInstanceRejectReqDTO() + .setProcessInstanceName(instance.getName()) + .setProcessInstanceId(instance.getId()) + .setReason(reason) + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java new file mode 100644 index 0000000..5f4e915 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -0,0 +1,176 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; + +/** + * Bpm 任务 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmTaskConvert { + + BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); + + default PageResult buildTodoTaskPage(PageResult pageResult, + Map processInstanceMap, + Map userMap) { + return BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { + ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance == null) { + return; + } + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + }); + } + + default PageResult buildTaskPage(PageResult pageResult, + Map processInstanceMap, + Map userMap, + Map deptMap) { + List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { + BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); + taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); + // 用户信息 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName())); + } + // 流程实例 + HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + } + return taskVO; + }); + return new PageResult<>(taskVOList, pageResult.getTotal()); + } + + default List buildTaskListByProcessInstanceId(List taskList, + HistoricProcessInstance processInstance, + Map formMap, + Map userMap, + Map deptMap) { + List taskVOList = CollectionUtils.convertList(taskList, task -> { + BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); + taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); + // 流程实例 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + // 表单信息 + BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); + if (form != null) { + taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) + .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); + } + // 用户信息 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName())); + } + AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); + if (ownerUser != null) { + taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); + findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); + } + return taskVO; + }); + + // 拼接父子关系 + Map> childrenTaskMap = convertMultiMap( + filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())), + BpmTaskRespVO::getParentTaskId); + for (BpmTaskRespVO taskVO : taskVOList) { + taskVO.setChildren(childrenTaskMap.get(taskVO.getId())); + } + return filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId())); + } + + default List buildTaskListByParentTaskId(List taskList, + Map userMap, + Map deptMap) { + return convertList(taskList, task -> BeanUtils.toBean(task, BpmTaskRespVO.class, taskVO -> { + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); + if (dept != null) { + taskVO.getAssigneeUser().setDeptName(dept.getName()); + } + } + AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); + if (ownerUser != null) { + taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); + findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); + } + })); + } + + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, + Task task) { + BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); + reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId()) + .setProcessInstanceName(processInstance.getName()).setStartUserId(startUser.getId()) + .setStartUserNickname(startUser.getNickname()).setTaskId(task.getId()).setTaskName(task.getName()) + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())); + return reqDTO; + } + + /** + * 将父任务的属性,拷贝到子任务(加签任务) + * + * 为什么不使用 mapstruct 映射?因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的。 + * 使用 mapstruct 会将里面嵌套的各个属性值都设置进去,会出现意想不到的问题。 + * + * @param parentTask 父任务 + * @param childTask 加签任务 + */ + default void copyTo(TaskEntityImpl parentTask, TaskEntityImpl childTask) { + childTask.setName(parentTask.getName()); + childTask.setDescription(parentTask.getDescription()); + childTask.setCategory(parentTask.getCategory()); + childTask.setParentTaskId(parentTask.getId()); + childTask.setProcessDefinitionId(parentTask.getProcessDefinitionId()); + childTask.setProcessInstanceId(parentTask.getProcessInstanceId()); +// childTask.setExecutionId(parentTask.getExecutionId()); // TODO 芋艿:新加的,不太确定;尴尬,不加时,子任务不通过会失败(报错);加了,子任务审批通过会失败(报错) + childTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); + childTask.setTaskDefinitionId(parentTask.getTaskDefinitionId()); + childTask.setPriority(parentTask.getPriority()); + childTask.setCreateTime(new Date()); + childTask.setTenantId(parentTask.getTenantId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java new file mode 100644 index 0000000..916009d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * BPM 流程分类 DO + * + * @author 芋道源码 + */ +@TableName("bpm_category") +@KeySequence("bpm_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmCategoryDO extends BaseDO { + + /** + * 分类编号 + */ + @TableId + private Long id; + /** + * 分类名 + */ + private String name; + /** + * 分类标志 + */ + private String code; + /** + * 分类描述 + */ + private String description; + /** + * 分类状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 分类排序 + */ + private Integer sort; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java new file mode 100644 index 0000000..4c02188 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * BPM 工作流的表单定义 + * 用于工作流的申请表单,需要动态配置的场景 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_form", autoResultMap = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmFormDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 表单名 + */ + private String name; + /** + * 状态 + */ + private Integer status; + /** + * 表单的配置 + */ + private String conf; + /** + * 表单项的数组 + * + * 目前直接将 https://github.com/JakHuang/form-generator 生成的 JSON 串,直接保存 + * 定义:https://github.com/JakHuang/form-generator/issues/46 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fields; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java new file mode 100644 index 0000000..9ac9252 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * BPM 流程定义的拓信息 + * 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_definition_info", autoResultMap = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessDefinitionInfoDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 流程定义的编号 + * + * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + /** + * 流程模型的编号 + * + * 关联 Model 的 id 属性 + */ + private String modelId; + + /** + * 图标 + */ + private String icon; + /** + * 描述 + */ + private String description; + + /** + * 表单类型 + * + * 关联 {@link BpmModelFormTypeEnum} + */ + private Integer formType; + /** + * 动态表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 关联 {@link BpmFormDO#getId()} + */ + private Long formId; + /** + * 表单的配置 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 冗余 {@link BpmFormDO#getConf()} + */ + private String formConf; + /** + * 表单项的数组 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 冗余 {@link BpmFormDO#getFields()} ()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List formFields; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java new file mode 100644 index 0000000..6f6be58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * BPM 流程表达式 DO + * + * @author 芋道源码 + */ +@TableName("bpm_process_expression") +@KeySequence("bpm_process_expression_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessExpressionDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 表达式名字 + */ + private String name; + /** + * 表达式状态 + * + * 枚举 {@link TODO common_status 对应的类} + */ + private Integer status; + /** + * 表达式 + */ + private String expression; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java new file mode 100644 index 0000000..56be88f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * BPM 流程监听器 DO + * + * 目的:本质上它是流程监听器的模版,用于 BPMN 在设计时,直接选择这些模版 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_listener") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessListenerDO extends BaseDO { + + /** + * 主键 ID,自增 + */ + @TableId + private Long id; + /** + * 监听器名字 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 监听类型 + * + * 枚举 {@link cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerType} + * + * 1. execution:ExecutionListener 执行监听器 + * 2. task:TaskListener 任务监听器 + */ + private String type; + /** + * 监听事件 + * + * execution 时:start、end + * task 时:create 创建、assignment 指派、complete 完成、delete 删除、update 更新、timeout 超时 + */ + private String event; + + /** + * 值类型 + * + * 1. class:Java 类,ExecutionListener 需要 {@link org.flowable.engine.delegate.JavaDelegate},TaskListener 需要 {@link org.flowable.engine.delegate.TaskListener} + * 2. delegateExpression:委托表达式,在 class 的基础上,需要注册到 Spring 容器里,后续表达式通过 Spring Bean 名称即可 + * 3. expression:表达式,一个普通类的普通方法,将这个普通类注册到 Spring 容器中,然后表达式中还可以执行这个类中的方法 + */ + private String valueType; + /** + * 值 + */ + private String value; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java new file mode 100644 index 0000000..87df047 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.Set; + +/** + * BPM 用户组 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_user_group", autoResultMap = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmUserGroupDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 组名 + */ + private String name; + /** + * 描述 + */ + private String description; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 成员用户编号数组 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set userIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java new file mode 100644 index 0000000..6c5b648 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * OA 请假申请 DO + * + * {@link #day} 请假天数,目前先简单做。一般是分成请假上午和下午,可以是 1 整天,可以是 0.5 半天 + * + * @author jason + * @author 芋道源码 + */ +@TableName("bpm_oa_leave") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOALeaveDO extends BaseDO { + + /** + * 请假表单主键 + */ + @TableId + private Long id; + /** + * 申请人的用户编号 + * + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + /** + * 请假类型 + */ + private String type; + /** + * 原因 + */ + private String reason; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 结束时间 + */ + private LocalDateTime endTime; + /** + * 请假天数 + */ + private Long day; + /** + * 审批结果 + * + * 枚举 {@link BpmTaskStatusEnum} + * 考虑到简单,所以直接复用了 BpmProcessInstanceStatusEnum 枚举,也可以自己定义一个枚举哈 + */ + private Integer status; + + /** + * 对应的流程编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java new file mode 100644 index 0000000..57e7296 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.task; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 流程抄送 DO + * + * @author kyle + * @since 2024-01-22 + */ +@TableName(value = "bpm_process_instance_copy", autoResultMap = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessInstanceCopyDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 发起人 Id + * + * 冗余 ProcessInstance 的 startUserId 字段 + */ + private Long startUserId; + /** + * 流程名 + * + * 冗余 ProcessInstance 的 name 字段 + */ + private String processInstanceName; + /** + * 流程实例的编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 流程分类 + * + * 冗余 ProcessInstance 的 category 字段 + */ + private String category; + + /** + * 任务主键 + * + * 关联 Task 的 id 属性 + */ + private String taskId; + /** + * 任务名称 + * + * 冗余 Task 的 name 属性 + */ + private String taskName; + + /** + * 用户编号(被抄送的用户编号) + * + * 关联 system_users 的 id 属性 + */ + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java new file mode 100644 index 0000000..5fc8236 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.category; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * BPM 流程分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmCategoryMapper extends BaseMapperX { + + default PageResult selectPage(BpmCategoryPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmCategoryDO::getName, reqVO.getName()) + .likeIfPresent(BpmCategoryDO::getCode, reqVO.getCode()) + .eqIfPresent(BpmCategoryDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmCategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(BpmCategoryDO::getSort)); + } + + default BpmCategoryDO selectByName(String name) { + return selectOne(BpmCategoryDO::getName, name); + } + + default BpmCategoryDO selectByCode(String code) { + return selectOne(BpmCategoryDO::getCode, code); + } + + default List selectListByCode(Collection codes) { + return selectList(BpmCategoryDO::getCode, codes); + } + + default List selectListByStatus(Integer status) { + return selectList(BpmCategoryDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java new file mode 100644 index 0000000..53c01d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +/** + * 动态表单 Mapper + * + * @author 风里雾里 + */ +@Mapper +public interface BpmFormMapper extends BaseMapperX { + + default PageResult selectPage(BpmFormPageReqVO reqVO) { + return selectPage(reqVO, new QueryWrapperX() + .likeIfPresent("name", reqVO.getName()) + .orderByDesc("id")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java new file mode 100644 index 0000000..419d638 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface BpmProcessDefinitionInfoMapper extends BaseMapperX { + + default List selectListByProcessDefinitionIds(Collection processDefinitionIds) { + return selectList(BpmProcessDefinitionInfoDO::getProcessDefinitionId, processDefinitionIds); + } + + default BpmProcessDefinitionInfoDO selectByProcessDefinitionId(String processDefinitionId) { + return selectOne(BpmProcessDefinitionInfoDO::getProcessDefinitionId, processDefinitionId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java new file mode 100644 index 0000000..ab8c18c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * BPM 流程表达式 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessExpressionMapper extends BaseMapperX { + + default PageResult selectPage(BpmProcessExpressionPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmProcessExpressionDO::getName, reqVO.getName()) + .eqIfPresent(BpmProcessExpressionDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmProcessExpressionDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmProcessExpressionDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java new file mode 100644 index 0000000..10ccd2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * BPM 流程监听器 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessListenerMapper extends BaseMapperX { + + default PageResult selectPage(BpmProcessListenerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmProcessListenerDO::getName, reqVO.getName()) + .eqIfPresent(BpmProcessListenerDO::getType, reqVO.getType()) + .eqIfPresent(BpmProcessListenerDO::getEvent, reqVO.getEvent()) + .eqIfPresent(BpmProcessListenerDO::getStatus, reqVO.getStatus()) + .orderByDesc(BpmProcessListenerDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java new file mode 100644 index 0000000..ed07627 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户组 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmUserGroupMapper extends BaseMapperX { + + default PageResult selectPage(BpmUserGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmUserGroupDO::getName, reqVO.getName()) + .eqIfPresent(BpmUserGroupDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmUserGroupDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmUserGroupDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(BpmUserGroupDO::getStatus, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java new file mode 100644 index 0000000..2787874 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +/** + * 请假申请 Mapper + * + * @author jason + * @author 芋道源码 + */ +@Mapper +public interface BpmOALeaveMapper extends BaseMapperX { + + default PageResult selectPage(Long userId, BpmOALeavePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BpmOALeaveDO::getUserId, userId) + .eqIfPresent(BpmOALeaveDO::getStatus, reqVO.getStatus()) + .eqIfPresent(BpmOALeaveDO::getType, reqVO.getType()) + .likeIfPresent(BpmOALeaveDO::getReason, reqVO.getReason()) + .betweenIfPresent(BpmOALeaveDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmOALeaveDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java new file mode 100644 index 0000000..c5ec50f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmProcessInstanceCopyMapper extends BaseMapperX { + + default PageResult selectPage(Long loginUserId, BpmProcessInstanceCopyPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BpmProcessInstanceCopyDO::getUserId, loginUserId) + .likeIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceName, reqVO.getProcessInstanceName()) + .betweenIfPresent(BpmProcessInstanceCopyDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmProcessInstanceCopyDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java new file mode 100644 index 0000000..8e69fdc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.config; + +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.flowable.common.engine.api.delegate.event.FlowableEventListener; +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.AsyncListenableTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.List; + +/** + * BPM 模块的 Flowable 配置类 + * + * @author jason + */ +@Configuration(proxyBeanMethods = false) +public class BpmFlowableConfiguration { + + /** + * 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean + * + * 如果不创建,会导致项目启动时,Flowable 报错的问题 + */ + @Bean(name = "applicationTaskExecutor") + @ConditionalOnMissingBean(name = "applicationTaskExecutor") + public AsyncListenableTaskExecutor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(8); + executor.setMaxPoolSize(8); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("flowable-task-Executor-"); + executor.setAwaitTerminationSeconds(30); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAllowCoreThreadTimeOut(true); + executor.initialize(); + return executor; + } + + /** + * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类: + * + * 1. 设置各种监听器 + * 2. 设置自定义的 ActivityBehaviorFactory 实现 + */ + @Bean + public EngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer( + ObjectProvider listeners, + BpmActivityBehaviorFactory bpmActivityBehaviorFactory) { + return configuration -> { + // 注册监听器,例如说 BpmActivityEventListener + configuration.setEventListeners(ListUtil.toList(listeners.iterator())); + // 设置 ActivityBehaviorFactory 实现类,用于流程任务的审核人的自定义 + configuration.setActivityBehaviorFactory(bpmActivityBehaviorFactory); + }; + } + + // =========== 审批人相关的 Bean ========== + + @Bean + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskCandidateInvoker bpmTaskCandidateInvoker) { + BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); + bpmActivityBehaviorFactory.setTaskCandidateInvoker(bpmTaskCandidateInvoker); + return bpmActivityBehaviorFactory; + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") // adminUserApi 可以注入成功 + public BpmTaskCandidateInvoker bpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + return new BpmTaskCandidateInvoker(strategyList, adminUserApi); + } + + // =========== 自己拓展的 Bean ========== + + @Bean + public BpmProcessInstanceEventPublisher processInstanceEventPublisher(ApplicationEventPublisher publisher) { + return new BpmProcessInstanceEventPublisher(publisher); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java new file mode 100644 index 0000000..b5278f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import lombok.Setter; +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; + +/** + * 自定义的 ActivityBehaviorFactory 实现类,目的如下: + * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 + * + * @author 芋道源码 + */ +@Setter +public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { + + private BpmTaskCandidateInvoker taskCandidateInvoker; + + @Override + public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { + return new BpmUserTaskActivityBehavior(userTask) + .setTaskCandidateInvoker(taskCandidateInvoker); + } + + @Override + public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior behavior) { + return new BpmParallelMultiInstanceBehavior(activity, behavior) + .setTaskCandidateInvoker(taskCandidateInvoker); + } + + @Override + public SequentialMultiInstanceBehavior createSequentialMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior behavior) { + return new BpmSequentialMultiInstanceBehavior(activity, behavior) + .setTaskCandidateInvoker(taskCandidateInvoker); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java new file mode 100644 index 0000000..64ebb1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import lombok.Setter; +import org.flowable.bpmn.model.Activity; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; + +import java.util.Set; + +/** + * 自定义的【并行】的【多个】流程任务的 assignee 负责人的分配 + * 第一步,基于分配规则,计算出分配任务的【多个】候选人们。 + * 第二步,将【多个】任务候选人们,设置到 DelegateExecution 的 collectionVariable 变量中,以便 BpmUserTaskActivityBehavior 使用它 + * + * @author kemengkai + * @since 2022-04-21 16:57 + */ +@Setter +public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { + + private BpmTaskCandidateInvoker taskCandidateInvoker; + + public BpmParallelMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + /** + * 重写该方法,主要实现两个功能: + * 1. 忽略原有的 collectionVariable、collectionElementVariable 表达式,而是采用自己定义的 + * 2. 获得任务的处理人,并设置到 collectionVariable 中,用于 BpmUserTaskActivityBehavior 从中可以获取任务的处理人 + * + * 注意,多个任务实例,每个任务实例对应一个处理人,所以返回的数量就是任务处理人的数量 + * + * @param execution 执行任务 + * @return 数量 + */ + @Override + protected int resolveNrOfInstances(DelegateExecution execution) { + // 第一步,设置 collectionVariable 和 CollectionVariable + // 从 execution.getVariable() 读取所有任务处理人的 key + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); + // 从 execution.getVariable() 读取当前所有任务处理的人的 key + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); + + // 第二步,获取任务的所有处理人 + Set assigneeUserIds = taskCandidateInvoker.calculateUsers(execution); + execution.setVariable(super.collectionVariable, assigneeUserIds); + return assigneeUserIds.size(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java new file mode 100644 index 0000000..a214e26 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import lombok.Setter; +import org.flowable.bpmn.model.Activity; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * 自定义的【串行】的【多个】流程任务的 assignee 负责人的分配 + * + * 本质上,实现和 {@link BpmParallelMultiInstanceBehavior} 一样,只是继承的类不一样 + * + * @author 芋道源码 + */ +@Setter +public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceBehavior { + + private BpmTaskCandidateInvoker taskCandidateInvoker; + + public BpmSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + /** + * 逻辑和 {@link BpmParallelMultiInstanceBehavior#resolveNrOfInstances(DelegateExecution)} 类似 + * + * 差异的点:是在【第二步】的时候,需要返回 LinkedHashSet 集合!因为它需要有序! + */ + @Override + protected int resolveNrOfInstances(DelegateExecution execution) { + // 第一步,设置 collectionVariable 和 CollectionVariable + // 从 execution.getVariable() 读取所有任务处理人的 key + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); + // 从 execution.getVariable() 读取当前所有任务处理的人的 key + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); + + // 第二步,获取任务的所有处理人 + Set assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!! + execution.setVariable(super.collectionVariable, assigneeUserIds); + return assigneeUserIds.size(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java new file mode 100644 index 0000000..c494652 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.impl.el.ExpressionManager; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.TaskHelper; +import org.flowable.task.service.TaskService; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +import java.util.List; +import java.util.Set; + +/** + * 自定义的【单个】流程任务的 assignee 负责人的分配 + * 第一步,基于分配规则,计算出分配任务的【单个】候选人。如果找不到,则直接报业务异常,不继续执行后续的流程; + * 第二步,随机选择一个候选人,则选择作为 assignee 负责人。 + * + * @author 芋道源码 + */ +@Slf4j +public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { + + @Setter + private BpmTaskCandidateInvoker taskCandidateInvoker; + + public BpmUserTaskActivityBehavior(UserTask userTask) { + super(userTask); + } + + @Override + protected void handleAssignments(TaskService taskService, String assignee, String owner, + List candidateUsers, List candidateGroups, TaskEntity task, ExpressionManager expressionManager, + DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { + // 第一步,获得任务的候选用户 + Long assigneeUserId = calculateTaskCandidateUsers(execution); + Assert.notNull(assigneeUserId, "任务处理人不能为空"); + // 第二步,设置作为负责人 + TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); + } + + private Long calculateTaskCandidateUsers(DelegateExecution execution) { + // 情况一,如果是多实例的任务,例如说会签、或签等情况,则从 Variable 中获取。 + // 顺序审批可见 BpmSequentialMultiInstanceBehavior,并发审批可见 BpmSequentialMultiInstanceBehavior + if (super.multiInstanceActivityBehavior != null) { + return execution.getVariable(super.multiInstanceActivityBehavior.getCollectionElementVariable(), Long.class); + } + + // 情况二,如果非多实例的任务,则计算任务处理人 + // 第一步,先计算可处理该任务的处理人们 + Set candidateUserIds = taskCandidateInvoker.calculateUsers(execution); + // 第二步,后随机选择一个任务的处理人 + // 疑问:为什么一定要选择一个任务处理人? + // 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。 + // 如果希望一个任务可以同时被多个人处理,可以考虑使用 BpmParallelMultiInstanceBehavior 实现的会签 or 或签。 + int index = RandomUtil.randomInt(candidateUserIds.size()); + return CollUtil.get(candidateUserIds, index); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java new file mode 100644 index 0000000..c0c7ca0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; + +/** + * {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算 + * + * @author 芋道源码 + */ +@Slf4j +public class BpmTaskCandidateInvoker { + + private final Map strategyMap = new HashMap<>(); + + private final AdminUserApi adminUserApi; + + public BpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + strategyList.forEach(strategy -> { + BpmTaskCandidateStrategy oldStrategy = strategyMap.put(strategy.getStrategy(), strategy); + Assert.isNull(oldStrategy, "策略(%s) 重复", strategy.getStrategy()); + }); + this.adminUserApi = adminUserApi; + } + + /** + * 校验流程模型的任务分配规则全部都配置了 + * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! + * + * @param bpmnBytes BPMN XML + */ + public void validateBpmnConfig(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + assert bpmnModel != null; + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + // 遍历所有的 UserTask,校验审批人配置 + userTaskList.forEach(userTask -> { + // 1. 非空校验 + Integer strategy = BpmnModelUtils.parseCandidateStrategy(userTask); + String param = BpmnModelUtils.parseCandidateParam(userTask); + if (strategy == null) { + throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); + } + BpmTaskCandidateStrategy candidateStrategy = getCandidateStrategy(strategy); + if (candidateStrategy.isParamRequired() && StrUtil.isBlank(param)) { + throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); + } + // 2. 具体策略校验 + getCandidateStrategy(strategy).validateParam(param); + }); + } + + /** + * 计算任务的候选人 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到候选人 + public Set calculateUsers(DelegateExecution execution) { + Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement()); + String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement()); + // 1.1 计算任务的候选人 + Set userIds = getCandidateStrategy(strategy).calculateUsers(execution, param); + // 1.2 移除被禁用的用户 + removeDisableUsers(userIds); + + // 2. 校验是否有候选人 + if (CollUtil.isEmpty(userIds)) { + log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), + execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param); + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); + } + return userIds; + } + + @VisibleForTesting + void removeDisableUsers(Set assigneeUserIds) { + if (CollUtil.isEmpty(assigneeUserIds)) { + return; + } + Map userMap = adminUserApi.getUserMap(assigneeUserIds); + assigneeUserIds.removeIf(id -> { + AdminUserRespDTO user = userMap.get(id); + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); + }); + } + + private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) { + BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy); + Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy); + BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum); + Assert.notNull(strategyObj, "策略(%s) 不存在", strategy); + return strategyObj; + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java new file mode 100644 index 0000000..1534d39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.Set; + +/** + * BPM 任务的候选人的策略接口 + * + * 例如说:分配审批人 + * + * @author 芋道源码 + */ +public interface BpmTaskCandidateStrategy { + + /** + * 对应策略 + * + * @return 策略 + */ + BpmTaskCandidateStrategyEnum getStrategy(); + + /** + * 校验参数 + * + * @param param 参数 + */ + void validateParam(String param); + + /** + * 基于执行任务,获得任务的候选用户们 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + Set calculateUsers(DelegateExecution execution, String param); + + /** + * 是否一定要输入参数 + * + * @return 是否 + */ + default boolean isParamRequired() { + return true; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java new file mode 100644 index 0000000..32e9b10 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; + +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static java.util.Collections.emptySet; + +/** + * 分配给发起人的 Leader 审批的 Expression 流程表达式 + * 目前 Leader 的定义是,发起人所在部门的 Leader + * + * @author 芋道源码 + */ +@Component +public class BpmTaskAssignLeaderExpression { + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Resource + private BpmProcessInstanceService processInstanceService; + + /** + * 计算审批的候选人 + * + * @param execution 流程执行实体 + * @param level 指定级别 + * @return 指定级别的领导 + */ + public Set calculateUsers(DelegateExecution execution, int level) { + Assert.isTrue(level > 0, "level 必须大于 0"); + // 获得发起人 + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); + // 获得对应 leve 的部门 + DeptRespDTO dept = null; + for (int i = 0; i < level; i++) { + // 获得 level 对应的部门 + if (dept == null) { + dept = getStartUserDept(startUserId); + if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 + return emptySet(); + } + } else { + DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()); + if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 + break; + } + dept = parentDept; + } + } + return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); + } + + private DeptRespDTO getStartUserDept(Long startUserId) { + AdminUserRespDTO startUser = adminUserApi.getUser(startUserId); + if (startUser.getDeptId() == null) { // 找不到部门,所以无法使用该规则 + return null; + } + return deptApi.getDept(startUser.getDeptId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java new file mode 100644 index 0000000..2c7de5a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; + +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 分配给发起人审批的 Expression 流程表达式 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskAssignStartUserExpression { + + @Resource + private BpmProcessInstanceService processInstanceService; + + /** + * 计算审批的候选人 + * + * @param execution 流程执行实体 + * @return 发起人 + */ + public Set calculateUsers(ExecutionEntityImpl execution) { + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); + return SetUtils.asSet(startUserId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java new file mode 100644 index 0000000..e3c439e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的负责人 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_LEADER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List depts = deptApi.getDeptList(deptIds); + return convertSet(depts, DeptRespDTO::getLeaderUserId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java new file mode 100644 index 0000000..78f1589 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的成员 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_MEMBER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByDeptIds(deptIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java new file mode 100644 index 0000000..e0f9dab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.hutool.core.convert.Convert; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 流程表达式 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy { + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.EXPRESSION; + } + + @Override + public void validateParam(String param) { + // do nothing 因为它基本做不了校验 + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Object result = FlowableUtils.getExpressionValue(execution, param); + return Convert.toSet(Long.class, result); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java new file mode 100644 index 0000000..da1aa39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; + +/** + * 用户组 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy { + + @Resource + private BpmUserGroupService userGroupService; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER_GROUP; + } + + @Override + public void validateParam(String param) { + Set groupIds = StrUtils.splitToLongSet(param); + userGroupService.getUserGroupList(groupIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set groupIds = StrUtils.splitToLongSet(param); + List groups = userGroupService.getUserGroupList(groupIds); + return convertSetByFlatMap(groups, BpmUserGroupDO::getUserIds, Collection::stream); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java new file mode 100644 index 0000000..ca259ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 岗位 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidatePostStrategy implements BpmTaskCandidateStrategy { + + @Resource + private PostApi postApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.POST; + } + + @Override + public void validateParam(String param) { + Set postIds = StrUtils.splitToLongSet(param); + postApi.validPostList(postIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set postIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByPostIds(postIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java new file mode 100644 index 0000000..de51b3c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 角色 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy { + + @Resource + private RoleApi roleApi; + @Resource + private PermissionApi permissionApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.ROLE; + } + + @Override + public void validateParam(String param) { + Set roleIds = StrUtils.splitToLongSet(param); + roleApi.validRoleList(roleIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set roleIds = StrUtils.splitToLongSet(param); + return permissionApi.getUserRoleIdListByRoleIds(roleIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java new file mode 100644 index 0000000..36750ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.*; + +/** + * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskCandidateStartUserSelectStrategy implements BpmTaskCandidateStrategy { + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessInstanceService processInstanceService; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.START_USER_SELECT; + } + + @Override + public void validateParam(String param) {} + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Assert.notNull(processInstance, "流程实例({})不能为空", execution.getProcessInstanceId()); + Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); + Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", + execution.getProcessInstanceId()); + // 获得审批人 + List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); + return new LinkedHashSet<>(assignees); + } + + @Override + public boolean isParamRequired() { + return false; + } + + /** + * 获得发起人自选审批人的 UserTask 列表 + * + * @param bpmnModel BPMN 模型 + * @return UserTask 列表 + */ + public static List getStartUserSelectUserTaskList(BpmnModel bpmnModel) { + if (bpmnModel == null) { + return null; + } + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + if (CollUtil.isEmpty(userTaskList)) { + return null; + } + userTaskList.removeIf(userTask -> !Objects.equals(BpmnModelUtils.parseCandidateStrategy(userTask), + BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())); + return userTaskList; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java new file mode 100644 index 0000000..a6daec0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 用户 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy { + + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER; + } + + @Override + public void validateParam(String param) { + adminUserApi.validateUserList(StrUtils.splitToLongSet(param)); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + return StrUtils.splitToLongSet(param); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java new file mode 100644 index 0000000..e965d22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +import org.flowable.engine.runtime.ProcessInstance; + +/** + * BPM 通用常量 + * + * @author 芋道源码 + */ +public class BpmConstants { + + /** + * 流程实例的变量 - 状态 + * + * @see ProcessInstance#getProcessVariables() + */ + public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS"; + /** + * 流程实例的变量 - 发起用户选择的审批人 Map + * + * @see ProcessInstance#getProcessVariables() + */ + public static final String PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES = "PROCESS_START_USER_SELECT_ASSIGNEES"; + + /** + * 任务的变量 - 状态 + * + * @see org.flowable.task.api.Task#getTaskLocalVariables() + */ + public static final String TASK_VARIABLE_STATUS = "TASK_STATUS"; + /** + * 任务的变量 - 理由 + * + * 例如说:审批通过、不通过的理由 + * + * @see org.flowable.task.api.Task#getTaskLocalVariables() + */ + public static final String TASK_VARIABLE_REASON = "TASK_REASON"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java new file mode 100644 index 0000000..a8b5385 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 任务的候选人策略枚举 + * + * 例如说:分配给指定人审批 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmTaskCandidateStrategyEnum { + + ROLE(10, "角色"), + DEPT_MEMBER(20, "部门的成员"), // 包括负责人 + DEPT_LEADER(21, "部门的负责人"), + POST(22, "岗位"), + USER(30, "用户"), + START_USER_SELECT(35, "发起人自选"), // 申请人自己,可在提交申请时选择此节点的审批人 + USER_GROUP(40, "用户组"), + EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager + ; + + /** + * 类型 + */ + private final Integer strategy; + /** + * 描述 + */ + private final String description; + + public static BpmTaskCandidateStrategyEnum valueOf(Integer strategy) { + return ArrayUtil.firstMatch(o -> o.getStrategy().equals(strategy), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java new file mode 100644 index 0000000..3eb6981 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +/** + * BPMN XML 常量信息 + * + * @author 芋道源码 + */ +public interface BpmnModelConstants { + + String BPMN_FILE_SUFFIX = ".bpmn"; + + /** + * BPMN 中的命名空间 + */ + String NAMESPACE = "http://flowable.org/bpmn"; + + /** + * BPMN UserTask 的扩展属性,用于标记候选人策略 + */ + String USER_TASK_CANDIDATE_STRATEGY = "candidateStrategy"; + /** + * BPMN UserTask 的扩展属性,用于标记候选人参数 + */ + String USER_TASK_CANDIDATE_PARAM = "candidateParam"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java new file mode 100644 index 0000000..efeda8a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.event; + +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import lombok.AllArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; + +/** + * {@link BpmProcessInstanceStatusEvent} 的生产者 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Validated +public class BpmProcessInstanceEventPublisher { + + private final ApplicationEventPublisher publisher; + + public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceStatusEvent event) { + publisher.publishEvent(event); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java new file mode 100644 index 0000000..f6d0a28 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; + +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import com.google.common.collect.ImmutableSet; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; +import org.flowable.engine.delegate.event.FlowableCancelledEvent; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 监听 {@link ProcessInstance} 的状态变更,更新其对应的 status 状态 + * + * @author jason + */ +@Component +public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEventListener { + + @Resource + @Lazy + private BpmProcessInstanceService processInstanceService; + + public static final Set PROCESS_INSTANCE_EVENTS = ImmutableSet.builder() + .add(FlowableEngineEventType.PROCESS_CANCELLED) + .add(FlowableEngineEventType.PROCESS_COMPLETED) + .build(); + + public BpmProcessInstanceEventListener(){ + super(PROCESS_INSTANCE_EVENTS); + } + + @Override + protected void processCancelled(FlowableCancelledEvent event) { + processInstanceService.updateProcessInstanceWhenCancel(event); + } + + @Override + protected void processCompleted(FlowableEngineEntityEvent event) { + processInstanceService.updateProcessInstanceWhenApprove((ProcessInstance)event.getEntity()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java new file mode 100644 index 0000000..8cb4041 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import com.google.common.collect.ImmutableSet; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; +import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.task.api.Task; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +/** + * 监听 {@link Task} 的开始与完成 + * + * @author jason + */ +@Component +@Slf4j +public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { + + @Resource + @Lazy // 解决循环依赖 + private BpmTaskService taskService; + @Resource + @Lazy // 解决循环依赖 + private BpmActivityService activityService; + + public static final Set TASK_EVENTS = ImmutableSet.builder() + .add(FlowableEngineEventType.TASK_CREATED) + .add(FlowableEngineEventType.TASK_ASSIGNED) +// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。 + .add(FlowableEngineEventType.ACTIVITY_CANCELLED) + .build(); + + public BpmTaskEventListener(){ + super(TASK_EVENTS); + } + + @Override + protected void taskCreated(FlowableEngineEntityEvent event) { + taskService.updateTaskStatusWhenCreated((Task) event.getEntity()); + } + + @Override + protected void taskAssigned(FlowableEngineEntityEvent event) { + taskService.updateTaskExtAssign((Task)event.getEntity()); + } + + @Override + protected void activityCancelled(FlowableActivityCancelledEvent event) { + List activityList = activityService.getHistoricActivityListByExecutionId(event.getExecutionId()); + if (CollUtil.isEmpty(activityList)) { + log.error("[activityCancelled][使用 executionId({}) 查找不到对应的活动实例]", event.getExecutionId()); + return; + } + // 遍历处理 + activityList.forEach(activity -> { + if (StrUtil.isEmpty(activity.getTaskId())) { + return; + } + taskService.updateTaskStatusWhenCanceled(activity.getTaskId()); + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java new file mode 100644 index 0000000..0ce920e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +/** + * 类型为 class 的 ExecutionListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +public class DemoDelegateClassExecutionListener implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java new file mode 100644 index 0000000..00f3504 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.stereotype.Component; + +/** + * 类型为 delegateExpression 的 ExecutionListener 监听器示例 + * + * 和 {@link DemoDelegateClassExecutionListener} 的差异是,需要注册到 Spring 中 + */ +@Component +@Slf4j +public class DemoDelegateExpressionExecutionListener implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java new file mode 100644 index 0000000..949140f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +/** + * 类型为 expression 的 ExecutionListener 监听器示例 + * + * 和 {@link DemoDelegateClassExecutionListener} 的差异是,需要注册到 Spring 中,但不用实现 {@link org.flowable.engine.delegate.JavaDelegate} 接口 + */ +@Component +@Slf4j +public class DemoSpringExpressionExecutionListener { + + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java new file mode 100644 index 0000000..dee2b95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; + +/** + * 类型为 class 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +public class DemoDelegateClassTaskListener implements TaskListener { + + @Override + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java new file mode 100644 index 0000000..e554ff8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; + +/** + * 类型为 delegateExpression 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class DemoDelegateExpressionTaskListener implements TaskListener { + + @Override + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java new file mode 100644 index 0000000..0917abd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; + +/** + * 类型为 expression 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +@Component +public class DemoSpringExpressionTaskListener { + + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java new file mode 100644 index 0000000..bcf82d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -0,0 +1,329 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.*; +import org.flowable.common.engine.impl.util.io.BytesStreamSource; + +import java.util.*; + +/** + * 流程模型转操作工具类 + */ +public class BpmnModelUtils { + + public static Integer parseCandidateStrategy(FlowElement userTask) { + return NumberUtils.parseInt(userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); + } + + public static String parseCandidateParam(FlowElement userTask) { + return userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); + } + + /** + * 根据节点,获取入口连线 + * + * @param source 起始节点 + * @return 入口连线列表 + */ + public static List getElementIncomingFlows(FlowElement source) { + if (source instanceof FlowNode) { + return ((FlowNode) source).getIncomingFlows(); + } + return new ArrayList<>(); + } + + /** + * 根据节点,获取出口连线 + * + * @param source 起始节点 + * @return 出口连线列表 + */ + public static List getElementOutgoingFlows(FlowElement source) { + if (source instanceof FlowNode) { + return ((FlowNode) source).getOutgoingFlows(); + } + return new ArrayList<>(); + } + + /** + * 获取流程元素信息 + * + * @param model bpmnModel 对象 + * @param flowElementId 元素 ID + * @return 元素信息 + */ + public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { + Process process = model.getMainProcess(); + return process.getFlowElement(flowElementId); + } + + /** + * 获得 BPMN 流程中,指定的元素们 + * + * @param model 模型 + * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等 + * @return 元素们 + */ + public static List getBpmnModelElements(BpmnModel model, Class clazz) { + List result = new ArrayList<>(); + model.getProcesses().forEach(process -> { + process.getFlowElements().forEach(flowElement -> { + if (flowElement.getClass().isAssignableFrom(clazz)) { + result.add((T) flowElement); + } + }); + }); + return result; + } + + public static StartEvent getStartEvent(BpmnModel model) { + Process process = model.getMainProcess(); + // 从 initialFlowElement 找 + FlowElement startElement = process.getInitialFlowElement(); + if (startElement instanceof StartEvent) { + return (StartEvent) startElement; + } + // 从 flowElementList 找 + return (StartEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof StartEvent); + } + + public static BpmnModel getBpmnModel(byte[] bpmnBytes) { + if (ArrayUtil.isEmpty(bpmnBytes)) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + // 补充说明:由于在 Flowable 中自定义了属性,所以 validateSchema 传递 false + return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), false, false); + } + + public static String getBpmnXml(BpmnModel model) { + if (model == null) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + return new String(converter.convertToXML(model)); + } + + // ========== 遍历相关的方法 ========== + + /** + * 找到 source 节点之前的所有用户任务节点 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 已找到的用户任务节点 + * @return 用户任务节点 数组 + */ + public static List getPreviousUserTaskList(FlowElement source, Set hasSequenceFlow, List userTaskList) { + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + userTaskList = getPreviousUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + if (sequenceFlows == null) { + return userTaskList; + } + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 类型为用户节点,则新增父级节点 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement()); + } + // 类型为子流程,则添加子流程开始节点出口处相连的节点 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { + // 获取子流程用户任务节点 + List childUserTaskList = findChildProcessUserTaskList((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (CollUtil.isNotEmpty(childUserTaskList)) { + userTaskList.addAll(childUserTaskList); + } + } + // 继续迭代 + userTaskList = getPreviousUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList); + } + return userTaskList; + } + + /** + * 迭代获取子流程用户任务节点 + * + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 需要撤回的用户任务列表 + * @return 用户任务节点 + */ + public static List findChildProcessUserTaskList(FlowElement source, Set hasSequenceFlow, List userTaskList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + if (sequenceFlows == null) { + return userTaskList; + } + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = findChildProcessUserTaskList((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (CollUtil.isNotEmpty(childUserTaskList)) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + userTaskList = findChildProcessUserTaskList(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList); + } + return userTaskList; + } + + + /** + * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 + * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 + * + * @param source 起始节点 + * @param target 目标节点 + * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复 + * @return 结果 + */ + public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set visitedElements) { + visitedElements = visitedElements == null ? new HashSet<>() : visitedElements; + // 不能是开始事件和子流程 + if (source instanceof StartEvent && isInEventSubprocess(source)) { + return false; + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + if (CollUtil.isEmpty(sequenceFlows)) { + return true; + } + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (visitedElements.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + visitedElements.add(sequenceFlow.getId()); + // 这条线路存在目标节点,这条线路完成,进入下个线路 + FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement(); + if (target.getId().equals(sourceFlowElement.getId())) { + continue; + } + // 如果目标节点为并行网关,则不继续 + if (sourceFlowElement instanceof ParallelGateway) { + return false; + } + // 否则就继续迭代 + if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) { + return false; + } + } + return true; + } + + /** + * 判断当前节点是否属于不同的子流程 + * + * @param flowElement 被判断的节点 + * @return true 表示属于子流程 + */ + private static boolean isInEventSubprocess(FlowElement flowElement) { + FlowElementsContainer flowElementsContainer = flowElement.getParentContainer(); + while (flowElementsContainer != null) { + if (flowElementsContainer instanceof EventSubProcess) { + return true; + } + + if (flowElementsContainer instanceof FlowElement) { + flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer(); + } else { + flowElementsContainer = null; + } + } + return false; + } + + /** + * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 + * + * @param source 起始节点 + * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 需要撤回的用户任务列表 + * @return 子级任务节点列表 + */ + public static List iteratorFindChildUserTasks(FlowElement source, List runTaskKeyList, + Set hasSequenceFlow, List userTaskList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList); + } + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + if (sequenceFlows == null) { + return userTaskList; + } + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) { + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (CollUtil.isNotEmpty(childUserTaskList)) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList); + } + return userTaskList; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java new file mode 100644 index 0000000..a8ee4e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; + +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; +import org.flowable.common.engine.api.delegate.Expression; +import org.flowable.common.engine.api.variable.VariableContainer; +import org.flowable.common.engine.impl.el.ExpressionManager; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.ProcessEngineConfiguration; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.TaskInfo; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Flowable 相关的工具方法 + * + * @author 芋道源码 + */ +public class FlowableUtils { + + // ========== User 相关的工具方法 ========== + + public static void setAuthenticatedUserId(Long userId) { + Authentication.setAuthenticatedUserId(String.valueOf(userId)); + } + + public static void clearAuthenticatedUserId() { + Authentication.setAuthenticatedUserId(null); + } + + public static String getTenantId() { + Long tenantId = TenantContextHolder.getTenantId(); + return tenantId != null ? String.valueOf(tenantId) : ProcessEngineConfiguration.NO_TENANT_ID; + } + + // ========== Execution 相关的工具方法 ========== + + /** + * 格式化多实例(并签、或签)的 collectionVariable 变量(多实例对应的多审批人列表) + * + * @param activityId 活动编号 + * @return collectionVariable 变量 + */ + public static String formatExecutionCollectionVariable(String activityId) { + return activityId + "_assignees"; + } + + /** + * 格式化多实例(并签、或签)的 collectionElementVariable 变量(当前实例对应的一个审批人) + * + * @param activityId 活动编号 + * @return collectionElementVariable 变量 + */ + public static String formatExecutionCollectionElementVariable(String activityId) { + return activityId + "_assignee"; + } + + // ========== ProcessInstance 相关的工具方法 ========== + + public static Integer getProcessInstanceStatus(ProcessInstance processInstance) { + return getProcessInstanceStatus(processInstance.getProcessVariables()); + } + + public static Integer getProcessInstanceStatus(HistoricProcessInstance processInstance) { + return getProcessInstanceStatus(processInstance.getProcessVariables()); + } + + /** + * 获得流程实例的状态 + * + * @param processVariables 流程实例的 variables + * @return 状态 + */ + private static Integer getProcessInstanceStatus(Map processVariables) { + return (Integer) processVariables.get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); + } + + /** + * 获得流程实例的表单 + * + * @param processInstance 流程实例 + * @return 表单 + */ + public static Map getProcessInstanceFormVariable(HistoricProcessInstance processInstance) { + Map formVariables = new HashMap<>(processInstance.getProcessVariables()); + filterProcessInstanceFormVariable(formVariables); + return formVariables; + } + + /** + * 过滤流程实例的表单 + * + * 为什么要过滤?目前使用 processVariables 存储所有流程实例的拓展字段,需要过滤掉一部分的系统字段,从而实现表单的展示 + * + * @param processVariables 流程实例的 variables + * @return 过滤后的表单 + */ + public static Map filterProcessInstanceFormVariable(Map processVariables) { + processVariables.remove(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); + return processVariables; + } + + /** + * 获得流程实例的发起用户选择的审批人 Map + * + * @param processInstance 流程实例 + * @return 发起用户选择的审批人 Map + */ + @SuppressWarnings("unchecked") + public static Map> getStartUserSelectAssignees(ProcessInstance processInstance) { + return (Map>) processInstance.getProcessVariables().get( + BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); + } + + // ========== Task 相关的工具方法 ========== + + /** + * 获得任务的状态 + * + * @param task 任务 + * @return 状态 + */ + public static Integer getTaskStatus(TaskInfo task) { + return (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + } + + /** + * 获得任务的审批原因 + * + * @param task 任务 + * @return 审批原因 + */ + public static String getTaskReason(TaskInfo task) { + return (String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON); + } + + /** + * 获得任务的表单 + * + * @param task 任务 + * @return 表单 + */ + public static Map getTaskFormVariable(TaskInfo task) { + Map formVariables = new HashMap<>(task.getTaskLocalVariables()); + filterTaskFormVariable(formVariables); + return formVariables; + } + + /** + * 过滤任务的表单 + * + * 为什么要过滤?目前使用 taskLocalVariables 存储所有任务的拓展字段,需要过滤掉一部分的系统字段,从而实现表单的展示 + * + * @param taskLocalVariables 任务的 taskLocalVariables + * @return 过滤后的表单 + */ + public static Map filterTaskFormVariable(Map taskLocalVariables) { + taskLocalVariables.remove(BpmConstants.TASK_VARIABLE_STATUS); + taskLocalVariables.remove(BpmConstants.TASK_VARIABLE_REASON); + return taskLocalVariables; + } + + // ========== Expression 相关的工具方法 ========== + + public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) { + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + assert processEngineConfiguration != null; + ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager(); + assert expressionManager != null; + Expression expression = expressionManager.createExpression(expressionString); + return expression.getValue(variableContainer); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java new file mode 100644 index 0000000..52fdb7f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 bpm 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.bpm.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java new file mode 100644 index 0000000..86e3135 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.framework.web.config; + +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import cn.iocoder.yudao.module.bpm.framework.web.core.FlowableWebFilter; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * bpm 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class BpmWebConfiguration { + + /** + * bpm 模块的 API 分组 + */ + @Bean + public GroupedOpenApi bpmGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("bpm"); + } + + /** + * 配置 Flowable Web 过滤器 + */ + @Bean + public FilterRegistrationBean flowableWebFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new FlowableWebFilter()); + registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); + return registrationBean; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java new file mode 100644 index 0000000..7c7ce35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.bpm.framework.web.core; + +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Flowable Web 过滤器,将 userId 设置到 {@link org.flowable.common.engine.impl.identity.Authentication} 中 + * + * @author jason + */ +public class FlowableWebFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + try { + // 设置工作流的用户 + Long userId = SecurityFrameworkUtils.getLoginUserId(); + if (userId != null) { + FlowableUtils.setAuthenticatedUserId(userId); + } + // 过滤 + chain.doFilter(request, response); + } finally { + // 清理 + FlowableUtils.clearAuthenticatedUserId(); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/package-info.java new file mode 100644 index 0000000..c014170 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * bpm 模块的 web 配置 + */ +package cn.iocoder.yudao.module.bpm.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java new file mode 100644 index 0000000..9d02824 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java @@ -0,0 +1,12 @@ +/** + * bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能,基于 Flowable 6 版本实现。 + * 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 + * + * bpm 解释:https://baike.baidu.com/item/BPM/1933 + * + * 1. Controller URL:以 /bpm/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 bpm_ 开头,方便在数据库中区分 + * + * 注意,由于 Bpm 模块下,容易和其它模块重名,所以类名都加载 Bpm 的前缀~ + */ +package cn.iocoder.yudao.module.bpm; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java new file mode 100644 index 0000000..e267d30 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * BPM 流程分类 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmCategoryService { + + /** + * 创建流程分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCategory(@Valid BpmCategorySaveReqVO createReqVO); + + /** + * 更新流程分类 + * + * @param updateReqVO 更新信息 + */ + void updateCategory(@Valid BpmCategorySaveReqVO updateReqVO); + + /** + * 删除流程分类 + * + * @param id 编号 + */ + void deleteCategory(Long id); + + /** + * 获得流程分类 + * + * @param id 编号 + * @return BPM 流程分类 + */ + BpmCategoryDO getCategory(Long id); + + /** + * 获得流程分类分页 + * + * @param pageReqVO 分页查询 + * @return 流程分类分页 + */ + PageResult getCategoryPage(BpmCategoryPageReqVO pageReqVO); + + /** + * 获得流程分类 Map,基于指定编码 + * + * @param codes 编号数组 + * @return 流程分类 Map + */ + default Map getCategoryMap(Collection codes) { + return convertMap(getCategoryListByCode(codes), BpmCategoryDO::getCode); + } + + /** + * 获得流程分类列表,基于指定编码 + * + * @return 流程分类列表 + */ + List getCategoryListByCode(Collection codes); + + /** + * 获得流程分类列表,基于指定状态 + * + * @param status 状态 + * @return 流程分类列表 + */ + List getCategoryListByStatus(Integer status); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java new file mode 100644 index 0000000..d76eb98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.category.BpmCategoryMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 流程分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmCategoryServiceImpl implements BpmCategoryService { + + @Resource + private BpmCategoryMapper bpmCategoryMapper; + + @Override + public Long createCategory(BpmCategorySaveReqVO createReqVO) { + // 校验唯一 + validateCategoryNameUnique(createReqVO); + validateCategoryCodeUnique(createReqVO); + // 插入 + BpmCategoryDO category = BeanUtils.toBean(createReqVO, BpmCategoryDO.class); + bpmCategoryMapper.insert(category); + return category.getId(); + } + + @Override + public void updateCategory(BpmCategorySaveReqVO updateReqVO) { + // 校验存在 + validateCategoryExists(updateReqVO.getId()); + validateCategoryNameUnique(updateReqVO); + validateCategoryCodeUnique(updateReqVO); + // 更新 + BpmCategoryDO updateObj = BeanUtils.toBean(updateReqVO, BpmCategoryDO.class); + bpmCategoryMapper.updateById(updateObj); + } + + private void validateCategoryNameUnique(BpmCategorySaveReqVO updateReqVO) { + BpmCategoryDO category = bpmCategoryMapper.selectByName(updateReqVO.getName()); + if (category == null + || ObjUtil.equal(category.getId(), updateReqVO.getId())) { + return; + } + throw exception(CATEGORY_NAME_DUPLICATE, updateReqVO.getName()); + } + + private void validateCategoryCodeUnique(BpmCategorySaveReqVO updateReqVO) { + BpmCategoryDO category = bpmCategoryMapper.selectByCode(updateReqVO.getCode()); + if (category == null + || ObjUtil.equal(category.getId(), updateReqVO.getId())) { + return; + } + throw exception(CATEGORY_CODE_DUPLICATE, updateReqVO.getCode()); + } + + @Override + public void deleteCategory(Long id) { + // 校验存在 + validateCategoryExists(id); + // 删除 + bpmCategoryMapper.deleteById(id); + } + + private void validateCategoryExists(Long id) { + if (bpmCategoryMapper.selectById(id) == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + } + + @Override + public BpmCategoryDO getCategory(Long id) { + return bpmCategoryMapper.selectById(id); + } + + @Override + public PageResult getCategoryPage(BpmCategoryPageReqVO pageReqVO) { + return bpmCategoryMapper.selectPage(pageReqVO); + } + + @Override + public List getCategoryListByCode(Collection codes) { + if (CollUtil.isEmpty(codes)) { + return Collections.emptyList(); + } + return bpmCategoryMapper.selectListByCode(codes); + } + + @Override + public List getCategoryListByStatus(Integer status) { + return bpmCategoryMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java new file mode 100644 index 0000000..cf421e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +/** + * 动态表单 Service 接口 + * + * @author @风里雾里 + */ +public interface BpmFormService { + + /** + * 创建动态表单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createForm(@Valid BpmFormSaveReqVO createReqVO); + + /** + * 更新动态表单 + * + * @param updateReqVO 更新信息 + */ + void updateForm(@Valid BpmFormSaveReqVO updateReqVO); + + /** + * 删除动态表单 + * + * @param id 编号 + */ + void deleteForm(Long id); + + /** + * 获得动态表单 + * + * @param id 编号 + * @return 动态表单 + */ + BpmFormDO getForm(Long id); + + /** + * 获得动态表单列表 + * + * @return 动态表单列表 + */ + List getFormList(); + + /** + * 获得动态表单列表 + * + * @param ids 编号 + * @return 动态表单列表 + */ + List getFormList(Collection ids); + + /** + * 获得动态表单 Map + * + * @param ids 编号 + * @return 动态表单 Map + */ + default Map getFormMap(Collection ids) { + return CollectionUtils.convertMap(this.getFormList(ids), BpmFormDO::getId); + } + + /** + * 获得动态表单分页 + * + * @param pageReqVO 分页查询 + * @return 动态表单分页 + */ + PageResult getFormPage(BpmFormPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java new file mode 100644 index 0000000..51d022d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 动态表单 Service 实现类 + * + * @author 风里雾里 + */ +@Service +@Validated +public class BpmFormServiceImpl implements BpmFormService { + + @Resource + private BpmFormMapper formMapper; + + @Override + public Long createForm(BpmFormSaveReqVO createReqVO) { + this.validateFields(createReqVO.getFields()); + // 插入 + BpmFormDO form = BeanUtils.toBean(createReqVO, BpmFormDO.class); + formMapper.insert(form); + // 返回 + return form.getId(); + } + + @Override + public void updateForm(BpmFormSaveReqVO updateReqVO) { + validateFields(updateReqVO.getFields()); + // 校验存在 + validateFormExists(updateReqVO.getId()); + // 更新 + BpmFormDO updateObj = BeanUtils.toBean(updateReqVO, BpmFormDO.class); + formMapper.updateById(updateObj); + } + + @Override + public void deleteForm(Long id) { + // 校验存在 + this.validateFormExists(id); + // 删除 + formMapper.deleteById(id); + } + + private void validateFormExists(Long id) { + if (formMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.FORM_NOT_EXISTS); + } + } + + @Override + public BpmFormDO getForm(Long id) { + return formMapper.selectById(id); + } + + @Override + public List getFormList() { + return formMapper.selectList(); + } + + @Override + public List getFormList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return formMapper.selectBatchIds(ids); + } + + @Override + public PageResult getFormPage(BpmFormPageReqVO pageReqVO) { + return formMapper.selectPage(pageReqVO); + } + + /** + * 校验 Field,避免 field 重复 + * + * @param fields field 数组 + */ + private void validateFields(List fields) { + if (true) { // TODO 芋艿:兼容 Vue3 工作流:因为采用了新的表单设计器,所以暂时不校验 + return; + } + Map fieldMap = new HashMap<>(); // key 是 vModel,value 是 label + for (String field : fields) { + BpmFormFieldRespDTO fieldDTO = JsonUtils.parseObject(field, BpmFormFieldRespDTO.class); + Assert.notNull(fieldDTO); + String oldLabel = fieldMap.put(fieldDTO.getVModel(), fieldDTO.getLabel()); + // 如果不存在,则直接返回 + if (oldLabel == null) { + continue; + } + // 如果存在,则报错 + throw exception(ErrorCodeConstants.FORM_FIELD_REPEAT, oldLabel, fieldDTO.getLabel(), fieldDTO.getVModel()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java new file mode 100644 index 0000000..fb3c943 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Model; + +import javax.validation.Valid; + +/** + * Flowable流程模型接口 + * + * @author yunlongn + */ +public interface BpmModelService { + + /** + * 获得流程模型分页 + * + * @param pageVO 分页查询 + * @return 流程模型分页 + */ + PageResult getModelPage(BpmModelPageReqVO pageVO); + + /** + * 创建流程模型 + * + * @param modelVO 创建信息 + * @param bpmnXml BPMN XML + * @return 创建的流程模型的编号 + */ + String createModel(@Valid BpmModelCreateReqVO modelVO, String bpmnXml); + + /** + * 获得流程模块 + * + * @param id 编号 + * @return 流程模型 + */ + Model getModel(String id); + + /** + * 获得流程模型的 BPMN XML + * + * @param id 编号 + * @return BPMN XML + */ + byte[] getModelBpmnXML(String id); + + /** + * 修改流程模型 + * + * @param updateReqVO 更新信息 + */ + void updateModel(@Valid BpmModelUpdateReqVO updateReqVO); + + /** + * 将流程模型,部署成一个流程定义 + * + * @param id 编号 + */ + void deployModel(String id); + + /** + * 删除模型 + * + * @param id 编号 + */ + void deleteModel(String id); + + /** + * 修改模型的状态,实际更新的部署的流程定义的状态 + * + * @param id 编号 + * @param state 状态 + */ + void updateModelState(String id, Integer state); + + /** + * 获得流程定义编号对应的 BPMN Model + * + * @param processDefinitionId 流程定义编号 + * @return BPMN Model + */ + BpmnModel getBpmnModelByDefinitionId(String processDefinitionId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java new file mode 100644 index 0000000..245fca2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -0,0 +1,280 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ModelQuery; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * Flowable流程模型实现 + * 主要进行 Flowable {@link Model} 的维护 + * + * @author yunlongn + * @author 芋道源码 + * @author jason + */ +@Service +@Validated +@Slf4j +public class BpmModelServiceImpl implements BpmModelService { + + @Resource + private RepositoryService repositoryService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmFormService bpmFormService; + + @Resource + private BpmTaskCandidateInvoker taskCandidateInvoker; + + @Override + public PageResult getModelPage(BpmModelPageReqVO pageVO) { + ModelQuery modelQuery = repositoryService.createModelQuery(); + if (StrUtil.isNotBlank(pageVO.getKey())) { + modelQuery.modelKey(pageVO.getKey()); + } + if (StrUtil.isNotBlank(pageVO.getName())) { + modelQuery.modelNameLike("%" + pageVO.getName() + "%"); // 模糊匹配 + } + if (StrUtil.isNotBlank(pageVO.getCategory())) { + modelQuery.modelCategory(pageVO.getCategory()); + } + // 执行查询 + long count = modelQuery.count(); + if (count == 0) { + return PageResult.empty(count); + } + List models = modelQuery + .modelTenantId(FlowableUtils.getTenantId()) + .orderByCreateTime().desc() + .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(models, count); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { + if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) { + throw exception(MODEL_KEY_VALID); + } + // 校验流程标识已经存在 + Model keyModel = getModelByKey(createReqVO.getKey()); + if (keyModel != null) { + throw exception(MODEL_KEY_EXISTS, createReqVO.getKey()); + } + + // 创建流程定义 + Model model = repositoryService.newModel(); + BpmModelConvert.INSTANCE.copyToCreateModel(model, createReqVO); + model.setTenantId(FlowableUtils.getTenantId()); + // 保存流程定义 + repositoryService.saveModel(model); + // 保存 BPMN XML + saveModelBpmnXml(model, bpmnXml); + return model.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 + public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) { + // 校验流程模型存在 + Model model = getModel(updateReqVO.getId()); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + + // 修改流程定义 + BpmModelConvert.INSTANCE.copyToUpdateModel(model, updateReqVO); + // 更新模型 + repositoryService.saveModel(model); + // 更新 BPMN XML + saveModelBpmnXml(model, updateReqVO.getBpmnXml()); + } + + @Override + @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 + public void deployModel(String id) { + // 1.1 校验流程模型存在 + Model model = getModel(id); + if (ObjectUtils.isEmpty(model)) { + throw exception(MODEL_NOT_EXISTS); + } + // 1.2 校验流程图 + byte[] bpmnBytes = getModelBpmnXML(model.getId()); + validateBpmnXml(bpmnBytes); + // 1.3 校验表单已配 + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmFormDO form = validateFormConfig(metaInfo); + // 1.4 校验任务分配规则已配置 + taskCandidateInvoker.validateBpmnConfig(bpmnBytes); + + // 2.1 创建流程定义 + String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form); + + // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。 + updateProcessDefinitionSuspended(model.getDeploymentId()); + + // 2.3 更新 model 的 deploymentId,进行关联 + ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId); + model.setDeploymentId(definition.getDeploymentId()); + repositoryService.saveModel(model); + } + + private void validateBpmnXml(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + if (bpmnModel == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 1. 没有 StartEvent + StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); + if (startEvent == null) { + throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS); + } + // 2. 校验 UserTask 的 name 都配置了 + List userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + userTasks.forEach(userTask -> { + if (StrUtil.isEmpty(userTask.getName())) { + throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteModel(String id) { + // 校验流程模型存在 + Model model = getModel(id); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 执行删除 + repositoryService.deleteModel(id); + // 禁用流程定义 + updateProcessDefinitionSuspended(model.getDeploymentId()); + } + + @Override + public void updateModelState(String id, Integer state) { + // 1.1 校验流程模型存在 + Model model = getModel(id); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 1.2 校验流程定义存在 + ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); + if (definition == null) { + throw exception(PROCESS_DEFINITION_NOT_EXISTS); + } + + // 2. 更新状态 + processDefinitionService.updateProcessDefinitionState(definition.getId(), state); + } + + @Override + public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) { + return repositoryService.getBpmnModel(processDefinitionId); + } + + /** + * 校验流程表单已配置 + * + * @param metaInfo 流程模型元数据 + * @return 表单配置 + */ + private BpmFormDO validateFormConfig(BpmModelMetaInfoRespDTO metaInfo) { + if (metaInfo == null || metaInfo.getFormType() == null) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + // 校验表单存在 + if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { + if (metaInfo.getFormId() == null) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId()); + if (form == null) { + throw exception(FORM_NOT_EXISTS); + } + return form; + } else { + if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath()) || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + return null; + } + } + + private void saveModelBpmnXml(Model model, String bpmnXml) { + if (StrUtil.isEmpty(bpmnXml)) { + return; + } + repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); + } + + /** + * 挂起 deploymentId 对应的流程定义 + * + * 注意:这里一个 deploymentId 只关联一个流程定义 + * + * @param deploymentId 流程发布Id + */ + private void updateProcessDefinitionSuspended(String deploymentId) { + if (StrUtil.isEmpty(deploymentId)) { + return; + } + ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId); + if (oldDefinition == null) { + return; + } + processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode()); + } + + private Model getModelByKey(String key) { + return repositoryService.createModelQuery() + .modelTenantId(FlowableUtils.getTenantId()) + .modelKey(key).singleResult(); + } + + @Override + public Model getModel(String id) { + return repositoryService.getModel(id); + } + + @Override + public byte[] getModelBpmnXML(String id) { + return repositoryService.getModelEditorSource(id); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java new file mode 100644 index 0000000..5e2e2f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -0,0 +1,162 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * Flowable流程定义接口 + * + * @author yunlong.li + * @author ZJQ + * @author 芋道源码 + */ +public interface BpmProcessDefinitionService { + + /** + * 获得流程定义分页 + * + * @param pageReqVO 分页入参 + * @return 流程定义 Page + */ + PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO); + + /** + * 获得流程定义列表 + * + * @param suspensionState 中断状态 + * @return 流程定义列表 + */ + List getProcessDefinitionListBySuspensionState(Integer suspensionState); + + /** + * 基于流程模型,创建流程定义 + * + * @param model 流程模型 + * @param modelMetaInfo 流程模型元信息 + * @param bpmnBytes BPMN XML 字节数组 + * @param form 表单 + * @return 流程编号 + */ + String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, byte[] bpmnBytes, BpmFormDO form); + + /** + * 更新流程定义状态 + * + * @param id 流程定义的编号 + * @param state 状态 + */ + void updateProcessDefinitionState(String id, Integer state); + + /** + * 获得流程定义对应的 BPMN + * + * @param id 流程定义编号 + * @return BPMN + */ + BpmnModel getProcessDefinitionBpmnModel(String id); + + /** + * 获得流程定义的信息 + * + * @param id 流程定义编号 + * @return 流程定义信息 + */ + BpmProcessDefinitionInfoDO getProcessDefinitionInfo(String id); + + /** + * 获得流程定义的信息 List + * + * @param ids 流程定义编号数组 + * @return 流程额定义信息数组 + */ + List getProcessDefinitionInfoList(Collection ids); + + default Map getProcessDefinitionInfoMap(Set ids) { + return convertMap(getProcessDefinitionInfoList(ids), BpmProcessDefinitionInfoDO::getProcessDefinitionId); + } + + /** + * 获得流程定义编号对应的 ProcessDefinition + * + * @param id 流程定义编号 + * @return 流程定义 + */ + ProcessDefinition getProcessDefinition(String id); + + /** + * 获得 ids 对应的 ProcessDefinition 数组 + * + * @param ids 编号的数组 + * @return 流程定义的数组 + */ + List getProcessDefinitionList(Set ids); + + default Map getProcessDefinitionMap(Set ids) { + return convertMap(getProcessDefinitionList(ids), ProcessDefinition::getId); + } + + /** + * 获得 deploymentId 对应的 ProcessDefinition + * + * @param deploymentId 部署编号 + * @return 流程定义 + */ + ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId); + + /** + * 获得 deploymentIds 对应的 ProcessDefinition 数组 + * + * @param deploymentIds 部署编号的数组 + * @return 流程定义的数组 + */ + List getProcessDefinitionListByDeploymentIds(Set deploymentIds); + + /** + * 获得流程定义标识对应的激活的流程定义 + * + * @param key 流程定义的标识 + * @return 流程定义 + */ + ProcessDefinition getActiveProcessDefinition(String key); + + /** + * 获得 ids 对应的 Deployment Map + * + * @param ids 部署编号的数组 + * @return 流程部署 Map + */ + default Map getDeploymentMap(Set ids) { + return convertMap(getDeploymentList(ids), Deployment::getId); + } + + /** + * 获得 ids 对应的 Deployment 数组 + * + * @param ids 部署编号的数组 + * @return 流程部署的数组 + */ + List getDeploymentList(Set ids); + + /** + * 获得 id 对应的 Deployment + * + * @param id 部署编号 + * @return 流程部署 + */ + Deployment getDeployment(String id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java new file mode 100644 index 0000000..37aa477 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java @@ -0,0 +1,205 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionInfoMapper; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH; +import static java.util.Collections.emptyList; + +/** + * 流程定义实现 + * 主要进行 Flowable {@link ProcessDefinition} 和 {@link Deployment} 的维护 + * + * @author yunlongn + * @author ZJQ + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionService { + + @Resource + private RepositoryService repositoryService; + + @Resource + private BpmProcessDefinitionInfoMapper processDefinitionMapper; + + @Override + public ProcessDefinition getProcessDefinition(String id) { + return repositoryService.getProcessDefinition(id); + } + + @Override + public List getProcessDefinitionList(Set ids) { + return repositoryService.createProcessDefinitionQuery().processDefinitionIds(ids).list(); + } + + @Override + public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) { + if (StrUtil.isEmpty(deploymentId)) { + return null; + } + return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult(); + } + + @Override + public List getProcessDefinitionListByDeploymentIds(Set deploymentIds) { + if (CollUtil.isEmpty(deploymentIds)) { + return emptyList(); + } + return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list(); + } + + @Override + public ProcessDefinition getActiveProcessDefinition(String key) { + return repositoryService.createProcessDefinitionQuery() + .processDefinitionTenantId(FlowableUtils.getTenantId()) + .processDefinitionKey(key).active().singleResult(); + } + + @Override + public List getDeploymentList(Set ids) { + if (CollUtil.isEmpty(ids)) { + return emptyList(); + } + List list = new ArrayList<>(ids.size()); + for (String id : ids) { + addIfNotNull(list, getDeployment(id)); + } + return list; + } + + @Override + public Deployment getDeployment(String id) { + if (StrUtil.isEmpty(id)) { + return null; + } + return repositoryService.createDeploymentQuery().deploymentId(id).singleResult(); + } + + @Override + public String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, + byte[] bpmnBytes, BpmFormDO form) { + // 创建 Deployment 部署 + Deployment deploy = repositoryService.createDeployment() + .key(model.getKey()).name(model.getName()).category(model.getCategory()) + .addBytes(model.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, bpmnBytes) + .tenantId(FlowableUtils.getTenantId()) + .disableSchemaValidation() // 禁用 XML Schema 验证,因为有自定义的属性 + .deploy(); + + // 设置 ProcessDefinition 的 category 分类 + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery() + .deploymentId(deploy.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory()); + // 注意 1,ProcessDefinition 的 key 和 name 是通过 BPMN 中的 的 id 和 name 决定 + // 注意 2,目前该项目的设计上,需要保证 Model、Deployment、ProcessDefinition 使用相同的 key,保证关联性。 + // 否则,会导致 ProcessDefinition 的分页无法查询到。 + if (!Objects.equals(definition.getKey(), model.getKey())) { + throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, model.getKey(), definition.getKey()); + } + if (!Objects.equals(definition.getName(), model.getName())) { + throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, model.getName(), definition.getName()); + } + + // 插入拓展表 + BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) + .setModelId(model.getId()).setProcessDefinitionId(definition.getId()); + if (form != null) { + definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); + } + processDefinitionMapper.insert(definitionDO); + return definition.getId(); + } + + @Override + public void updateProcessDefinitionState(String id, Integer state) { + // 激活 + if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) { + repositoryService.activateProcessDefinitionById(id, false, null); + return; + } + // 挂起 + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) { + // suspendProcessInstances = false,进行中的任务,不进行挂起。 + // 原因:只要新的流程不允许发起即可,老流程继续可以执行。 + repositoryService.suspendProcessDefinitionById(id, false, null); + return; + } + log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state); + } + + @Override + public BpmnModel getProcessDefinitionBpmnModel(String id) { + return repositoryService.getBpmnModel(id); + } + + @Override + public BpmProcessDefinitionInfoDO getProcessDefinitionInfo(String id) { + return processDefinitionMapper.selectByProcessDefinitionId(id); + } + + @Override + public List getProcessDefinitionInfoList(Collection ids) { + return processDefinitionMapper.selectListByProcessDefinitionIds(ids); + } + + @Override + public PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) { + ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); + query.processDefinitionTenantId(FlowableUtils.getTenantId()); + if (StrUtil.isNotBlank(pageVO.getKey())) { + query.processDefinitionKey(pageVO.getKey()); + } + // 执行查询 + long count = query.count(); + if (count == 0) { + return PageResult.empty(count); + } + List list = query.orderByProcessDefinitionVersion().desc() + .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(list, count); + } + + @Override + public List getProcessDefinitionListBySuspensionState(Integer suspensionState) { + // 拼接查询条件 + ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), suspensionState)) { + query.suspended(); + } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), suspensionState)) { + query.active(); + } + // 执行查询 + query.processDefinitionTenantId(FlowableUtils.getTenantId()); + return query.list(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java new file mode 100644 index 0000000..0d8a99e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; + +import javax.validation.Valid; + +/** + * BPM 流程表达式 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessExpressionService { + + /** + * 创建流程表达式 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProcessExpression(@Valid BpmProcessExpressionSaveReqVO createReqVO); + + /** + * 更新流程表达式 + * + * @param updateReqVO 更新信息 + */ + void updateProcessExpression(@Valid BpmProcessExpressionSaveReqVO updateReqVO); + + /** + * 删除流程表达式 + * + * @param id 编号 + */ + void deleteProcessExpression(Long id); + + /** + * 获得流程表达式 + * + * @param id 编号 + * @return 流程表达式 + */ + BpmProcessExpressionDO getProcessExpression(Long id); + + /** + * 获得流程表达式分页 + * + * @param pageReqVO 分页查询 + * @return 流程表达式分页 + */ + PageResult getProcessExpressionPage(BpmProcessExpressionPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java new file mode 100644 index 0000000..f379bfd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessExpressionMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_EXPRESSION_NOT_EXISTS; + +/** + * BPM 流程表达式 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmProcessExpressionServiceImpl implements BpmProcessExpressionService { + + @Resource + private BpmProcessExpressionMapper processExpressionMapper; + + @Override + public Long createProcessExpression(BpmProcessExpressionSaveReqVO createReqVO) { + // 插入 + BpmProcessExpressionDO processExpression = BeanUtils.toBean(createReqVO, BpmProcessExpressionDO.class); + processExpressionMapper.insert(processExpression); + // 返回 + return processExpression.getId(); + } + + @Override + public void updateProcessExpression(BpmProcessExpressionSaveReqVO updateReqVO) { + // 校验存在 + validateProcessExpressionExists(updateReqVO.getId()); + // 更新 + BpmProcessExpressionDO updateObj = BeanUtils.toBean(updateReqVO, BpmProcessExpressionDO.class); + processExpressionMapper.updateById(updateObj); + } + + @Override + public void deleteProcessExpression(Long id) { + // 校验存在 + validateProcessExpressionExists(id); + // 删除 + processExpressionMapper.deleteById(id); + } + + private void validateProcessExpressionExists(Long id) { + if (processExpressionMapper.selectById(id) == null) { + throw exception(PROCESS_EXPRESSION_NOT_EXISTS); + } + } + + @Override + public BpmProcessExpressionDO getProcessExpression(Long id) { + return processExpressionMapper.selectById(id); + } + + @Override + public PageResult getProcessExpressionPage(BpmProcessExpressionPageReqVO pageReqVO) { + return processExpressionMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java new file mode 100644 index 0000000..f9f1020 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; + +import javax.validation.Valid; + +/** + * BPM 流程监听器 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessListenerService { + + /** + * 创建流程监听器 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProcessListener(@Valid BpmProcessListenerSaveReqVO createReqVO); + + /** + * 更新流程监听器 + * + * @param updateReqVO 更新信息 + */ + void updateProcessListener(@Valid BpmProcessListenerSaveReqVO updateReqVO); + + /** + * 删除流程监听器 + * + * @param id 编号 + */ + void deleteProcessListener(Long id); + + /** + * 获得流程监听器 + * + * @param id 编号 + * @return 流程监听器 + */ + BpmProcessListenerDO getProcessListener(Long id); + + /** + * 获得流程监听器分页 + * + * @param pageReqVO 分页查询 + * @return 流程监听器分页 + */ + PageResult getProcessListenerPage(BpmProcessListenerPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java new file mode 100644 index 0000000..e5f47b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessListenerMapper; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerType; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerValueType; +import org.flowable.engine.delegate.JavaDelegate; +import org.flowable.engine.delegate.TaskListener; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 流程监听器 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmProcessListenerServiceImpl implements BpmProcessListenerService { + + @Resource + private BpmProcessListenerMapper processListenerMapper; + + @Override + public Long createProcessListener(BpmProcessListenerSaveReqVO createReqVO) { + // 校验 + validateCreateProcessListenerValue(createReqVO); + // 插入 + BpmProcessListenerDO processListener = BeanUtils.toBean(createReqVO, BpmProcessListenerDO.class); + processListenerMapper.insert(processListener); + return processListener.getId(); + } + + @Override + public void updateProcessListener(BpmProcessListenerSaveReqVO updateReqVO) { + // 校验存在 + validateProcessListenerExists(updateReqVO.getId()); + validateCreateProcessListenerValue(updateReqVO); + // 更新 + BpmProcessListenerDO updateObj = BeanUtils.toBean(updateReqVO, BpmProcessListenerDO.class); + processListenerMapper.updateById(updateObj); + } + + private void validateCreateProcessListenerValue(BpmProcessListenerSaveReqVO createReqVO) { + // class 类型 + if (createReqVO.getValueType().equals(BpmProcessListenerValueType.CLASS.getType())) { + try { + Class clazz = Class.forName(createReqVO.getValue()); + if (createReqVO.getType().equals(BpmProcessListenerType.EXECUTION.getType()) + && !JavaDelegate.class.isAssignableFrom(clazz)) { + throw exception(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, createReqVO.getValue(), + JavaDelegate.class.getName()); + } else if (createReqVO.getType().equals(BpmProcessListenerType.TASK.getType()) + && !TaskListener.class.isAssignableFrom(clazz)) { + throw exception(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, createReqVO.getValue(), + TaskListener.class.getName()); + } + } catch (ClassNotFoundException e) { + throw exception(PROCESS_LISTENER_CLASS_NOT_FOUND, createReqVO.getValue()); + } + return; + } + // 表达式 + if (!StrUtil.startWith(createReqVO.getValue(), "${") || !StrUtil.endWith(createReqVO.getValue(), "}")) { + throw exception(PROCESS_LISTENER_EXPRESSION_INVALID, createReqVO.getValue()); + } + } + + @Override + public void deleteProcessListener(Long id) { + // 校验存在 + validateProcessListenerExists(id); + // 删除 + processListenerMapper.deleteById(id); + } + + private void validateProcessListenerExists(Long id) { + if (processListenerMapper.selectById(id) == null) { + throw exception(PROCESS_LISTENER_NOT_EXISTS); + } + } + + @Override + public BpmProcessListenerDO getProcessListener(Long id) { + return processListenerMapper.selectById(id); + } + + @Override + public PageResult getProcessListenerPage(BpmProcessListenerPageReqVO pageReqVO) { + return processListenerMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java new file mode 100644 index 0000000..967f6e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 用户组 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmUserGroupService { + + /** + * 创建用户组 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createUserGroup(@Valid BpmUserGroupSaveReqVO createReqVO); + + /** + * 更新用户组 + * + * @param updateReqVO 更新信息 + */ + void updateUserGroup(@Valid BpmUserGroupSaveReqVO updateReqVO); + + /** + * 删除用户组 + * + * @param id 编号 + */ + void deleteUserGroup(Long id); + + /** + * 获得用户组 + * + * @param id 编号 + * @return 用户组 + */ + BpmUserGroupDO getUserGroup(Long id); + + /** + * 获得用户组列表 + * + * @param ids 编号 + * @return 用户组列表 + */ + List getUserGroupList(Collection ids); + + /** + * 获得指定状态的用户组列表 + * + * @param status 状态 + * @return 用户组列表 + */ + List getUserGroupListByStatus(Integer status); + + /** + * 获得用户组分页 + * + * @param pageReqVO 分页查询 + * @return 用户组分页 + */ + PageResult getUserGroupPage(BpmUserGroupPageReqVO pageReqVO); + + /** + * 校验用户组们是否有效。如下情况,视为无效: + * 1. 用户组编号不存在 + * 2. 用户组被禁用 + * + * @param ids 用户组编号数组 + */ + void validUserGroups(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java new file mode 100644 index 0000000..3d60dea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_IS_DISABLE; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; + +/** + * 用户组 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmUserGroupServiceImpl implements BpmUserGroupService { + + @Resource + private BpmUserGroupMapper userGroupMapper; + + @Override + public Long createUserGroup(BpmUserGroupSaveReqVO createReqVO) { + BpmUserGroupDO userGroup = BeanUtils.toBean(createReqVO, BpmUserGroupDO.class); + userGroupMapper.insert(userGroup); + return userGroup.getId(); + } + + @Override + public void updateUserGroup(BpmUserGroupSaveReqVO updateReqVO) { + // 校验存在 + validateUserGroupExists(updateReqVO.getId()); + // 更新 + BpmUserGroupDO updateObj = BeanUtils.toBean(updateReqVO, BpmUserGroupDO.class); + userGroupMapper.updateById(updateObj); + } + + @Override + public void deleteUserGroup(Long id) { + // 校验存在 + this.validateUserGroupExists(id); + // 删除 + userGroupMapper.deleteById(id); + } + + private void validateUserGroupExists(Long id) { + if (userGroupMapper.selectById(id) == null) { + throw exception(USER_GROUP_NOT_EXISTS); + } + } + + @Override + public BpmUserGroupDO getUserGroup(Long id) { + return userGroupMapper.selectById(id); + } + + @Override + public List getUserGroupList(Collection ids) { + return userGroupMapper.selectBatchIds(ids); + } + + + @Override + public List getUserGroupListByStatus(Integer status) { + return userGroupMapper.selectListByStatus(status); + } + + @Override + public PageResult getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) { + return userGroupMapper.selectPage(pageReqVO); + } + + @Override + public void validUserGroups(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得用户组信息 + List userGroups = userGroupMapper.selectBatchIds(ids); + Map userGroupMap = convertMap(userGroups, BpmUserGroupDO::getId); + // 校验 + ids.forEach(id -> { + BpmUserGroupDO userGroup = userGroupMap.get(id); + if (userGroup == null) { + throw exception(USER_GROUP_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(userGroup.getStatus())) { + throw exception(USER_GROUP_IS_DISABLE, userGroup.getName()); + } + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java new file mode 100644 index 0000000..1606192 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * Bpm 表单的 Field 表单项 Response DTO + * 字段的定义,可见 https://github.com/JakHuang/form-generator/issues/46 文档 + * + * @author 芋道源码 + */ +@Data +public class BpmFormFieldRespDTO { + + /** + * 表单标题 + */ + private String label; + /** + * 表单字段的属性名,可自定义 + */ + @JsonProperty(value = "vModel") + private String vModel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java new file mode 100644 index 0000000..8ec9dc6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import lombok.Data; + +/** + * BPM 流程 MetaInfo Response DTO + * 主要用于 { Model#setMetaInfo(String)} 的存储 + * + * 最终,它的字段和 {@link cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO} 是一致的 + * + * @author 芋道源码 + */ +@Data +public class BpmModelMetaInfoRespDTO { + + /** + * 流程图标 + */ + private String icon; + /** + * 流程描述 + */ + private String description; + + /** + * 表单类型 + */ + private Integer formType; + /** + * 表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private Long formId; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java new file mode 100644 index 0000000..e7b84c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 流程定义创建 Request DTO + */ +@Data +public class BpmProcessDefinitionCreateReqDTO { + + // ========== 模型相关 ========== + + /** + * 流程模型的编号 + */ + @NotEmpty(message = "流程模型编号不能为空") + private String modelId; + /** + * 流程标识 + */ + @NotEmpty(message = "流程标识不能为空") + private String key; + /** + * 流程名称 + */ + @NotEmpty(message = "流程名称不能为空") + private String name; + /** + * 流程描述 + */ + private String description; + /** + * 流程分类 + */ + @NotEmpty(message = "流程分类不能为空") + private String category; + /** + * BPMN XML + */ + @NotEmpty(message = "BPMN XML 不能为空") + private byte[] bpmnBytes; + + // ========== 表单相关 ========== + + /** + * 表单类型 + */ + @NotNull(message = "表单类型不能为空") + private Integer formType; + /** + * 动态表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private Long formId; + /** + * 表单的配置 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private String formConf; + /** + * 表单项的数组 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private List formFields; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java new file mode 100644 index 0000000..ff51ae3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.service.message; + +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; + +import javax.validation.Valid; + +/** + * BPM 消息 Service 接口 + * + * TODO 芋艿:未来支持消息的可配置;不同的流程,在什么场景下,需要发送什么消息,消息的内容是什么; + * + * @author 芋道源码 + */ +public interface BpmMessageService { + + /** + * 发送流程实例被通过的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenProcessInstanceApprove(@Valid BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO); + + /** + * 发送流程实例被不通过的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenProcessInstanceReject(@Valid BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO); + + /** + * 发送任务被分配的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenTaskAssigned(@Valid BpmMessageSendWhenTaskCreatedReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java new file mode 100644 index 0000000..0323701 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.bpm.service.message; + +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert; +import cn.iocoder.yudao.module.bpm.enums.message.BpmMessageEnum; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * BPM 消息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmMessageServiceImpl implements BpmMessageService { + + @Resource + private SmsSendApi smsSendApi; + + @Resource + private WebProperties webProperties; + + @Override + public void sendMessageWhenProcessInstanceApprove(BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(), + BpmMessageEnum.PROCESS_INSTANCE_APPROVE.getSmsTemplateCode(), templateParams)); + } + + @Override + public void sendMessageWhenProcessInstanceReject(BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("reason", reqDTO.getReason()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(), + BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams)); + } + + @Override + public void sendMessageWhenTaskAssigned(BpmMessageSendWhenTaskCreatedReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("taskName", reqDTO.getTaskName()); + templateParams.put("startUserNickname", reqDTO.getStartUserNickname()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getAssigneeUserId(), + BpmMessageEnum.TASK_ASSIGNED.getSmsTemplateCode(), templateParams)); + } + + private String getProcessInstanceDetailUrl(String taskId) { + return webProperties.getAdminUi().getUrl() + "/bpm/process-instance/detail?id=" + taskId; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java new file mode 100644 index 0000000..7c37734 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送流程实例被通过 Request DTO + */ +@Data +public class BpmMessageSendWhenProcessInstanceApproveReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java new file mode 100644 index 0000000..69a266b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送流程实例被不通过 Request DTO + */ +@Data +public class BpmMessageSendWhenProcessInstanceRejectReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + + /** + * 不通过理由 + */ + @NotEmpty(message = "不通过理由不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java new file mode 100644 index 0000000..7cb0e3d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送任务被分配 Request DTO + */ +@Data +public class BpmMessageSendWhenTaskCreatedReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + @NotEmpty(message = "发起人的昵称") + private String startUserNickname; + + /** + * 流程任务的编号 + */ + @NotEmpty(message = "流程任务的编号不能为空") + private String taskId; + /** + * 流程任务的名字 + */ + @NotEmpty(message = "流程任务的名字不能为空") + private String taskName; + + /** + * 审批人的用户编号 + */ + @NotNull(message = "审批人的用户编号不能为空") + private Long assigneeUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java new file mode 100644 index 0000000..b255e08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; + +import javax.validation.Valid; + +/** + * 请假申请 Service 接口 + * + * @author jason + * @author 芋道源码 + */ +public interface BpmOALeaveService { + + /** + * 创建请假申请 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createLeave(Long userId, @Valid BpmOALeaveCreateReqVO createReqVO); + + /** + * 更新请假申请的状态 + * + * @param id 编号 + * @param status 结果 + */ + void updateLeaveStatus(Long id, Integer status); + + /** + * 获得请假申请 + * + * @param id 编号 + * @return 请假申请 + */ + BpmOALeaveDO getLeave(Long id); + + /** + * 获得请假申请分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页查询 + * @return 请假申请分页 + */ + PageResult getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java new file mode 100644 index 0000000..e86575a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_LEAVE_NOT_EXISTS; + +/** + * OA 请假申请 Service 实现类 + * + * @author jason + * @author 芋道源码 + */ +@Service +@Validated +public class BpmOALeaveServiceImpl implements BpmOALeaveService { + + /** + * OA 请假对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "oa_leave"; + + @Resource + private BpmOALeaveMapper leaveMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) { + // 插入 OA 请假单 + long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays(); + BpmOALeaveDO leave = BeanUtils.toBean(createReqVO, BpmOALeaveDO.class) + .setUserId(userId).setDay(day).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()); + leaveMapper.insert(leave); + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + processInstanceVariables.put("day", day); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId())) + .setStartUserSelectAssignees(createReqVO.getStartUserSelectAssignees())); + + // 将工作流的编号,更新到 OA 请假单中 + leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId)); + return leave.getId(); + } + + @Override + public void updateLeaveStatus(Long id, Integer status) { + validateLeaveExists(id); + leaveMapper.updateById(new BpmOALeaveDO().setId(id).setStatus(status)); + } + + private void validateLeaveExists(Long id) { + if (leaveMapper.selectById(id) == null) { + throw exception(OA_LEAVE_NOT_EXISTS); + } + } + + @Override + public BpmOALeaveDO getLeave(Long id) { + return leaveMapper.selectById(id); + } + + @Override + public PageResult getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO) { + return leaveMapper.selectPage(userId, pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java new file mode 100644 index 0000000..912479a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.service.oa.listener; + +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * OA 请假单的结果的监听器实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmOALeaveStatusListener extends BpmProcessInstanceStatusEventListener { + + @Resource + private BpmOALeaveService leaveService; + + @Override + protected String getProcessDefinitionKey() { + return BpmOALeaveServiceImpl.PROCESS_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceStatusEvent event) { + leaveService.updateLeaveStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java new file mode 100644 index 0000000..4bed164 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import org.flowable.engine.history.HistoricActivityInstance; + +import java.util.List; + +/** + * BPM 活动实例 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmActivityService { + + /** + * 获得指定流程实例的活动实例列表 + * + * @param processInstanceId 流程实例的编号 + * @return 活动实例列表 + */ + List getActivityListByProcessInstanceId(String processInstanceId); + + /** + * 获得执行编号对应的活动实例 + * + * @param executionId 执行编号 + * @return 活动实例 + */ + List getHistoricActivityListByExecutionId(String executionId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java new file mode 100644 index 0000000..c06445e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import cn.iocoder.yudao.module.bpm.convert.task.BpmActivityConvert; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + + +/** + * BPM 活动实例 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +@Validated +public class BpmActivityServiceImpl implements BpmActivityService { + + @Resource + private HistoryService historyService; + + @Override + public List getActivityListByProcessInstanceId(String processInstanceId) { + List activityList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).list(); + return BpmActivityConvert.INSTANCE.convertList(activityList); + } + + @Override + public List getHistoricActivityListByExecutionId(String executionId) { + return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java new file mode 100644 index 0000000..bd84490 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; + +import java.util.Collection; + +/** + * 流程抄送 Service 接口 + * + * 现在是在审批的时候进行流程抄送 + */ +public interface BpmProcessInstanceCopyService { + + /** + * 流程实例的抄送 + * + * @param userIds 抄送的用户编号 + * @param taskId 流程任务编号 + */ + void createProcessInstanceCopy(Collection userIds, String taskId); + + /** + * 获得抄送的流程的分页 + * + * @param userId 当前登录用户 + * @param pageReqVO 分页请求 + * @return 抄送的分页结果 + */ + PageResult getProcessInstanceCopyPage(Long userId, + BpmProcessInstanceCopyPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java new file mode 100644 index 0000000..5d73470 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceCopyMapper; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 流程抄送 Service 实现类 + * + * @author kyle + */ +@Service +@Validated +@Slf4j +public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService { + + @Resource + private BpmProcessInstanceCopyMapper processInstanceCopyMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmTaskService taskService; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessInstanceService processInstanceService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessDefinitionService processDefinitionService; + + @Override + public void createProcessInstanceCopy(Collection userIds, String taskId) { + // 1.1 校验任务存在 + Task task = taskService.getTask(taskId); + if (ObjectUtil.isNull(task)) { + throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); + } + // 1.2 校验流程实例存在 + String processInstanceId = task.getProcessInstanceId(); + ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId); + if (processInstance == null) { + throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); + } + // 1.3 校验流程定义存在 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + processInstance.getProcessDefinitionId()); + if (processDefinition == null) { + throw exception(ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS); + } + + // 2. 创建抄送流程 + List copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO() + .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId())) + .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName()) + .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName())); + processInstanceCopyMapper.insertBatch(copyList); + } + + @Override + public PageResult getProcessInstanceCopyPage(Long userId, + BpmProcessInstanceCopyPageReqVO pageReqVO) { + return processInstanceCopyMapper.selectPage(userId, pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java new file mode 100644 index 0000000..43e44aa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -0,0 +1,144 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; +import org.flowable.engine.delegate.event.FlowableCancelledEvent; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 流程实例 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessInstanceService { + + /** + * 获得流程实例 + * + * @param id 流程实例的编号 + * @return 流程实例 + */ + ProcessInstance getProcessInstance(String id); + + /** + * 获得流程实例列表 + * + * @param ids 流程实例的编号集合 + * @return 流程实例列表 + */ + List getProcessInstances(Set ids); + + /** + * 获得流程实例 Map + * + * @param ids 流程实例的编号集合 + * @return 流程实例列表 Map + */ + default Map getProcessInstanceMap(Set ids) { + return convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); + } + + /** + * 获得历史的流程实例 + * + * @param id 流程实例的编号 + * @return 历史的流程实例 + */ + HistoricProcessInstance getHistoricProcessInstance(String id); + + /** + * 获得历史的流程实例列表 + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 + */ + List getHistoricProcessInstances(Set ids); + + /** + * 获得历史的流程实例 Map + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 Map + */ + default Map getHistoricProcessInstanceMap(Set ids) { + return convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); + } + + /** + * 获得流程实例的分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程实例的分页 + */ + PageResult getProcessInstancePage(Long userId, + @Valid BpmProcessInstancePageReqVO pageReqVO); + + /** + * 创建流程实例(提供给前端) + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO); + + /** + * 创建流程实例(提供给内部) + * + * @param userId 用户编号 + * @param createReqDTO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO); + + /** + * 发起人取消流程实例 + * + * @param userId 用户编号 + * @param cancelReqVO 取消信息 + */ + void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); + + /** + * 管理员取消流程实例 + * + * @param userId 用户编号 + * @param cancelReqVO 取消信息 + */ + void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO); + + /** + * 更新 ProcessInstance 拓展记录为取消 + * + * @param event 流程取消事件 + */ + void updateProcessInstanceWhenCancel(FlowableCancelledEvent event); + + /** + * 更新 ProcessInstance 拓展记录为完成 + * + * @param instance 流程任务 + */ + void updateProcessInstanceWhenApprove(ProcessInstance instance); + + /** + * 更新 ProcessInstance 拓展记录为不通过 + * + * @param id 流程编号 + * @param reason 理由。例如说,审批不通过时,需要传递该值 + */ + void updateProcessInstanceReject(String id, String reason); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java new file mode 100644 index 0000000..a95e6fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } } \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java new file mode 100644 index 0000000..e9a55c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -0,0 +1,186 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import org.flowable.bpmn.model.UserTask; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 流程任务实例 Service 接口 + * + * @author jason + * @author 芋道源码 + */ +public interface BpmTaskService { + + /** + * 获得待办的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程任务分页 + */ + PageResult getTaskTodoPage(Long userId, BpmTaskPageReqVO pageReqVO); + + /** + * 获得已办的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程任务分页 + */ + PageResult getTaskDonePage(Long userId, BpmTaskPageReqVO pageReqVO); + + /** + * 获得全部的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程任务分页 + */ + PageResult getTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); + + /** + * 获得流程任务 Map + * + * @param processInstanceIds 流程实例的编号数组 + * @return 流程任务 Map + */ + default Map> getTaskMapByProcessInstanceIds(List processInstanceIds) { + return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds), + Task::getProcessInstanceId); + } + + /** + * 获得流程任务列表 + * + * @param processInstanceIds 流程实例的编号数组 + * @return 流程任务列表 + */ + List getTasksByProcessInstanceIds(List processInstanceIds); + + /** + * 获得指定流程实例的流程任务列表,包括所有状态的 + * + * @param processInstanceId 流程实例的编号 + * @return 流程任务列表 + */ + List getTaskListByProcessInstanceId(String processInstanceId); + + /** + * 通过任务 + * + * @param userId 用户编号 + * @param reqVO 通过请求 + */ + void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO); + + /** + * 不通过任务 + * + * @param userId 用户编号 + * @param reqVO 不通过请求 + */ + void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); + + /** + * 将流程任务分配给指定用户 + * + * @param userId 用户编号 + * @param reqVO 分配请求 + */ + void transferTask(Long userId, BpmTaskTransferReqVO reqVO); + + /** + * 更新 Task 状态,在创建时 + * + * @param task 任务实体 + */ + void updateTaskStatusWhenCreated(Task task); + + /** + * 更新 Task 状态,在取消时 + * + * @param taskId 任务的编号 + */ + void updateTaskStatusWhenCanceled(String taskId); + + /** + * 更新 Task 拓展记录,并发送通知 + * + * @param task 任务实体 + */ + void updateTaskExtAssign(Task task); + + /** + * 获取任务 + * + * @param id 任务编号 + * @return 任务 + */ + Task getTask(String id); + + /** + * 获取当前任务的可回退的 UserTask 集合 + * + * @param id 当前的任务 ID + * @return 可以回退的节点列表 + */ + List getUserTaskListByReturn(String id); + + /** + * 将任务回退到指定的 targetDefinitionKey 位置 + * + * @param userId 用户编号 + * @param reqVO 回退的任务key和当前所在的任务ID + */ + void returnTask(Long userId, BpmTaskReturnReqVO reqVO); + + /** + * 将指定任务委派给其他人处理,等接收人处理后再回到原审批人手中审批 + * + * @param userId 用户编号 + * @param reqVO 被委派人和被委派的任务编号理由参数 + */ + void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO); + + /** + * 任务加签 + * + * @param userId 被加签的用户和任务 ID,加签类型 + * @param reqVO 当前用户 ID + */ + void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO); + + /** + * 任务减签 + * + * @param userId 当前用户ID + * @param reqVO 被减签的任务 ID,理由 + */ + void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO); + + /** + * 获取指定任务的子任务列表 + * + * @param parentTaskId 父任务ID + * @return 子任务列表 + */ + List getTaskListByParentTaskId(String parentTaskId); + + /** + * 通过任务 ID,查询任务名 Map + * + * @param taskIds 任务 ID + * @return 任务 ID 与名字的 Map + */ + Map getTaskNameByTaskIds(Collection taskIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java new file mode 100644 index 0000000..7da366a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -0,0 +1,822 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; +import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; +import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.HistoryService; +import org.flowable.engine.ManagementService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.DelegationState; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * 流程任务实例 Service 实现类 + * + * @author 芋道源码 + * @author jason + */ +@Slf4j +@Service +public class BpmTaskServiceImpl implements BpmTaskService { + + @Resource + private TaskService taskService; + @Resource + private HistoryService historyService; + @Resource + private RuntimeService runtimeService; + @Resource + private ManagementService managementService; + + @Resource + private BpmProcessInstanceService processInstanceService; + @Resource + private BpmProcessInstanceCopyService processInstanceCopyService; + @Resource + private BpmModelService bpmModelService; + @Resource + private BpmMessageService messageService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + public PageResult getTaskTodoPage(Long userId, BpmTaskPageReqVO pageVO) { + TaskQuery taskQuery = taskService.createTaskQuery() + .taskAssignee(String.valueOf(userId)) // 分配给自己 + .active() + .includeProcessVariables() + .orderByTaskCreateTime().desc(); // 创建时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); + } + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); + } + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(tasks, count); + } + + @Override + public PageResult getTaskDonePage(Long userId, BpmTaskPageReqVO pageVO) { + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery() + .finished() // 已完成 + .taskAssignee(String.valueOf(userId)) // 分配给自己 + .includeTaskLocalVariables() + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); + } + // 执行查询 + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); + } + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(tasks, count); + } + + @Override + public PageResult getTaskPage(Long userId, BpmTaskPageReqVO pageVO) { + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery() + .includeTaskLocalVariables() + .taskTenantId(FlowableUtils.getTenantId()) + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); + } + // 执行查询 + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); + } + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(tasks, count); + } + + @Override + public List getTasksByProcessInstanceIds(List processInstanceIds) { + if (CollUtil.isEmpty(processInstanceIds)) { + return Collections.emptyList(); + } + return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list(); + } + + @Override + public List getTaskListByProcessInstanceId(String processInstanceId) { + List tasks = historyService.createHistoricTaskInstanceQuery() + .includeTaskLocalVariables() + .processInstanceId(processInstanceId) + .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序 + .list(); + if (CollUtil.isEmpty(tasks)) { + return Collections.emptyList(); + } + return tasks; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { + // 1.1 校验任务存在 + Task task = validateTask(userId, reqVO.getId()); + // 1.2 校验流程实例存在 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + + // 2. 抄送用户 + if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) { + processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId()); + } + + // 情况一:被委派的任务,不调用 complete 去完成任务 + if (DelegationState.PENDING.equals(task.getDelegationState())) { + approveDelegateTask(reqVO, task); + return; + } + + // 情况二:审批有【后】加签的任务 + if (BpmTaskSignTypeEnum.AFTER.getType().equals(task.getScopeType())) { + approveAfterSignTask(task, reqVO); + return; + } + + // 情况三:审批普通的任务。大多数情况下,都是这样 + // 3.1 更新 task 状态、原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); + // 3.2 添加评论 + taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), + BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); + // 3.3 调用 BPM complete 去完成任务 + // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 + if (CollUtil.isNotEmpty(reqVO.getVariables())) { + Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); + taskService.complete(task.getId(), variables, true); + } else { + taskService.complete(task.getId()); + } + + // 【加签专属】处理加签任务 + handleParentTaskIfSign(task.getParentTaskId()); + } + + /** + * 审批通过存在“后加签”的任务。 + *

+ * 注意:该任务不能马上完成,需要一个中间状态(APPROVING),并激活剩余所有子任务(PROCESS)为可审批处理 + * 如果马上完成,则会触发下一个任务,甚至如果没有下一个任务则流程实例就直接结束了! + * + * @param task 当前任务 + * @param reqVO 前端请求参数 + */ + private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { + // 更新父 task 状态 + 原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVING.getStatus(), reqVO.getReason()); + + // 2. 激活子任务 + List childrenTaskList = getTaskListByParentTaskId(task.getId()); + for (Task childrenTask : childrenTaskList) { + taskService.resolveTask(childrenTask.getId()); + // 更新子 task 状态 + updateTaskStatus(childrenTask.getId(), BpmTaskStatusEnum.RUNNING.getStatus()); + } + } + + /** + * 如果父任务是有前后【加签】的任务,如果它【加签】出来的子任务都被处理,需要处理父任务: + * + * 1. 如果是【向前】加签,则需要重新激活父任务,让它可以被审批 + * 2. 如果是【向后】加签,则需要完成父任务,让它完成审批 + * + * @param parentTaskId 父任务编号 + */ + private void handleParentTaskIfSign(String parentTaskId) { + if (StrUtil.isBlank(parentTaskId)) { + return; + } + // 1.1 判断是否还有子任务。如果没有,就不处理 + Long childrenTaskCount = getTaskCountByParentTaskId(parentTaskId); + if (childrenTaskCount > 0) { + return; + } + // 1.2 只处理加签的父任务 + Task parentTask = validateTaskExist(parentTaskId); + String scopeType = parentTask.getScopeType(); + if (BpmTaskSignTypeEnum.of(scopeType) == null) { + return; + } + + // 2. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 + TaskEntityImpl parentTaskImpl = (TaskEntityImpl) parentTask; + parentTaskImpl.setScopeType(null); + taskService.saveTask(parentTaskImpl); + + // 3.1 情况一:处理向【向前】加签 + if (BpmTaskSignTypeEnum.BEFORE.getType().equals(scopeType)) { + // 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批 + taskService.resolveTask(parentTaskId); + // 3.1.2 更新流程任务 status + updateTaskStatus(parentTaskId, BpmTaskStatusEnum.RUNNING.getStatus()); + // 3.2 情况二:处理向【向后】加签 + } else if (BpmTaskSignTypeEnum.AFTER.getType().equals(scopeType)) { + // 只有 parentTask 处于 APPROVING 的情况下,才可以继续 complete 完成 + // 否则,一个未审批的 parentTask 任务,在加签出来的任务都被减签的情况下,就直接完成审批,这样会存在问题 + Integer status = (Integer) parentTask.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (ObjectUtil.notEqual(status, BpmTaskStatusEnum.APPROVING.getStatus())) { + return; + } + // 3.2.2 完成自己(因为它已经没有子任务,所以也可以完成) + updateTaskStatus(parentTaskId, BpmTaskStatusEnum.APPROVE.getStatus()); + taskService.complete(parentTaskId); + } + + // 4. 递归处理父任务 + handleParentTaskIfSign(parentTask.getParentTaskId()); + } + + /** + * 审批被委派的任务 + * + * @param reqVO 前端请求参数,包含当前任务ID,审批意见等 + * @param task 当前被审批的任务 + */ + private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) { + // 1. 添加审批意见 + AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()); + AdminUserRespDTO ownerUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); // 发起委托的用户 + Assert.notNull(ownerUser, "委派任务找不到原审批人,需要检查数据"); + taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_END.getType(), + BpmCommentTypeEnum.DELEGATE_END.formatComment(currentUser.getNickname(), ownerUser.getNickname(), reqVO.getReason())); + + // 2.1 调用 resolveTask 完成任务。 + // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee + taskService.resolveTask(task.getId()); + // 2.2 更新 task 状态 + 原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus(), reqVO.getReason()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { + // 1.1 校验任务存在 + Task task = validateTask(userId, reqVO.getId()); + // 1.2 校验流程实例存在 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + + // 2.1 更新流程实例为不通过 + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.REJECT.getStatus(), reqVO.getReason()); + // 2.2 添加评论 + taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), + BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); + + // 3. 更新流程实例,审批不通过! + processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); + } + + /** + * 更新流程任务的 status 状态 + * + * @param id 任务编号 + * @param status 状态 + */ + private void updateTaskStatus(String id, Integer status) { + taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status); + } + + /** + * 更新流程任务的 status 状态、reason 理由 + * + * @param id 任务编号 + * @param status 状态 + * @param reason 理由(审批通过、审批不通过的理由) + */ + private void updateTaskStatusAndReason(String id, Integer status, String reason) { + updateTaskStatus(id, status); + taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_REASON, reason); + } + + /** + * 校验任务是否存在,并且是否是分配给自己的任务 + * + * @param userId 用户 id + * @param taskId task id + */ + private Task validateTask(Long userId, String taskId) { + Task task = validateTaskExist(taskId); + if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) { + throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF); + } + return task; + } + + @Override + public void updateTaskStatusWhenCreated(Task task) { + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (status != null) { + log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status); + return; + } + updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus()); + } + + @Override + public void updateTaskStatusWhenCanceled(String taskId) { + Task task = getTask(taskId); + // 1. 可能只是活动,不是任务,所以查询不到 + if (task == null) { + log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", taskId); + return; + } + + // 2. 更新 task 状态 + 原因 + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (BpmTaskStatusEnum.isEndStatus(status)) { + log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status); + return; + } + updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason()); + // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 + } + + @Override + public void updateTaskExtAssign(Task task) { + // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + if (StrUtil.isEmpty(task.getAssignee())) { + return; + } + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); + } + + }); + } + + private Task validateTaskExist(String id) { + Task task = getTask(id); + if (task == null) { + throw exception(TASK_NOT_EXISTS); + } + return task; + } + + @Override + public Task getTask(String id) { + return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult(); + } + + private HistoricTaskInstance getHistoricTask(String id) { + return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult(); + } + + @Override + public List getUserTaskListByReturn(String id) { + // 1.1 校验当前任务 task 存在 + Task task = validateTaskExist(id); + // 1.2 根据流程定义获取流程模型信息 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); + if (source == null) { + throw exception(TASK_NOT_EXISTS); + } + + // 2.1 查询该任务的前置任务节点的 key 集合 + List previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null); + if (CollUtil.isEmpty(previousUserList)) { + return Collections.emptyList(); + } + // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回 + previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null)); + return previousUserList; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void returnTask(Long userId, BpmTaskReturnReqVO reqVO) { + // 1.1 当前任务 task + Task task = validateTask(userId, reqVO.getId()); + if (task.isSuspended()) { + throw exception(TASK_IS_PENDING); + } + // 1.2 校验源头和目标节点的关系,并返回目标元素 + FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), + reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId()); + + // 2. 调用 Flowable 框架的回退逻辑 + returnTask(task, targetElement, reqVO); + } + + /** + * 回退流程节点时,校验目标任务节点是否可回退 + * + * @param sourceKey 当前任务节点 Key + * @param targetKey 目标任务节点 key + * @param processDefinitionId 当前流程定义 ID + * @return 目标任务节点元素 + */ + private FlowElement validateTargetTaskCanReturn(String sourceKey, String targetKey, String processDefinitionId) { + // 1.1 获取流程模型信息 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId); + // 1.3 获取当前任务节点元素 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, sourceKey); + // 1.3 获取跳转的节点元素 + FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, targetKey); + if (target == null) { + throw exception(TASK_TARGET_NODE_NOT_EXISTS); + } + + // 2.2 只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回 + if (!BpmnModelUtils.isSequentialReachable(source, target, null)) { + throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR); + } + return target; + } + + /** + * 执行回退逻辑 + * + * @param currentTask 当前回退的任务 + * @param targetElement 需要回退到的目标任务 + * @param reqVO 前端参数封装 + */ + public void returnTask(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) { + // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤 + // 1.1 获取所有正常进行的任务节点 Key + List taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list(); + List runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey); + // 1.2 通过 targetElement 的出口连线,计算在 runTaskKeyList 有哪些 key 需要被撤回 + // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F + List returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null); + List returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId); + + // 2. 给当前要被回退的 task 数组,设置回退意见 + taskList.forEach(task -> { + // 需要排除掉,不需要设置回退意见的任务 + if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { + return; + } + // 2.1 添加评论 + taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(), + BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason())); + // 2.2 更新 task 状态 + 原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RETURN.getStatus(), reqVO.getReason()); + }); + + // 3. 执行驳回 + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(currentTask.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多) + reqVO.getTargetTaskDefinitionKey()) // targetKey 跳转到的节点(1) + .changeState(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO) { + String taskId = reqVO.getId(); + // 1.1 校验任务 + Task task = validateTask(userId, reqVO.getId()); + if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) { // 校验当前审批人和被委派人不是同一人 + throw exception(TASK_DELEGATE_FAIL_USER_REPEAT); + } + // 1.2 校验目标用户存在 + AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId()); + if (delegateUser == null) { + throw exception(TASK_DELEGATE_FAIL_USER_NOT_EXISTS); + } + + // 2. 添加委托意见 + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); + taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START.getType(), + BpmCommentTypeEnum.DELEGATE_START.formatComment(currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason())); + + // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) + taskService.setOwner(taskId, task.getAssignee()); + // 3.2 执行委派,将任务委派给 delegateUser + taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString()); + // 3.3 更新 task 状态。 + // 为什么不更新原因?因为原因目前主要给审批通过、不通过时使用 + updateTaskStatus(taskId, BpmTaskStatusEnum.DELEGATE.getStatus()); + } + + @Override + public void transferTask(Long userId, BpmTaskTransferReqVO reqVO) { + String taskId = reqVO.getId(); + // 1.1 校验任务 + Task task = validateTask(userId, reqVO.getId()); + if (task.getAssignee().equals(reqVO.getAssigneeUserId().toString())) { // 校验当前审批人和被转派人不是同一人 + throw exception(TASK_TRANSFER_FAIL_USER_REPEAT); + } + // 1.2 校验目标用户存在 + AdminUserRespDTO assigneeUser = adminUserApi.getUser(reqVO.getAssigneeUserId()); + if (assigneeUser == null) { + throw exception(TASK_TRANSFER_FAIL_USER_NOT_EXISTS); + } + + // 2. 添加委托意见 + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); + taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.TRANSFER.getType(), + BpmCommentTypeEnum.TRANSFER.formatComment(currentUser.getNickname(), assigneeUser.getNickname(), reqVO.getReason())); + + // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) + taskService.setOwner(taskId, task.getAssignee()); + // 3.2 执行转派(审批人),将任务转派给 assigneeUser + // 委托( delegate)和转派(transfer)的差别,就在这块的调用!!!! + taskService.setAssignee(taskId, reqVO.getAssigneeUserId().toString()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO) { + // 1. 获取和校验任务 + TaskEntityImpl taskEntity = validateTaskCanCreateSign(userId, reqVO); + List userList = adminUserApi.getUserList(reqVO.getUserIds()); + if (CollUtil.isEmpty(userList)) { + throw exception(TASK_SIGN_CREATE_USER_NOT_EXIST); + } + + // 2. 处理当前任务 + // 2.1 开启计数功能,主要用于为了让表 ACT_RU_TASK 中的 SUB_TASK_COUNT_ 字段记录下总共有多少子任务,后续可能有用 + taskEntity.setCountEnabled(true); + // 2.2 向前加签,设置 owner,置空 assign。等子任务都完成后,再调用 resolveTask 重新将 owner 设置为 assign + // 原因是:不能和向前加签的子任务一起审批,需要等前面的子任务都完成才能审批 + if (reqVO.getType().equals(BpmTaskSignTypeEnum.BEFORE.getType())) { + taskEntity.setOwner(taskEntity.getAssignee()); + taskEntity.setAssignee(null); + } + // 2.4 记录加签方式,完成任务时需要用到判断 + taskEntity.setScopeType(reqVO.getType()); + // 2.5 保存当前任务修改后的值 + taskService.saveTask(taskEntity); + // 2.6 更新 task 状态为 WAIT,只有在向前加签的时候 + if (reqVO.getType().equals(BpmTaskSignTypeEnum.BEFORE.getType())) { + updateTaskStatus(taskEntity.getId(), BpmTaskStatusEnum.WAIT.getStatus()); + } + + // 3. 创建加签任务 + createSignTaskList(convertList(reqVO.getUserIds(), String::valueOf), taskEntity); + + // 4. 记录加签的评论到 task 任务 + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); + String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), + currentUser.getNickname(), BpmTaskSignTypeEnum.nameOfType(reqVO.getType()), + String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); + taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), BpmCommentTypeEnum.ADD_SIGN.getType(), comment); + } + + /** + * 校验任务是否可以加签,主要校验加签类型是否一致: + *

+ * 1. 如果存在“向前加签”的任务,则不能“向后加签” + * 2. 如果存在“向后加签”的任务,则不能“向前加签” + * + * @param userId 当前用户 ID + * @param reqVO 请求参数,包含任务 ID 和加签类型 + * @return 当前任务 + */ + private TaskEntityImpl validateTaskCanCreateSign(Long userId, BpmTaskSignCreateReqVO reqVO) { + TaskEntityImpl taskEntity = (TaskEntityImpl) validateTask(userId, reqVO.getId()); + // 向前加签和向后加签不能同时存在 + if (taskEntity.getScopeType() != null + && ObjectUtil.notEqual(taskEntity.getScopeType(), reqVO.getType())) { + throw exception(TASK_SIGN_CREATE_TYPE_ERROR, + BpmTaskSignTypeEnum.nameOfType(taskEntity.getScopeType()), BpmTaskSignTypeEnum.nameOfType(reqVO.getType())); + } + + // 同一个 key 的任务,审批人不重复 + List taskList = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()) + .taskDefinitionKey(taskEntity.getTaskDefinitionKey()).list(); + List currentAssigneeList = convertListByFlatMap(taskList, task -> // 需要考虑 owner 的情况,因为向后加签时,它暂时没 assignee 而是 owner + Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); + if (CollUtil.containsAny(currentAssigneeList, reqVO.getUserIds())) { + List userList = adminUserApi.getUserList( CollUtil.intersection(currentAssigneeList, reqVO.getUserIds())); + throw exception(TASK_SIGN_CREATE_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname))); + } + return taskEntity; + } + + /** + * 创建加签子任务 + * + * @param userIds 被加签的用户 ID + * @param taskEntity 被加签的任务 + */ + private void createSignTaskList(List userIds, TaskEntityImpl taskEntity) { + if (CollUtil.isEmpty(userIds)) { + return; + } + // 创建加签人的新任务,全部基于 taskEntity 为父任务来创建 + for (String addSignId : userIds) { + if (StrUtil.isBlank(addSignId)) { + continue; + } + createSignTask(taskEntity, addSignId); + } + } + + /** + * 创建加签子任务 + * + * @param parentTask 父任务 + * @param assignee 子任务的执行人 + */ + private void createSignTask(TaskEntityImpl parentTask, String assignee) { + // 1. 生成子任务 + TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); + BpmTaskConvert.INSTANCE.copyTo(parentTask, task); + + // 2.1 向前加签,设置审批人 + if (BpmTaskSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) { + task.setAssignee(assignee); + // 2.2 向后加签,设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 + } else { + task.setOwner(assignee); + } + // 2.3 保存子任务 + taskService.saveTask(task); + + // 3. 向后前签,设置子任务的状态为 WAIT,因为需要等父任务审批完 + if (BpmTaskSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { + updateTaskStatus(task.getId(), BpmTaskStatusEnum.WAIT.getStatus()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO) { + // 1.1 校验 task 可以被减签 + Task task = validateTaskCanSignDelete(reqVO.getId()); + // 1.2 校验取消人存在 + AdminUserRespDTO cancelUser = null; + if (StrUtil.isNotBlank(task.getAssignee())) { + cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())); + } + if (cancelUser == null && StrUtil.isNotBlank(task.getOwner())) { + cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); + } + Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); + + // 2.1 获得子任务列表,包括子任务的子任务 + List childTaskList = getAllChildTaskList(task); + childTaskList.add(task); + // 2.2 更新子任务为已取消 + String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname()); + childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), cancelReason)); + // 2.3 删除任务和所有子任务 + taskService.deleteTasks(convertList(childTaskList, Task::getId)); + + // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 + AdminUserRespDTO user = adminUserApi.getUser(userId); + taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType(), + StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname())); + + // 4. 处理当前任务的父任务 + handleParentTaskIfSign(task.getParentTaskId()); + } + + /** + * 校验任务是否能被减签 + * + * @param id 任务编号 + * @return 任务信息 + */ + private Task validateTaskCanSignDelete(String id) { + Task task = validateTaskExist(id); + if (task.getParentTaskId() == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); + } + Task parentTask = getTask(task.getParentTaskId()); + if (parentTask == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); + } + if (BpmTaskSignTypeEnum.of(parentTask.getScopeType()) == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); + } + return task; + } + + /** + * 获得所有子任务列表 + * + * @param parentTask 父任务 + * @return 所有子任务列表 + */ + private List getAllChildTaskList(Task parentTask) { + List result = new ArrayList<>(); + // 1. 递归获取子级 + Stack stack = new Stack<>(); + stack.push(parentTask); + // 2. 递归遍历 + for (int i = 0; i < Short.MAX_VALUE; i++) { + if (stack.isEmpty()) { + break; + } + // 2.1 获取子任务们 + Task task = stack.pop(); + List childTaskList = getTaskListByParentTaskId(task.getId()); + // 2.2 如果非空,则添加到 stack 进一步递归 + if (CollUtil.isNotEmpty(childTaskList)) { + stack.addAll(childTaskList); + result.addAll(childTaskList); + } + } + return result; + } + + @Override + public List getTaskListByParentTaskId(String parentTaskId) { + String tableName = managementService.getTableName(TaskEntity.class); + // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询 + String sql = "select ID_,NAME_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); + } + + /** + * 获取子任务个数 + * + * @param parentTaskId 父任务 ID + * @return 剩余子任务个数 + */ + private Long getTaskCountByParentTaskId(String parentTaskId) { + String tableName = managementService.getTableName(TaskEntity.class); + String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}"; + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count(); + } + + @Override + public Map getTaskNameByTaskIds(Collection taskIds) { + if (CollUtil.isEmpty(taskIds)) { + return Collections.emptyMap(); + } + List tasks = taskService.createTaskQuery().taskIds(taskIds).list(); + return convertMap(tasks, Task::getId, Task::getName); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java new file mode 100644 index 0000000..702dce3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateUserStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * {@link BpmTaskCandidateInvoker} 的单元测试 + * + * @author 芋道源码 + */ +public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateInvoker taskCandidateInvoker; + + @Mock + private AdminUserApi adminUserApi; + @Spy + private BpmTaskCandidateStrategy strategy = new BpmTaskCandidateUserStrategy(); + @Spy + private List strategyList = Collections.singletonList(strategy); + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法(DelegateExecution) + UserTask userTask = mock(UserTask.class); + when(execution.getCurrentFlowElement()).thenReturn(userTask); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY))) + .thenReturn(BpmTaskCandidateStrategyEnum.USER.getStrategy().toString()); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM))) + .thenReturn(param); + // mock 方法(adminUserApi) + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap); + + // 调用 + Set results = taskCandidateInvoker.calculateUsers(execution); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + + @Test + public void testRemoveDisableUsers() { + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 + Set assigneeUserIds = asSet(1L, 2L, 3L); + // mock 方法 + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); + + // 调用 + taskCandidateInvoker.removeDisableUsers(assigneeUserIds); + // 断言 + assertEquals(asSet(1L), assigneeUserIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java new file mode 100644 index 0000000..f7eac7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskAssignLeaderExpression expression; + + @Mock + private AdminUserApi adminUserApi; + @Mock + private DeptApi deptApi; + + @Mock + private BpmProcessInstanceService processInstanceService; + + @Test + public void testCalculateUsers_noDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); + // mock 方法(getStartUserDept)没有部门 + when(deptApi.getDept(eq(10L))).thenReturn(null); + + // 调用 + Set result = expression.calculateUsers(execution, 1); + // 断言 + assertEquals(0, result.size()); + } + + @Test + public void testCalculateUsers_noParentDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) + .setLeaderUserId(20L)); + // mock 方法(getDept) + when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); + when(deptApi.getDept(eq(100L))).thenReturn(null); + + // 调用 + Set result = expression.calculateUsers(execution, 2); + // 断言 + assertEquals(asSet(20L), result); + } + + @Test + public void testCalculateUsers_existParentDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) + .setLeaderUserId(20L)); + when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); + // mock 方法(父 dept) + DeptRespDTO parentDept = randomPojo(DeptRespDTO.class, o -> o.setId(100L).setParentId(1000L) + .setLeaderUserId(200L)); + when(deptApi.getDept(eq(100L))).thenReturn(parentDept); + + // 调用 + Set result = expression.calculateUsers(execution, 2); + // 断言 + assertEquals(asSet(200L), result); + } + + @SuppressWarnings("SameParameterValue") + private DelegateExecution mockDelegateExecution(Long startUserId) { + ExecutionEntityImpl execution = new ExecutionEntityImpl(); + execution.setProcessInstanceId(randomString()); + // mock 返回 startUserId + ExecutionEntityImpl processInstance = new ExecutionEntityImpl(); + processInstance.setStartUserId(String.valueOf(startUserId)); + when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))) + .thenReturn(processInstance); + return execution; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java new file mode 100644 index 0000000..9b89e2b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptLeaderStrategy strategy; + + @Mock + private DeptApi deptApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); + DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); + when(deptApi.getDeptList(eq(asSet(1L, 2L)))).thenReturn(asList(dept1, dept2)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java new file mode 100644 index 0000000..4e72c02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptMemberStrategy strategy; + + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "11,22"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java new file mode 100644 index 0000000..eaa2ef7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateExpressionStrategy strategy; + + @Test + public void testCalculateUsers() { + try (MockedStatic flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法 + flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(execution), eq(param))) + .thenReturn(asSet(1L, 2L)); + + // 调用 + Set results = strategy.calculateUsers(execution, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java new file mode 100644 index 0000000..8bd2c88 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Arrays; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateGroupStrategy strategy; + + @Mock + private BpmUserGroupService userGroupService; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(11L, 12L))); + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(21L, 22L))); + when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 12L, 21L, 22L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java new file mode 100644 index 0000000..a30ce28 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidatePostStrategy strategy; + + @Mock + private PostApi postApi; + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java new file mode 100644 index 0000000..7c4247b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateRoleStrategy strategy; + + @Mock + private RoleApi roleApi; + @Mock + private PermissionApi permissionApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + when(permissionApi.getUserRoleIdListByRoleIds(eq(asSet(1L, 2L)))) + .thenReturn(asSet(11L, 22L)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java new file mode 100644 index 0000000..d71cceb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateUserStrategy strategy; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java new file mode 100644 index 0000000..f5033d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.bpm.service.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.category.BpmCategoryMapper; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryServiceImpl; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link BpmCategoryServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(BpmCategoryServiceImpl.class) +public class BpmCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private BpmCategoryServiceImpl categoryService; + + @Resource + private BpmCategoryMapper categoryMapper; + + @Test + public void testCreateCategory_success() { + // 准备参数 + BpmCategorySaveReqVO createReqVO = randomPojo(BpmCategorySaveReqVO.class).setId(null) + .setStatus(randomCommonStatus()); + + // 调用 + Long categoryId = categoryService.createCategory(createReqVO); + // 断言 + assertNotNull(categoryId); + // 校验记录的属性是否正确 + BpmCategoryDO category = categoryMapper.selectById(categoryId); + assertPojoEquals(createReqVO, category, "id"); + } + + @Test + public void testUpdateCategory_success() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class, o -> { + o.setId(dbCategory.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用 + categoryService.updateCategory(updateReqVO); + // 校验是否更新正确 + BpmCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, category); + } + + @Test + public void testUpdateCategory_notExists() { + // 准备参数 + BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteCategory_success() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCategory.getId(); + + // 调用 + categoryService.deleteCategory(id); + // 校验数据不存在了 + assertNull(categoryMapper.selectById(id)); + } + + @Test + public void testDeleteCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS); + } + + @Test + public void testGetCategoryPage() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class, o -> { // 等会查询到 + o.setName("芋头"); + o.setCode("xiaodun"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2023, 2, 2)); + }); + categoryMapper.insert(dbCategory); + // 测试 name 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName("小盾"))); + // 测试 code 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCode("tudou"))); + // 测试 status 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCreateTime(buildTime(2024, 2, 2)))); + // 准备参数 + BpmCategoryPageReqVO reqVO = new BpmCategoryPageReqVO(); + reqVO.setName("芋"); + reqVO.setCode("xiao"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = categoryService.getCategoryPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbCategory, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java new file mode 100644 index 0000000..3d5d508 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java @@ -0,0 +1,144 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.FORM_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link BpmFormServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(BpmFormServiceImpl.class) +public class BpmFormServiceTest extends BaseDbUnitTest { + + @Resource + private BpmFormServiceImpl formService; + + @Resource + private BpmFormMapper formMapper; + + @Test + public void testCreateForm_success() { + // 准备参数 + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { + o.setConf("{}"); + o.setFields(randomFields()); + }); + + // 调用 + Long formId = formService.createForm(reqVO); + // 断言 + assertNotNull(formId); + // 校验记录的属性是否正确 + BpmFormDO form = formMapper.selectById(formId); + assertPojoEquals(reqVO, form); + } + + @Test + public void testUpdateForm_success() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> { + o.setConf("{}"); + o.setFields(randomFields()); + }); + formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { + o.setId(dbForm.getId()); // 设置更新的 ID + o.setConf("{'yudao': 'yuanma'}"); + o.setFields(randomFields()); + }); + + // 调用 + formService.updateForm(reqVO); + // 校验是否更新正确 + BpmFormDO form = formMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, form); + } + + @Test + public void testUpdateForm_notExists() { + // 准备参数 + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { + o.setConf("{'yudao': 'yuanma'}"); + o.setFields(randomFields()); + }); + + // 调用, 并断言异常 + assertServiceException(() -> formService.updateForm(reqVO), FORM_NOT_EXISTS); + } + + @Test + public void testDeleteForm_success() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class); + formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbForm.getId(); + + // 调用 + formService.deleteForm(id); + // 校验数据不存在了 + assertNull(formMapper.selectById(id)); + } + + @Test + public void testDeleteForm_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> formService.deleteForm(id), FORM_NOT_EXISTS); + } + + @Test + public void testGetFormPage() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + }); + formMapper.insert(dbForm); + // 测试 name 不匹配 + formMapper.insert(cloneIgnoreId(dbForm, o -> o.setName("源码"))); + // 准备参数 + BpmFormPageReqVO reqVO = new BpmFormPageReqVO(); + reqVO.setName("芋道"); + + // 调用 + PageResult pageResult = formService.getFormPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbForm, pageResult.getList().get(0)); + } + + private List randomFields() { + int size = RandomUtil.randomInt(1, 3); + return Stream.iterate(0, i -> i).limit(size) + .map(i -> JsonUtils.toJsonString(randomPojo(BpmFormFieldRespDTO.class))) + .collect(Collectors.toList()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java new file mode 100644 index 0000000..7a0ecb6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; + +/** + * {@link BpmUserGroupServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(BpmUserGroupServiceImpl.class) +public class BpmUserGroupServiceTest extends BaseDbUnitTest { + + @Resource + private BpmUserGroupServiceImpl userGroupService; + + @Resource + private BpmUserGroupMapper userGroupMapper; + + @Test + public void testCreateUserGroup_success() { + // 准备参数 + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class); + + // 调用 + Long userGroupId = userGroupService.createUserGroup(reqVO); + // 断言 + Assertions.assertNotNull(userGroupId); + // 校验记录的属性是否正确 + BpmUserGroupDO userGroup = userGroupMapper.selectById(userGroupId); + AssertUtils.assertPojoEquals(reqVO, userGroup); + } + + @Test + public void testUpdateUserGroup_success() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class); + userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class, o -> { + o.setId(dbUserGroup.getId()); // 设置更新的 ID + }); + + // 调用 + userGroupService.updateUserGroup(reqVO); + // 校验是否更新正确 + BpmUserGroupDO userGroup = userGroupMapper.selectById(reqVO.getId()); // 获取最新的 + AssertUtils.assertPojoEquals(reqVO, userGroup); + } + + @Test + public void testUpdateUserGroup_notExists() { + // 准备参数 + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> userGroupService.updateUserGroup(reqVO), USER_GROUP_NOT_EXISTS); + } + + @Test + public void testDeleteUserGroup_success() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class); + userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbUserGroup.getId(); + + // 调用 + userGroupService.deleteUserGroup(id); + // 校验数据不存在了 + Assertions.assertNull(userGroupMapper.selectById(id)); + } + + @Test + public void testDeleteUserGroup_notExists() { + // 准备参数 + Long id = RandomUtils.randomLongId(); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> userGroupService.deleteUserGroup(id), USER_GROUP_NOT_EXISTS); + } + + @Test + public void testGetUserGroupPage() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2021, 11, 11)); + }); + userGroupMapper.insert(dbUserGroup); + // 测试 name 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setName("芋道"))); + // 测试 status 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setCreateTime(buildTime(2021, 12, 12)))); + // 准备参数 + BpmUserGroupPageReqVO reqVO = new BpmUserGroupPageReqVO(); + reqVO.setName("源码"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)})); + + // 调用 + PageResult pageResult = userGroupService.getUserGroupPage(reqVO); + // 断言 + Assertions.assertEquals(1, pageResult.getTotal()); + Assertions.assertEquals(1, pageResult.getList().size()); + AssertUtils.assertPojoEquals(dbUserGroup, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..dd9b95b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,42 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + +mybatis-plus: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..d4f93bb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,3 @@ +DELETE FROM "bpm_form"; +DELETE FROM "bpm_user_group"; +DELETE FROM "bpm_category"; diff --git a/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..1034962 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,43 @@ +CREATE TABLE IF NOT EXISTS "bpm_user_group" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "description" varchar(255) NOT NULL, + "status" tinyint NOT NULL, + "user_ids" varchar(255) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '用户组'; + +CREATE TABLE IF NOT EXISTS "bpm_category" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "code" varchar(63) NOT NULL, + "description" varchar(255) NOT NULL, + "status" tinyint NOT NULL, + "sort" int NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '分类'; + +CREATE TABLE IF NOT EXISTS "bpm_form" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "status" tinyint NOT NULL, + "fields" varchar(255) NOT NULL, + "conf" varchar(255) NOT NULL, + "remark" varchar(255), + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '动态表单'; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/pom.xml b/ruoyi-vue-pro-master/yudao-module-crm/pom.xml new file mode 100644 index 0000000..310a7df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/pom.xml @@ -0,0 +1,24 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + + yudao-module-crm-api + yudao-module-crm-biz + + 4.0.0 + yudao-module-crm + pom + + ${project.artifactId} + + crm 包下,客户关系管理(Customer Relationship Management)。 + 例如说:客户、联系人、商机、合同、回款等等 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/pom.xml new file mode 100644 index 0000000..94e1296 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-crm + ${revision} + + 4.0.0 + yudao-module-crm-api + jar + + ${project.artifactId} + + crm 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java new file mode 100644 index 0000000..c38bde7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * crm API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.crm.api; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java new file mode 100644 index 0000000..eee2b32 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.enums; + +/** + * CRM 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String CRM_CUSTOMER_INDUSTRY = "crm_customer_industry"; // CRM 客户所属行业 + String CRM_CUSTOMER_LEVEL = "crm_customer_level"; // CRM 客户等级 + String CRM_CUSTOMER_SOURCE = "crm_customer_source"; // CRM 客户来源 + String CRM_AUDIT_STATUS = "crm_audit_status"; // CRM 审批状态 + String CRM_PRODUCT_UNIT = "crm_product_unit"; // CRM 产品单位 + String CRM_PRODUCT_STATUS = "crm_product_status"; // CRM 产品状态 + String CRM_FOLLOW_UP_TYPE = "crm_follow_up_type"; // CRM 跟进方式 + String CRM_RECEIVABLE_RETURN_TYPE = "crm_receivable_return_type"; // CRM 回款方式 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..07a6dad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.crm.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * CRM 错误码枚举类 + *

+ * crm 系统,使用 1-020-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 合同管理 1-020-000-000 ========== + ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); + ErrorCode CONTRACT_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_001, "合同更新失败,原因:合同不是草稿状态"); + ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态"); + ErrorCode CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_000_003, "更新合同审核状态失败,原因:合同不是审核中状态"); + ErrorCode CONTRACT_NO_EXISTS = new ErrorCode(1_020_000_004, "生成合同序列号重复,请重试"); + ErrorCode CONTRACT_DELETE_FAIL = new ErrorCode(1_020_000_005, "删除合同失败,原因:有被回款所使用"); + + // ========== 线索管理 1-020-001-000 ========== + ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); + ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_001, "线索已经转化过了,请勿重复转化"); + + // ========== 商机管理 1-020-002-000 ========== + ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); + ErrorCode BUSINESS_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除"); + ErrorCode BUSINESS_UPDATE_STATUS_FAIL_END_STATUS = new ErrorCode(1_020_002_002, "更新商机状态失败,原因:已经是结束状态"); + ErrorCode BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS = new ErrorCode(1_020_002_003, "更新商机状态失败,原因:已经是该状态"); + + // ========== 联系人管理 1-020-003-000 ========== + ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); + ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); + ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败"); + + // ========== 回款 1-020-004-000 ========== + ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); + ErrorCode RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_004_001, "更新回款失败,原因:禁止编辑"); + ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); + ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); + ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态"); + ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试"); + ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态"); + ErrorCode RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_020_004_007, "创建回款失败,原因:回款金额超出合同金额,目前剩余可退:{} 元"); + ErrorCode RECEIVABLE_DELETE_FAIL_IS_APPROVE = new ErrorCode(1_020_004_008, "删除回款失败,原因:回款审批已通过"); + + // ========== 回款计划 1-020-005-000 ========== + ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); + ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款"); + ErrorCode RECEIVABLE_PLAN_EXISTS_RECEIVABLE = new ErrorCode(1_020_006_001, "回款计划已经有对应的回款,不能使用"); + + // ========== 客户管理 1_020_006_000 ========== + ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); + ErrorCode CUSTOMER_OWNER_EXISTS = new ErrorCode(1_020_006_001, "客户【{}】已存在所属负责人"); + ErrorCode CUSTOMER_LOCKED = new ErrorCode(1_020_006_002, "客户【{}】状态已锁定"); + ErrorCode CUSTOMER_ALREADY_DEAL = new ErrorCode(1_020_006_003, "客户已交易"); + ErrorCode CUSTOMER_IN_POOL = new ErrorCode(1_020_006_004, "客户【{}】放入公海失败,原因:已经是公海客户"); + ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定"); + ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常"); + ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态"); + ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "解锁客户失败,它已经处于未锁定状态"); + ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限"); + ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限"); + ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}"); + ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!"); + ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!"); + ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!"); + ErrorCode CUSTOMER_UPDATE_DEAL_STATUS_FAIL = new ErrorCode(1_020_006_015, "更新客户的成交状态失败,原因:已经是该状态,无需更新"); + + // ========== 权限管理 1_020_007_000 ========== + ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); + ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); + ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); + ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); + ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); + ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); + ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); + ErrorCode CRM_PERMISSION_CREATE_FAIL_EXISTS = new ErrorCode(1_020_007_009, "同时添加数据权限失败,原因:用户【{}】已有模块【{}】数据【{}】的【{}】权限"); + + // ========== 产品 1_020_008_000 ========== + ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); + ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); + ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用"); + + // ========== 产品分类 1_020_009_000 ========== + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); + ErrorCode PRODUCT_CATEGORY_EXISTS = new ErrorCode(1_020_009_001, "产品分类已存在"); + ErrorCode PRODUCT_CATEGORY_USED = new ErrorCode(1_020_009_002, "产品分类已关联产品"); + ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_020_009_003, "父分类不存在"); + ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); + ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); + + // ========== 商机状态 1_020_010_000 ========== + ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态组不存在"); + ErrorCode BUSINESS_STATUS_TYPE_NAME_EXISTS = new ErrorCode(1_020_010_001, "商机状态组的名称已存在"); + ErrorCode BUSINESS_STATUS_UPDATE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行更新"); + ErrorCode BUSINESS_STATUS_DELETE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行删除"); + ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在"); + + // ========== 客户公海规则设置 1_020_012_000 ========== + ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); + + // ========== 跟进记录 1_020_013_000 ========== + ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); + ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); + + // ========== 数据统计 1_020_014_000 ========== + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java new file mode 100644 index 0000000..aeeed31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.crm.enums; + +/** + * CRM 操作日志枚举 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串 + * + * @author HUIHUI + */ +public interface LogRecordConstants { + + // ======================= CRM_CLUE 线索 ======================= + + String CRM_CLUE_TYPE = "CRM 线索"; + String CRM_CLUE_CREATE_SUB_TYPE = "创建线索"; + String CRM_CLUE_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; + String CRM_CLUE_UPDATE_SUB_TYPE = "更新线索"; + String CRM_CLUE_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; + String CRM_CLUE_DELETE_SUB_TYPE = "删除线索"; + String CRM_CLUE_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; + String CRM_CLUE_TRANSFER_SUB_TYPE = "转移线索"; + String CRM_CLUE_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_CLUE_TRANSLATE_SUB_TYPE = "线索转化为客户"; + String CRM_CLUE_TRANSLATE_SUCCESS = "将线索【{{#clueName}}】转化为客户"; + String CRM_CLUE_FOLLOW_UP_SUB_TYPE = "线索跟进"; + String CRM_CLUE_FOLLOW_UP_SUCCESS = "线索跟进【{{#clueName}}】"; + + // ======================= CRM_CUSTOMER 客户 ======================= + + String CRM_CUSTOMER_TYPE = "CRM 客户"; + String CRM_CUSTOMER_CREATE_SUB_TYPE = "创建客户"; + String CRM_CUSTOMER_CREATE_SUCCESS = "创建了客户{{#customer.name}}"; + String CRM_CUSTOMER_UPDATE_SUB_TYPE = "更新客户"; + String CRM_CUSTOMER_UPDATE_SUCCESS = "更新了客户【{{#customerName}}】: {_DIFF{#updateReqVO}}"; + String CRM_CUSTOMER_DELETE_SUB_TYPE = "删除客户"; + String CRM_CUSTOMER_DELETE_SUCCESS = "删除了客户【{{#customerName}}】"; + String CRM_CUSTOMER_TRANSFER_SUB_TYPE = "转移客户"; + String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#customer.name}}】的负责人从【{getAdminUserById{#customer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#customer.lockStatus ? '解锁客户' : '锁定客户'}}"; + String CRM_CUSTOMER_LOCK_SUCCESS = "{{#customer.lockStatus ? '将客户【' + #customer.name + '】解锁' : '将客户【' + #customer.name + '】锁定'}}"; + String CRM_CUSTOMER_POOL_SUB_TYPE = "客户放入公海"; + String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海"; + String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}"; + String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; + String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}"; + String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}"; + String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE = "更新客户成交状态"; + String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS = "更新了客户【{{#customerName}}】的成交状态为【{{#dealStatus ? '已成交' : '未成交'}}】"; + String CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE = "客户跟进"; + String CRM_CUSTOMER_FOLLOW_UP_SUCCESS = "客户跟进【{{#customerName}}】"; + + // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= + + String CRM_CUSTOMER_LIMIT_CONFIG_TYPE = "CRM 客户限制配置"; + String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUB_TYPE = "创建客户限制配置"; + String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUCCESS = "创建了【{{#limitType}}】类型的客户限制配置"; + String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUB_TYPE = "更新客户限制配置"; + String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUCCESS = "更新了客户限制配置: {_DIFF{#updateReqVO}}"; + String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUB_TYPE = "删除客户限制配置"; + String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUCCESS = "删除了【{{#limitType}}】类型的客户限制配置"; + + // ======================= CRM_CUSTOMER_POOL_CONFIG 客户公海规则 ======================= + + String CRM_CUSTOMER_POOL_CONFIG_TYPE = "CRM 客户公海规则"; + String CRM_CUSTOMER_POOL_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新客户公海规则' : '创建客户公海规则'}}"; + String CRM_CUSTOMER_POOL_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了客户公海规则' : '创建了客户公海规则'}}"; + + // ======================= CRM_CONTACT 联系人 ======================= + + String CRM_CONTACT_TYPE = "CRM 联系人"; + String CRM_CONTACT_CREATE_SUB_TYPE = "创建联系人"; + String CRM_CONTACT_CREATE_SUCCESS = "创建了联系人{{#contact.name}}"; + String CRM_CONTACT_UPDATE_SUB_TYPE = "更新联系人"; + String CRM_CONTACT_UPDATE_SUCCESS = "更新了联系人【{{#contactName}}】: {_DIFF{#updateReqVO}}"; + String CRM_CONTACT_DELETE_SUB_TYPE = "删除联系人"; + String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; + String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; + String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_CONTACT_FOLLOW_UP_SUB_TYPE = "联系人跟进"; + String CRM_CONTACT_FOLLOW_UP_SUCCESS = "联系人跟进【{{#contactName}}】"; + String CRM_CONTACT_UPDATE_OWNER_USER_SUB_TYPE = "更新联系人负责人"; + String CRM_CONTACT_UPDATE_OWNER_USER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#ownerUserId}}】"; + + // ======================= CRM_BUSINESS 商机 ======================= + + String CRM_BUSINESS_TYPE = "CRM 商机"; + String CRM_BUSINESS_CREATE_SUB_TYPE = "创建商机"; + String CRM_BUSINESS_CREATE_SUCCESS = "创建了商机{{#business.name}}"; + String CRM_BUSINESS_UPDATE_SUB_TYPE = "更新商机"; + String CRM_BUSINESS_UPDATE_SUCCESS = "更新了商机【{{#businessName}}】: {_DIFF{#updateReqVO}}"; + String CRM_BUSINESS_DELETE_SUB_TYPE = "删除商机"; + String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; + String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; + String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_BUSINESS_FOLLOW_UP_SUB_TYPE = "商机跟进"; + String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】"; + String CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE = "更新商机状态"; + String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "更新了商机【{{#businessName}}】的状态从【{{#oldStatusName}}】变更为了【{{#newStatusName}}】"; + + // ======================= CRM_CONTRACT_CONFIG 合同配置 ======================= + + String CRM_CONTRACT_CONFIG_TYPE = "CRM 合同配置"; + String CRM_CONTRACT_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新合同配置' : '创建合同配置'}}"; + String CRM_CONTRACT_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了合同配置' : '创建了合同配置'}}"; + + // ======================= CRM_CONTRACT 合同 ======================= + + String CRM_CONTRACT_TYPE = "CRM 合同"; + String CRM_CONTRACT_CREATE_SUB_TYPE = "创建合同"; + String CRM_CONTRACT_CREATE_SUCCESS = "创建了合同{{#contract.name}}"; + String CRM_CONTRACT_UPDATE_SUB_TYPE = "更新合同"; + String CRM_CONTRACT_UPDATE_SUCCESS = "更新了合同【{{#contractName}}】: {_DIFF{#updateReqVO}}"; + String CRM_CONTRACT_DELETE_SUB_TYPE = "删除合同"; + String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】"; + String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同"; + String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批"; + String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功"; + String CRM_CONTRACT_FOLLOW_UP_SUB_TYPE = "合同跟进"; + String CRM_CONTRACT_FOLLOW_UP_SUCCESS = "合同跟进【{{#contractName}}】"; + + // ======================= CRM_PRODUCT 产品 ======================= + + String CRM_PRODUCT_TYPE = "CRM 产品"; + String CRM_PRODUCT_CREATE_SUB_TYPE = "创建产品"; + String CRM_PRODUCT_CREATE_SUCCESS = "创建了产品【{{#createReqVO.name}}】"; + String CRM_PRODUCT_UPDATE_SUB_TYPE = "更新产品"; + String CRM_PRODUCT_UPDATE_SUCCESS = "更新了产品【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; + String CRM_PRODUCT_DELETE_SUB_TYPE = "删除产品"; + String CRM_PRODUCT_DELETE_SUCCESS = "删除了产品【{{#product.name}}】"; + + // ======================= CRM_PRODUCT_CATEGORY 产品分类 ======================= + + String CRM_PRODUCT_CATEGORY_TYPE = "CRM 产品分类"; + String CRM_PRODUCT_CATEGORY_CREATE_SUB_TYPE = "创建产品分类"; + String CRM_PRODUCT_CATEGORY_CREATE_SUCCESS = "创建了产品分类【{{#createReqVO.name}}】"; + String CRM_PRODUCT_CATEGORY_UPDATE_SUB_TYPE = "更新产品分类"; + String CRM_PRODUCT_CATEGORY_UPDATE_SUCCESS = "更新了产品分类【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; + String CRM_PRODUCT_CATEGORY_DELETE_SUB_TYPE = "删除产品分类"; + String CRM_PRODUCT_CATEGORY_DELETE_SUCCESS = "删除了产品分类【{{#productCategory.name}}】"; + + // ======================= CRM_RECEIVABLE 回款 ======================= + + String CRM_RECEIVABLE_TYPE = "CRM 回款"; + String CRM_RECEIVABLE_CREATE_SUB_TYPE = "创建回款"; + String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款"; + String CRM_RECEIVABLE_UPDATE_SUB_TYPE = "更新回款"; + String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款: {_DIFF{#updateReqVO}}"; + String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; + String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款"; + String CRM_RECEIVABLE_SUBMIT_SUB_TYPE = "提交回款审批"; + String CRM_RECEIVABLE_SUBMIT_SUCCESS = "提交编号为【{{#receivableNo}}】的回款审批成功"; + + // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= + + String CRM_RECEIVABLE_PLAN_TYPE = "CRM 回款计划"; + String CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE = "创建回款计划"; + String CRM_RECEIVABLE_PLAN_CREATE_SUCCESS = "创建了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; + String CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE = "更新回款计划"; + String CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划: {_DIFF{#updateReqVO}}"; + String CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE = "删除回款计划"; + String CRM_RECEIVABLE_PLAN_DELETE_SUCCESS = "删除了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java new file mode 100644 index 0000000..4736c01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.enums.business; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 商机的结束状态枚举 + * + * @author lzxhqs + */ +@RequiredArgsConstructor +@Getter +public enum CrmBusinessEndStatusEnum implements IntArrayValuable { + + WIN(1, "赢单"), + LOSE(2, "输单"), + INVALID(3, "无效"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBusinessEndStatusEnum::getStatus).toArray(); + + /** + * 场景类型 + */ + private final Integer status; + /** + * 场景名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static CrmBusinessEndStatusEnum fromStatus(Integer status) { + return Arrays.stream(values()) + .filter(value -> value.getStatus().equals(status)) + .findFirst() + .orElse(null); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java new file mode 100644 index 0000000..67709e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmAuditStatusEnum.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * CRM 的审批状态 + * + * @author 赤焰 + */ +@RequiredArgsConstructor +@Getter +public enum CrmAuditStatusEnum implements IntArrayValuable { + + DRAFT(0, "未提交"), + PROCESS(10, "审批中"), + APPROVE(20, "审核通过"), + REJECT(30, "审核不通过"), + CANCEL(40, "已取消"); + + private final Integer status; + private final String name; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmAuditStatusEnum::getStatus).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java new file mode 100644 index 0000000..8402ad2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.enums.common; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * CRM 业务类型枚举 + * + * @author HUIHUI + */ +@RequiredArgsConstructor +@Getter +public enum CrmBizTypeEnum implements IntArrayValuable { + + CRM_CLUE(1, "线索"), + CRM_CUSTOMER(2, "客户"), + CRM_CONTACT(3, "联系人"), + CRM_BUSINESS(4, "商机"), + CRM_CONTRACT(5, "合同"), + CRM_PRODUCT(6, "产品"), + CRM_RECEIVABLE(7, "回款"), + CRM_RECEIVABLE_PLAN(8, "回款计划") + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名称 + */ + private final String name; + + public static String getNameByType(Integer type) { + CrmBizTypeEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmBizTypeEnum.values()), + item -> ObjUtil.equal(item.type, type)); + return typeEnum == null ? null : typeEnum.getName(); + } + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java new file mode 100644 index 0000000..945d7c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.crm.enums.common; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 列表检索场景 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum CrmSceneTypeEnum implements IntArrayValuable { + + OWNER(1, "我负责的"), + INVOLVED(2, "我参与的"), + SUBORDINATE(3, "下属负责的"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneTypeEnum::getType).toArray(); + + /** + * 场景类型 + */ + private final Integer type; + /** + * 场景名称 + */ + private final String name; + + public static boolean isOwner(Integer type) { + return ObjUtil.equal(OWNER.getType(), type); + } + + public static boolean isInvolved(Integer type) { + return ObjUtil.equal(INVOLVED.getType(), type); + } + + public static boolean isSubordinate(Integer type) { + return ObjUtil.equal(SUBORDINATE.getType(), type); + } + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLevelEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLevelEnum.java new file mode 100644 index 0000000..aa06b05 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLevelEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.crm.enums.customer; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 客户等级 + * + * @author Wanwan + */ +@Getter +@AllArgsConstructor +public enum CrmCustomerLevelEnum implements IntArrayValuable { + + IMPORTANT(1, "A(重点客户)"), + GENERAL(2, "B(普通客户)"), + LOW_PRIORITY(3, "C(非优先客户)"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLevelEnum::getLevel).toArray(); + + /** + * 状态 + */ + private final Integer level; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java new file mode 100644 index 0000000..2cf8d78 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.enums.customer; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 客户限制配置规则类型 + * + * @author Wanwan + */ +@Getter +@AllArgsConstructor +public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable { + + /** + * 拥有客户数限制 + */ + CUSTOMER_OWNER_LIMIT(1, "拥有客户数限制"), + /** + * 锁定客户数限制 + */ + CUSTOMER_LOCK_LIMIT(2, "锁定客户数限制"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getType).toArray(); + + /** + * 状态 + */ + private final Integer type; + /** + * 状态名 + */ + private final String name; + + public static String getNameByType(Integer type) { + CrmCustomerLimitConfigTypeEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmCustomerLimitConfigTypeEnum.values()), + item -> ObjUtil.equal(item.type, type)); + return typeEnum == null ? null : typeEnum.getName(); + } + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java new file mode 100644 index 0000000..f36e8cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.crm.enums.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 数据权限级别枚举 + * + * OWNER > WRITE > READ + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum CrmPermissionLevelEnum implements IntArrayValuable { + + OWNER(1, "负责人"), + READ(2, "只读"), + WRITE(3, "读写"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray(); + + /** + * 级别 + */ + private final Integer level; + /** + * 级别名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isOwner(Integer level) { + return ObjUtil.equal(OWNER.level, level); + } + + public static boolean isRead(Integer level) { + return ObjUtil.equal(READ.level, level); + } + + public static boolean isWrite(Integer level) { + return ObjUtil.equal(WRITE.level, level); + } + + public static String getNameByLevel(Integer level) { + CrmPermissionLevelEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmPermissionLevelEnum.values()), + item -> ObjUtil.equal(item.level, level)); + return typeEnum == null ? null : typeEnum.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/product/CrmProductStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/product/CrmProductStatusEnum.java new file mode 100644 index 0000000..9516c35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/product/CrmProductStatusEnum.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.crm.enums.product; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 商品状态 + * + * @author ZanGe丶 + * @since 2023-11-30 21:53 + */ +@Getter +@AllArgsConstructor +public enum CrmProductStatusEnum implements IntArrayValuable { + + DISABLE(0, "下架"), + ENABLE(1, "上架"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmProductStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isEnable(Integer status) { + return ObjUtil.equal(ENABLE.status, status); + } + + public static boolean isDisable(Integer status) { + return ObjUtil.equal(DISABLE.status, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java new file mode 100644 index 0000000..3c01fe9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.crm.enums.receivable; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 回款方式枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum CrmReceivableReturnTypeEnum implements IntArrayValuable { + + CHECK(1, "支票"), + CASH(2, "现金"), + POSTAL_REMITTANCE(3, "邮政汇款"), + TELEGRAPHIC_TRANSFER(4, "电汇"), + ONLINE_TRANSFER(5, "网上转账"), + ALIPAY(6, "支付宝"), + WECHAT_PAY(7, "微信支付"), + OTHER(8, "其它"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReceivableReturnTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/pom.xml new file mode 100644 index 0000000..0af42a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/pom.xml @@ -0,0 +1,75 @@ + + + + cn.iocoder.boot + yudao-module-crm + ${revision} + + 4.0.0 + yudao-module-crm-biz + + ${project.artifactId} + + crm 包下,客户关系管理(Customer Relationship Management)。 + 例如说:客户、联系人、商机、合同、回款等等 + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-crm-api + ${revision} + + + cn.iocoder.boot + yudao-module-bpm-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java new file mode 100644 index 0000000..5c4e249 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * crm API 实现类,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.crm.api; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java new file mode 100644 index 0000000..f55bd89 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java @@ -0,0 +1,222 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; + +@Tag(name = "管理后台 - CRM 商机") +@RestController +@RequestMapping("/crm/business") +@Validated +public class CrmBusinessController { + + @Resource + private CrmBusinessService businessService; + @Resource + private CrmCustomerService customerService; + @Resource + private CrmBusinessStatusService businessStatusTypeService; + @Resource + private CrmBusinessStatusService businessStatusService; + @Resource + private CrmProductService productService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建商机") + @PreAuthorize("@ss.hasPermission('crm:business:create')") + public CommonResult createBusiness(@Valid @RequestBody CrmBusinessSaveReqVO createReqVO) { + return success(businessService.createBusiness(createReqVO, getLoginUserId())); + } + + @PutMapping("/update") + @Operation(summary = "更新商机") + @PreAuthorize("@ss.hasPermission('crm:business:update')") + public CommonResult updateBusiness(@Valid @RequestBody CrmBusinessSaveReqVO updateReqVO) { + businessService.updateBusiness(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新商机状态") + @PreAuthorize("@ss.hasPermission('crm:business:update')") + public CommonResult updateBusinessStatus(@Valid @RequestBody CrmBusinessUpdateStatusReqVO updateStatusReqVO) { + businessService.updateBusinessStatus(updateStatusReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商机") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:business:delete')") + public CommonResult deleteBusiness(@RequestParam("id") Long id) { + businessService.deleteBusiness(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得商机") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult getBusiness(@RequestParam("id") Long id) { + CrmBusinessDO business = businessService.getBusiness(id); + return success(buildBusinessDetail(business)); + } + + private CrmBusinessRespVO buildBusinessDetail(CrmBusinessDO business) { + if (business == null) { + return null; + } + CrmBusinessRespVO businessVO = buildBusinessDetailList(Collections.singletonList(business)).get(0); + // 拼接产品项 + List businessProducts = businessService.getBusinessProductListByBusinessId(businessVO.getId()); + Map productMap = productService.getProductMap( + convertSet(businessProducts, CrmBusinessProductDO::getProductId)); + businessVO.setProducts(BeanUtils.toBean(businessProducts, CrmBusinessRespVO.Product.class, businessProductVO -> + MapUtils.findAndThen(productMap, businessProductVO.getProductId(), + product -> businessProductVO.setProductName(product.getName()) + .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); + return businessVO; + } + + @GetMapping("/simple-all-list") + @Operation(summary = "获得联系人的精简列表") + @PreAuthorize("@ss.hasPermission('crm:contact:query')") + public CommonResult> getSimpleContactList() { + CrmBusinessPageReqVO reqVO = new CrmBusinessPageReqVO(); + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 + PageResult pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); + return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 + new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()) + .setCustomerId(business.getCustomerId()))); + } + + @GetMapping("/page") + @Operation(summary = "获得商机分页") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { + PageResult pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-customer") + @Operation(summary = "获得商机分页,基于指定客户") + public CommonResult> getBusinessPageByCustomer(@Valid CrmBusinessPageReqVO pageReqVO) { + if (pageReqVO.getCustomerId() == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + PageResult pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-contact") + @Operation(summary = "获得联系人的商机分页") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { + PageResult pageResult = businessService.getBusinessPageByContact(pageReqVO); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出商机 Excel") + @PreAuthorize("@ss.hasPermission('crm:business:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PAGE_SIZE_NONE); + List list = businessService.getBusinessPage(exportReqVO, getLoginUserId()).getList(); + // 导出 Excel + ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, + buildBusinessDetailList(list)); + } + + public List buildBusinessDetailList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(list, CrmBusinessDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.3 获得商机状态组 + Map statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap( + convertSet(list, CrmBusinessDO::getStatusTypeId)); + Map statusMap = businessStatusService.getBusinessStatusMap( + convertSet(list, CrmBusinessDO::getStatusId)); + // 2. 拼接数据 + return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> { + // 2.1 设置客户名称 + MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName())); + // 2.2 设置创建人、负责人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()), + user -> businessVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> { + businessVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName())); + }); + // 2.3 设置商机状态 + MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName())); + MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName( + businessService.getBusinessStatusName(businessVO.getEndStatus(), status))); + }); + } + + @PutMapping("/transfer") + @Operation(summary = "商机转移") + @PreAuthorize("@ss.hasPermission('crm:business:update')") + public CommonResult transferBusiness(@Valid @RequestBody CrmBusinessTransferReqVO reqVO) { + businessService.transferBusiness(reqVO, getLoginUserId()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java new file mode 100644 index 0000000..db80306 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - CRM 商机状态") +@RestController +@RequestMapping("/crm/business-status") +@Validated +public class CrmBusinessStatusController { + + @Resource + private CrmBusinessStatusService businessStatusTypeService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建商机状态") + @PreAuthorize("@ss.hasPermission('crm:business-status:create')") + public CommonResult createBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO createReqVO) { + return success(businessStatusTypeService.createBusinessStatus(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新商机状态") + @PreAuthorize("@ss.hasPermission('crm:business-status:update')") + public CommonResult updateBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO updateReqVO) { + businessStatusTypeService.updateBusinessStatus(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商机状态") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:business-status:delete')") + public CommonResult deleteBusinessStatusType(@RequestParam("id") Long id) { + businessStatusTypeService.deleteBusinessStatusType(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得商机状态") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:business-status:query')") + public CommonResult getBusinessStatusType(@RequestParam("id") Long id) { + CrmBusinessStatusTypeDO statusType = businessStatusTypeService.getBusinessStatusType(id); + if (statusType == null) { + return success(null); + } + List statuses = businessStatusTypeService.getBusinessStatusListByTypeId(id); + return success(BeanUtils.toBean(statusType, CrmBusinessStatusRespVO.class, + statusTypeVO -> statusTypeVO.setStatuses(BeanUtils.toBean(statuses, CrmBusinessStatusRespVO.Status.class)))); + } + + @GetMapping("/page") + @Operation(summary = "获得商机状态分页") + @PreAuthorize("@ss.hasPermission('crm:business-status:query')") + public CommonResult> getBusinessStatusPage(@Valid PageParam pageReqVO) { + // 1. 查询数据 + PageResult pageResult = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 2. 拼接数据 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), statusType -> Long.parseLong(statusType.getCreator()))); + Map deptMap = deptApi.getDeptMap( + convertSetByFlatMap(pageResult.getList(), CrmBusinessStatusTypeDO::getDeptIds, Collection::stream)); + return success(BeanUtils.toBean(pageResult, CrmBusinessStatusRespVO.class, statusTypeVO -> { + statusTypeVO.setCreator(userMap.get(NumberUtils.parseLong(statusTypeVO.getCreator())).getNickname()); + statusTypeVO.setDeptNames(convertList(statusTypeVO.getDeptIds(), + deptId -> deptMap.containsKey(deptId) ? deptMap.get(deptId).getName() : null)); + })); + } + + @GetMapping("/type-simple-list") + @Operation(summary = "获得商机状态组列表") + public CommonResult> getBusinessStatusTypeSimpleList() { + List list = businessStatusTypeService.getBusinessStatusTypeList(); + // 过滤掉部门不匹配的 + Long deptId = adminUserApi.getUser(getLoginUserId()).getDeptId(); + list.removeIf(statusType -> CollUtil.isNotEmpty(statusType.getDeptIds()) && !statusType.getDeptIds().contains(deptId)); + return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.class)); + } + + @GetMapping("/status-simple-list") + @Operation(summary = "获得商机状态列表") + @Parameter(name = "typeId", description = "商机状态组", required = true, example = "1024") + public CommonResult> getBusinessStatusSimpleList(@RequestParam("typeId") Long typeId) { + List list = businessStatusTypeService.getBusinessStatusListByTypeId(typeId); + return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.Status.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java new file mode 100644 index 0000000..0e47bf5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 商机分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmBusinessPageReqVO extends PageParam { + + @Schema(description = "商机名称", example = "李四") + private String name; + + @Schema(description = "客户编号", example = "10795") + private Long customerId; + + @Schema(description = "联系人编号", example = "10795") + private Long contactId; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java new file mode 100644 index 0000000..49cdcb8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java @@ -0,0 +1,144 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - CRM 商机 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmBusinessRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("商机名称") + private String name; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") + private Long customerId; + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true") + @ExcelProperty("跟进状态") + private Boolean followUpStatus; + + @Schema(description = "最后跟进时间") + @ExcelProperty("最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "下次联系时间") + @ExcelProperty("下次联系时间") + private LocalDateTime contactNextTime; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("负责人的用户编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") + private Long statusTypeId; + @Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") + @ExcelProperty("商机状态组") + private String statusTypeName; + + @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") + private Long statusId; + @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中") + @ExcelProperty("商机状态") + private String statusName; + + @Schema + @ExcelProperty("结束状态") + private Integer endStatus; + + @ExcelProperty("结束时的备注") + private String endRemark; + + @Schema(description = "预计成交日期") + @ExcelProperty("预计成交日期") + private LocalDateTime dealTime; + + @Schema(description = "产品总金额", example = "12025") + @ExcelProperty("产品总金额") + private BigDecimal totalProductPrice; + + @Schema(description = "整单折扣") + @ExcelProperty("整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "商机总金额", example = "12371") + @ExcelProperty("商机总金额") + private BigDecimal totalPrice; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "产品列表") + private List products; + + @Schema(description = "产品列表") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Product { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private Long productId; + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private String productNo; + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private Integer productUnit; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal productPrice; + + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal businessPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + private BigDecimal count; + + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal totalPrice; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java new file mode 100644 index 0000000..578139c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; + +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 商机创建/更新 Request VO") +@Data +public class CrmBusinessSaveReqVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + private Long id; + + @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @DiffLogField(name = "商机名称") + @NotNull(message = "商机名称不能为空") + private String name; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) + @NotNull(message = "客户不能为空") + private Long customerId; + + @Schema(description = "下次联系时间") + @DiffLogField(name = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime contactNextTime; + + @Schema(description = "负责人用户编号", example = "14334") + @NotNull(message = "负责人不能为空") + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) + private Long ownerUserId; + + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") + @DiffLogField(name = "商机状态组") + @NotNull(message = "商机状态组不能为空") + private Long statusTypeId; + + @Schema(description = "预计成交日期") + @DiffLogField(name = "预计成交日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime dealTime; + + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") + @DiffLogField(name = "整单折扣") + @NotNull(message = "整单折扣不能为空") + private BigDecimal discountPercent; + + @Schema(description = "备注", example = "随便") + @DiffLogField(name = "备注") + private String remark; + + @Schema(description = "联系人编号", example = "110") + private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 + + @Schema(description = "产品列表") + private List products; + + @Schema(description = "产品列表") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class BusinessProduct { + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "产品单价不能为空") + private BigDecimal productPrice; + + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "商机价格不能为空") + private BigDecimal businessPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + @NotNull(message = "产品数量不能为空") + private Integer count; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java new file mode 100644 index 0000000..da3a87f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; + +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商机转移 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessTransferReqVO { + + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "商机编号不能为空") + private Long id; + + /** + * 新负责人的用户编号 + */ + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + /** + * 老负责人加入团队后的权限级别。如果 null 说明移除 + * + * 关联 {@link CrmPermissionLevelEnum} + */ + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer oldOwnerPermissionLevel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java new file mode 100644 index 0000000..3fe7d9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 商机更新状态 Request VO") +@Data +public class CrmBusinessUpdateStatusReqVO { + + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + @NotNull(message = "商机编号不能为空") + private Long id; + + @Schema(description = "状态编号", example = "1") + private Long statusId; + + @Schema(description = "结束状态", example = "1") + @InEnum(value = CrmBusinessEndStatusEnum.class) + private Integer endStatus; + + @AssertTrue(message = "变更状态不正确") + public boolean isStatusValid() { + return statusId != null || endStatus != null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java new file mode 100644 index 0000000..a2ee1df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 商机状态 Response VO") +@Data +public class CrmBusinessStatusRespVO { + + @Schema(description = "状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") + private Long id; + + @Schema(description = "状态组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String name; + + @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) + private List deptIds; + @Schema(description = "使用的部门名称", requiredMode = Schema.RequiredMode.REQUIRED) + private List deptNames; + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED) + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "状态集合", requiredMode = Schema.RequiredMode.REQUIRED) + private List statuses; + + @Data + public static class Status { + + @Schema(description = "状态编号", example = "23899") + private Long id; + + @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private BigDecimal percent; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sort; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java new file mode 100644 index 0000000..42d6620 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@Schema(description = "管理后台 - 商机状态组新增/修改 Request VO") +@Data +public class CrmBusinessStatusSaveReqVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") + private Long id; + + @Schema(description = "状态类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "状态类型名不能为空") + private String name; + + @Schema(description = "使用的部门编号") + private List deptIds; + + @Schema(description = "商机状态集合", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "商机状态集合不能为空") + @Valid + private List statuses; + + @Data + public static class Status { + + @Schema(description = "状态编号", example = "23899") + private Long id; + + @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "状态名不能为空") + private String name; + + @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + @NotNull(message = "赢单率不能为空") + private BigDecimal percent; + + @Schema(description = "排序", hidden = true, example = "1") + private Integer sort; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java new file mode 100644 index 0000000..166268c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java @@ -0,0 +1,173 @@ +package cn.iocoder.yudao.module.crm.controller.admin.clue; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; + +@Tag(name = "管理后台 - 线索") +@RestController +@RequestMapping("/crm/clue") +@Validated +public class CrmClueController { + + @Resource + private CrmClueService clueService; + @Resource + private CrmCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建线索") + @PreAuthorize("@ss.hasPermission('crm:clue:create')") + public CommonResult createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { + return success(clueService.createClue(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新线索") + @PreAuthorize("@ss.hasPermission('crm:clue:update')") + public CommonResult updateClue(@Valid @RequestBody CrmClueSaveReqVO updateReqVO) { + clueService.updateClue(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除线索") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:clue:delete')") + public CommonResult deleteClue(@RequestParam("id") Long id) { + clueService.deleteClue(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得线索") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:clue:query')") + public CommonResult getClue(@RequestParam("id") Long id) { + CrmClueDO clue = clueService.getClue(id); + return success(buildClueDetail(clue)); + } + + private CrmClueRespVO buildClueDetail(CrmClueDO clue) { + if (clue == null) { + return null; + } + return buildClueDetailList(singletonList(clue)).get(0); + } + + @GetMapping("/page") + @Operation(summary = "获得线索分页") + @PreAuthorize("@ss.hasPermission('crm:clue:query')") + public CommonResult> getCluePage(@Valid CrmCluePageReqVO pageVO) { + PageResult pageResult = clueService.getCluePage(pageVO, getLoginUserId()); + return success(new PageResult<>(buildClueDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出线索 Excel") + @PreAuthorize("@ss.hasPermission('crm:clue:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportClueExcel(@Valid CrmCluePageReqVO pageReqVO, HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PAGE_SIZE_NONE); + List list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); + // 导出 Excel + ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, buildClueDetailList(list)); + } + + private List buildClueDetailList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(list, CrmClueDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 2. 转换成 VO + return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> { + clueVO.setAreaName(AreaUtils.format(clueVO.getAreaId())); + // 2.1 设置客户名称 + MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName())); + // 2.2 设置创建人、负责人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(clueVO.getCreator()), + user -> clueVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, clueVO.getOwnerUserId(), user -> { + clueVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> clueVO.setOwnerUserDeptName(dept.getName())); + }); + }); + } + + @PutMapping("/transfer") + @Operation(summary = "线索转移") + @PreAuthorize("@ss.hasPermission('crm:clue:update')") + public CommonResult transferClue(@Valid @RequestBody CrmClueTransferReqVO reqVO) { + clueService.transferClue(reqVO, getLoginUserId()); + return success(true); + } + + @PutMapping("/transform") + @Operation(summary = "线索转化为客户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:clue:update')") + public CommonResult transformClue(@RequestParam("id") Long id) { + clueService.transformClue(id, getLoginUserId()); + return success(Boolean.TRUE); + } + + @GetMapping("/follow-count") + @Operation(summary = "获得分配给我的、待跟进的线索数量") + @PreAuthorize("@ss.hasPermission('crm:clue:query')") + public CommonResult getFollowClueCount() { + return success(clueService.getFollowClueCount(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java new file mode 100644 index 0000000..a63d946 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 线索分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmCluePageReqVO extends PageParam { + + @Schema(description = "线索名称", example = "线索xxx") + private String name; + + @Schema(description = "转化状态", example = "2048") + private Boolean transformStatus; + + @Schema(description = "电话", example = "18000000000") + private String telephone; + + @Schema(description = "手机号", example = "18000000000") + private String mobile; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean pool; // null 则表示为不是公海数据 + + @Schema(description = "所属行业", example = "1") + private Integer industryId; + + @Schema(description = "客户等级", example = "1") + private Integer level; + + @Schema(description = "客户来源", example = "1") + private Integer source; + + @Schema(description = "跟进状态", example = "true") + private Boolean followUpStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java new file mode 100644 index 0000000..56e5c25 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 线索 Response VO") +@Data +@ToString(callSuper = true) +@ExcelIgnoreUnannotated +public class CrmClueRespVO { + + @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") + @ExcelProperty("线索名称") + private String name; + + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "跟进状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean followUpStatus; + + @Schema(description = "最后跟进时间") + @ExcelProperty("最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") + @ExcelProperty("最后跟进内容") + private String contactLastContent; + + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") + @ExcelProperty("下次联系时间") + private LocalDateTime contactNextTime; + + @Schema(description = "负责人编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "转化状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean transformStatus; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") + private Long customerId; + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户名称") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "手机号", example = "18000000000") + @ExcelProperty("手机号") + private String mobile; + + @Schema(description = "电话", example = "18000000000") + @ExcelProperty("电话") + private String telephone; + + @Schema(description = "QQ", example = "25682") + @ExcelProperty("QQ") + private String qq; + + @Schema(description = "wechat", example = "25682") + @ExcelProperty("wechat") + private String wechat; + + @Schema(description = "email", example = "25682") + @ExcelProperty("email") + private String email; + + @Schema(description = "地区编号", example = "1024") + @ExcelProperty("地区编号") + private Integer areaId; + @Schema(description = "地区名称", example = "北京市") + @ExcelProperty("地区名称") + private String areaName; + @Schema(description = "详细地址", example = "北京市成华大道") + @ExcelProperty("详细地址") + private String detailAddress; + + @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "所属行业", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) + private Integer industryId; + + @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "客户等级", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) + private Integer level; + + @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "客户来源", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) + private Integer source; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java new file mode 100644 index 0000000..aff2ad1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAreaParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; + +@Schema(description = "管理后台 - CRM 线索创建/更新 Request VO") +@Data +public class CrmClueSaveReqVO { + + @Schema(description = "编号", example = "10969") + private Long id; + + @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") + @DiffLogField(name = "线索名称") + @NotEmpty(message = "线索名称不能为空") + private String name; + + @Schema(description = "最后跟进时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @DiffLogField(name = "最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") + @DiffLogField(name = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime contactNextTime; + + @Schema(description = "负责人编号", example = "2048") + @NotNull(message = "负责人编号不能为空") + private Long ownerUserId; + + @Schema(description = "手机号", example = "18000000000") + @DiffLogField(name = "手机号") + @Mobile + private String mobile; + + @Schema(description = "电话", example = "18000000000") + @DiffLogField(name = "电话") + @Telephone + private String telephone; + + @Schema(description = "QQ", example = "123456789") + @DiffLogField(name = "QQ") + @Size(max = 20, message = "QQ长度不能超过 20 个字符") + private String qq; + + @Schema(description = "微信", example = "123456789") + @DiffLogField(name = "微信") + @Size(max = 255, message = "微信长度不能超过 255 个字符") + private String wechat; + + @Schema(description = "邮箱", example = "123456789@qq.com") + @DiffLogField(name = "邮箱") + @Email(message = "邮箱格式不正确") + @Size(max = 255, message = "邮箱长度不能超过 255 个字符") + private String email; + + @Schema(description = "地区编号", example = "20158") + @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) + private Integer areaId; + + @Schema(description = "详细地址", example = "北京市海淀区") + @DiffLogField(name = "详细地址") + private String detailAddress; + + @Schema(description = "所属行业", example = "1") + @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) + @DictFormat(CRM_CUSTOMER_INDUSTRY) + private Integer industryId; + + @Schema(description = "客户等级", example = "2") + @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) + @InEnum(CrmCustomerLevelEnum.class) + private Integer level; + + @Schema(description = "客户来源", example = "3") + @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) + private Integer source; + + @Schema(description = "客户描述", example = "任意文字") + @DiffLogField(name = "客户描述") + @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") + private String description; + + @Schema(description = "备注", example = "随便") + @DiffLogField(name = "备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java new file mode 100644 index 0000000..894dc71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 线索转移 Request VO") +@Data +public class CrmClueTransferReqVO { + + @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "线索编号不能为空") + private Long id; + + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(value = CrmPermissionLevelEnum.class) + private Integer oldOwnerPermissionLevel; // 老负责人加入团队后的权限级别。如果 null 说明移除 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java new file mode 100644 index 0000000..a9d2b35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java @@ -0,0 +1,226 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; + +@Tag(name = "管理后台 - CRM 联系人") +@RestController +@RequestMapping("/crm/contact") +@Validated +@Slf4j +public class CrmContactController { + + @Resource + private CrmContactService contactService; + @Resource + private CrmCustomerService customerService; + @Resource + private CrmContactBusinessService contactBusinessLinkService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建联系人") + @PreAuthorize("@ss.hasPermission('crm:contact:create')") + public CommonResult createContact(@Valid @RequestBody CrmContactSaveReqVO createReqVO) { + return success(contactService.createContact(createReqVO, getLoginUserId())); + } + + @PutMapping("/update") + @Operation(summary = "更新联系人") + @PreAuthorize("@ss.hasPermission('crm:contact:update')") + public CommonResult updateContact(@Valid @RequestBody CrmContactSaveReqVO updateReqVO) { + contactService.updateContact(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除联系人") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:contact:delete')") + public CommonResult deleteContact(@RequestParam("id") Long id) { + contactService.deleteContact(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得联系人") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:contact:query')") + public CommonResult getContact(@RequestParam("id") Long id) { + CrmContactDO contact = contactService.getContact(id); + return success(buildContactDetail(contact)); + } + + private CrmContactRespVO buildContactDetail(CrmContactDO contact) { + if (contact == null) { + return null; + } + return buildContactDetailList(singletonList(contact)).get(0); + } + + @GetMapping("/simple-all-list") + @Operation(summary = "获得联系人的精简列表") + @PreAuthorize("@ss.hasPermission('crm:contact:query')") + public CommonResult> getSimpleContactList() { + List list = contactService.getContactList(getLoginUserId()); + return success(convertList(list, contact -> // 只返回 id、name 字段 + new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()) + .setCustomerId(contact.getCustomerId()))); + } + + @GetMapping("/page") + @Operation(summary = "获得联系人分页") + @PreAuthorize("@ss.hasPermission('crm:contact:query')") + public CommonResult> getContactPage(@Valid CrmContactPageReqVO pageVO) { + PageResult pageResult = contactService.getContactPage(pageVO, getLoginUserId()); + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-customer") + @Operation(summary = "获得联系人分页,基于指定客户") + public CommonResult> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { + Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); + PageResult pageResult = contactService.getContactPageByCustomerId(pageVO); + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-business") + @Operation(summary = "获得联系人分页,基于指定商机") + public CommonResult> getContactPageByBusiness(@Valid CrmContactPageReqVO pageVO) { + Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); + PageResult pageResult = contactService.getContactPageByBusinessId(pageVO); + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出联系人 Excel") + @PreAuthorize("@ss.hasPermission('crm:contact:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportContactExcel(@Valid CrmContactPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageNo(PAGE_SIZE_NONE); + List list = contactService.getContactPage(exportReqVO, getLoginUserId()).getList(); + ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class, buildContactDetailList(list)); + } + + private List buildContactDetailList(List contactList) { + if (CollUtil.isEmpty(contactList)) { + return Collections.emptyList(); + } + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(contactList, CrmContactDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.3 直属上级 Map + Map parentContactMap = contactService.getContactMap( + convertSet(contactList, CrmContactDO::getParentId)); + // 2. 转换成 VO + return BeanUtils.toBean(contactList, CrmContactRespVO.class, contactVO -> { + contactVO.setAreaName(AreaUtils.format(contactVO.getAreaId())); + // 2.1 设置客户名称 + MapUtils.findAndThen(customerMap, contactVO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName())); + // 2.2 设置创建人、负责人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(contactVO.getCreator()), + user -> contactVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, contactVO.getOwnerUserId(), user -> { + contactVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contactVO.setOwnerUserDeptName(dept.getName())); + }); + // 2.3 设置直属上级名称 + findAndThen(parentContactMap, contactVO.getParentId(), contact -> contactVO.setParentName(contact.getName())); + }); + } + + @PutMapping("/transfer") + @Operation(summary = "联系人转移") + @PreAuthorize("@ss.hasPermission('crm:contact:update')") + public CommonResult transferContact(@Valid @RequestBody CrmContactTransferReqVO reqVO) { + contactService.transferContact(reqVO, getLoginUserId()); + return success(true); + } + + // ================== 关联/取关商机 =================== + + @PostMapping("/create-business-list") + @Operation(summary = "创建联系人与商机的关联") + @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") + public CommonResult createContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO createReqVO) { + contactBusinessLinkService.createContactBusinessList(createReqVO); + return success(true); + } + + + @PostMapping("/create-business-list2") + @Operation(summary = "创建联系人与商机的关联") + @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") + public CommonResult createContactBusinessList2(@Valid @RequestBody CrmContactBusiness2ReqVO createReqVO) { + contactBusinessLinkService.createContactBusinessList2(createReqVO); + return success(true); + } + + @DeleteMapping("/delete-business-list") + @Operation(summary = "删除联系人与联系人的关联") + @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") + public CommonResult deleteContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO deleteReqVO) { + contactBusinessLinkService.deleteContactBusinessList(deleteReqVO); + return success(true); + } + + @DeleteMapping("/delete-business-list2") + @Operation(summary = "删除联系人与联系人的关联") + @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") + public CommonResult deleteContactBusinessList(@Valid @RequestBody CrmContactBusiness2ReqVO deleteReqVO) { + contactBusinessLinkService.deleteContactBusinessList2(deleteReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java new file mode 100644 index 0000000..edc07bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【商机关联联系人】用于关联,取消关联的操作 +@Data +public class CrmContactBusiness2ReqVO { + + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") + @NotNull(message="商机不能为空") + private Long businessId; + + @Schema(description = "联系人编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") + @NotEmpty(message="联系人数组不能为空") + private List contactIds; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java new file mode 100644 index 0000000..aaac18e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【联系人关联商机】用于关联,取消关联的操作 +@Data +public class CrmContactBusinessReqVO { + + @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") + @NotNull(message="联系人不能为空") + private Long contactId; + + @Schema(description = "商机编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") + @NotEmpty(message="商机不能为空") + private List businessIds; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java new file mode 100644 index 0000000..6698a38 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 联系人分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmContactPageReqVO extends PageParam { + + @Schema(description = "姓名", example = "芋艿") + private String name; + + @Schema(description = "客户编号", example = "10795") + private Long customerId; + + @Schema(description = "手机号", example = "13898273941") + private String mobile; + + @Schema(description = "电话", example = "021-383773") + private String telephone; + + @Schema(description = "电子邮箱", example = "111@22.com") + private String email; + + @Schema(description = "QQ", example = "3882872") + private Long qq; + + @Schema(description = "微信", example = "zzZ98373") + private String wechat; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "商机编号", example = "10430") + private Long businessId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java new file mode 100644 index 0000000..b2b1e83 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 联系人 Response VO") +@Data +@ToString(callSuper = true) +@ExcelIgnoreUnannotated +public class CrmContactRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + private Long id; + + @Schema(description = "联系人姓名", example = "芋艿") + @ExcelProperty(value = "联系人姓名", order = 1) + private String name; + + @Schema(description = "客户编号", example = "10795") + private Long customerId; + @ExcelProperty(value = "客户名称", order = 2) + @Schema(description = "客户名字", example = "test") + private String customerName; + + @Schema(description = "最后跟进时间") + @ExcelProperty(value = "最后跟进时间", order = 6) + private LocalDateTime contactLastTime; + + @Schema(description = "最后跟进内容") + @ExcelProperty(value = "最后跟进内容", order = 6) + private String contactLastContent; + + @Schema(description = "下次联系时间") + @ExcelProperty(value = "下次联系时间", order = 6) + private LocalDateTime contactNextTime; + + @Schema(description = "负责人编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "手机号", example = "1387171766") + @ExcelProperty(value = "手机号", order = 4) + private String mobile; + + @Schema(description = "电话", example = "021-0029922") + @ExcelProperty(value = "电话", order = 4) + private String telephone; + + @Schema(description = "电子邮箱", example = "1111@22.com") + @ExcelProperty(value = "邮箱", order = 4) + private String email; + + @Schema(description = "QQ", example = "197272662") + @ExcelProperty(value = "QQ", order = 4) + private Long qq; + + @Schema(description = "微信", example = "zzz3883") + @ExcelProperty(value = "微信", order = 4) + private String wechat; + + @Schema(description = "地区编号", example = "20158") + private Integer areaId; + @Schema(description = "地区名", example = "上海上海市浦东新区") + @ExcelProperty(value = "地区", order = 5) + private String areaName; + + @Schema(description = "地址") + @ExcelProperty(value = "地址", order = 5) + private String detailAddress; + + @Schema(description = "性别") + @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) + private Integer sex; + + @Schema(description = "是否关键决策人") + @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean master; + + @Schema(description = "职位") + @ExcelProperty(value = "职位", order = 3) + private String post; + + @Schema(description = "直属上级", example = "23457") + private Long parentId; + @Schema(description = "直属上级名", example = "芋头") + @ExcelProperty(value = "直属上级", order = 4) + private String parentName; + + @Schema(description = "备注", example = "你说的对") + @ExcelProperty(value = "备注", order = 6) + private String remark; + + @Schema(description = "创建人", example = "25682") + private String creator; + @Schema(description = "创建人名字", example = "test") + @ExcelProperty(value = "创建人", order = 8) + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java new file mode 100644 index 0000000..f16af86 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") +@Data +public class CrmContactSaveReqVO { + + @Schema(description = "主键", example = "3167") + private Long id; + + @Schema(description = "姓名", example = "芋艿") + @NotNull(message = "姓名不能为空") + @DiffLogField(name = "姓名") + private String name; + + @Schema(description = "客户编号", example = "10795") + @NotNull(message = "客户编号不能为空") + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) + private Long customerId; + + @Schema(description = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @DiffLogField(name = "下次联系时间") + private LocalDateTime contactNextTime; + + @Schema(description = "负责人用户编号", example = "14334") + @NotNull(message = "负责人不能为空") + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) + private Long ownerUserId; + + @Schema(description = "手机号", example = "1387171766") + @Mobile + @DiffLogField(name = "手机号") + private String mobile; + + @Schema(description = "电话", example = "021-0029922") + @Telephone + @DiffLogField(name = "电话") + private String telephone; + + @Schema(description = "QQ", example = "197272662") + @DiffLogField(name = "QQ") + private Long qq; + + @Schema(description = "微信", example = "zzz3883") + @DiffLogField(name = "微信") + private String wechat; + + @Schema(description = "电子邮箱", example = "1111@22.com") + @DiffLogField(name = "邮箱") + @Email + private String email; + + @Schema(description = "地区编号", example = "20158") + @DiffLogField(name = "所在地", function = SysAreaParseFunction.NAME) + private Integer areaId; + + @Schema(description = "地址") + @DiffLogField(name = "地址") + private String detailAddress; + + @Schema(description = "性别") + @DiffLogField(name = "性别", function = SysSexParseFunction.NAME) + private Integer sex; + + @Schema(description = "是否关键决策人") + @DiffLogField(name = "关键决策人", function = SysBooleanParseFunction.NAME) + private Boolean master; + + @Schema(description = "职位") + @DiffLogField(name = "职位") + private String post; + + @Schema(description = "直属上级", example = "23457") + @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) + private Long parentId; + + @Schema(description = "备注", example = "你说的对") + @DiffLogField(name = "备注") + private String remark; + + @Schema(description = "关联商机 ID", example = "122233") + private Long businessId; // 注意:该字段用于在【商机】详情界面「新建联系人」时,自动进行关联 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java new file mode 100644 index 0000000..4f94ee2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; + +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 联系人转移 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CrmContactTransferReqVO { + + @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "联系人编号不能为空") + private Long id; + + /** + * 新负责人的用户编号 + */ + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + /** + * 老负责人加入团队后的权限级别。如果 null 说明移除 + * + * 关联 {@link CrmPermissionLevelEnum} + */ + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer oldOwnerPermissionLevel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java new file mode 100644 index 0000000..369260f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 合同配置") +@RestController +@RequestMapping("/crm/contract-config") +@Validated +public class CrmContractConfigController { + + @Resource + private CrmContractConfigService contractConfigService; + + @GetMapping("/get") + @Operation(summary = "获取合同配置") + @PreAuthorize("@ss.hasPermission('crm:contract-config:query')") + public CommonResult getCustomerPoolConfig() { + CrmContractConfigDO config = contractConfigService.getContractConfig(); + return success(BeanUtils.toBean(config, CrmContractConfigRespVO.class)); + } + + @PutMapping("/save") + @Operation(summary = "更新合同配置") + @PreAuthorize("@ss.hasPermission('crm:contract-config:update')") + public CommonResult saveCustomerPoolConfig(@Valid @RequestBody CrmContractConfigSaveReqVO updateReqVO) { + contractConfigService.saveContractConfig(updateReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java new file mode 100644 index 0000000..225ef13 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java @@ -0,0 +1,256 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; + +@Tag(name = "管理后台 - CRM 合同") +@RestController +@RequestMapping("/crm/contract") +@Validated +public class CrmContractController { + + @Resource + private CrmContractService contractService; + @Resource + private CrmCustomerService customerService; + @Resource + private CrmContactService contactService; + @Resource + private CrmBusinessService businessService; + @Resource + private CrmProductService productService; + @Resource + private CrmReceivableService receivableService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建合同") + @PreAuthorize("@ss.hasPermission('crm:contract:create')") + public CommonResult createContract(@Valid @RequestBody CrmContractSaveReqVO createReqVO) { + return success(contractService.createContract(createReqVO, getLoginUserId())); + } + + @PutMapping("/update") + @Operation(summary = "更新合同") + @PreAuthorize("@ss.hasPermission('crm:contract:update')") + public CommonResult updateContract(@Valid @RequestBody CrmContractSaveReqVO updateReqVO) { + contractService.updateContract(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除合同") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:contract:delete')") + public CommonResult deleteContract(@RequestParam("id") Long id) { + contractService.deleteContract(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得合同") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:contract:query')") + public CommonResult getContract(@RequestParam("id") Long id) { + CrmContractDO contract = contractService.getContract(id); + return success(buildContractDetail(contract)); + } + + private CrmContractRespVO buildContractDetail(CrmContractDO contract) { + if (contract == null) { + return null; + } + CrmContractRespVO contractVO = buildContractDetailList(singletonList(contract)).get(0); + // 拼接产品项 + List businessProducts = contractService.getContractProductListByContractId(contractVO.getId()); + Map productMap = productService.getProductMap( + convertSet(businessProducts, CrmContractProductDO::getProductId)); + contractVO.setProducts(BeanUtils.toBean(businessProducts, CrmContractRespVO.Product.class, businessProductVO -> + MapUtils.findAndThen(productMap, businessProductVO.getProductId(), + product -> businessProductVO.setProductName(product.getName()) + .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); + return contractVO; + } + + @GetMapping("/page") + @Operation(summary = "获得合同分页") + @PreAuthorize("@ss.hasPermission('crm:contract:query')") + public CommonResult> getContractPage(@Valid CrmContractPageReqVO pageVO) { + PageResult pageResult = contractService.getContractPage(pageVO, getLoginUserId()); + return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); + } + + @GetMapping("/page-by-customer") + @Operation(summary = "获得合同分页,基于指定客户") + public CommonResult> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { + Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); + PageResult pageResult = contractService.getContractPageByCustomerId(pageVO); + return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); + } + + @GetMapping("/page-by-business") + @Operation(summary = "获得合同分页,基于指定商机") + public CommonResult> getContractPageByBusiness(@Valid CrmContractPageReqVO pageVO) { + Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); + PageResult pageResult = contractService.getContractPageByBusinessId(pageVO); + return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出合同 Excel") + @PreAuthorize("@ss.hasPermission('crm:contract:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportContractExcel(@Valid CrmContractPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + PageResult pageResult = contractService.getContractPage(exportReqVO, getLoginUserId()); + // 导出 Excel + ExcelUtils.write(response, "合同.xls", "数据", CrmContractRespVO.class, + BeanUtils.toBean(pageResult.getList(), CrmContractRespVO.class)); + } + + @PutMapping("/transfer") + @Operation(summary = "合同转移") + @PreAuthorize("@ss.hasPermission('crm:contract:update')") + public CommonResult transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) { + contractService.transferContract(reqVO, getLoginUserId()); + return success(true); + } + + @PutMapping("/submit") + @Operation(summary = "提交合同审批") + @PreAuthorize("@ss.hasPermission('crm:contract:update')") + public CommonResult submitContract(@RequestParam("id") Long id) { + contractService.submitContract(id, getLoginUserId()); + return success(true); + } + + private List buildContractDetailList(List contractList) { + if (CollUtil.isEmpty(contractList)) { + return Collections.emptyList(); + } + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(contractList, CrmContractDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.3 获取联系人 + Map contactMap = convertMap(contactService.getContactList(convertSet(contractList, + CrmContractDO::getSignContactId)), CrmContactDO::getId); + // 1.4 获取商机 + Map businessMap = businessService.getBusinessMap( + convertSet(contractList, CrmContractDO::getBusinessId)); + // 1.5 获得已回款金额 + Map receivablePriceMap = receivableService.getReceivablePriceMapByContractId( + convertSet(contractList, CrmContractDO::getId)); + // 2. 拼接数据 + return BeanUtils.toBean(contractList, CrmContractRespVO.class, contractVO -> { + // 2.1 设置客户信息 + findAndThen(customerMap, contractVO.getCustomerId(), customer -> contractVO.setCustomerName(customer.getName())); + // 2.2 设置用户信息 + findAndThen(userMap, Long.parseLong(contractVO.getCreator()), user -> contractVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, contractVO.getOwnerUserId(), user -> { + contractVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contractVO.setOwnerUserDeptName(dept.getName())); + }); + findAndThen(userMap, contractVO.getSignUserId(), user -> contractVO.setSignUserName(user.getNickname())); + // 2.3 设置联系人信息 + findAndThen(contactMap, contractVO.getSignContactId(), contact -> contractVO.setSignContactName(contact.getName())); + // 2.4 设置商机信息 + findAndThen(businessMap, contractVO.getBusinessId(), business -> contractVO.setBusinessName(business.getName())); + // 2.5 设置已回款金额 + contractVO.setTotalReceivablePrice(receivablePriceMap.getOrDefault(contractVO.getId(), BigDecimal.ZERO)); + }); + } + + @GetMapping("/audit-count") + @Operation(summary = "获得待审核合同数量") + @PreAuthorize("@ss.hasPermission('crm:contract:query')") + public CommonResult getAuditContractCount() { + return success(contractService.getAuditContractCount(getLoginUserId())); + } + + @GetMapping("/remind-count") + @Operation(summary = "获得即将到期(提醒)的合同数量") + @PreAuthorize("@ss.hasPermission('crm:contract:query')") + public CommonResult getRemindContractCount() { + return success(contractService.getRemindContractCount(getLoginUserId())); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得合同精简列表", description = "只包含的合同,主要用于前端的下拉选项") + @Parameter(name = "customerId", description = "客户编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:contract:query')") + public CommonResult> getContractSimpleList(@RequestParam("customerId") Long customerId) { + CrmContractPageReqVO pageReqVO = new CrmContractPageReqVO().setCustomerId(customerId); + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页 + PageResult pageResult = contractService.getContractPageByCustomerId(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(Collections.emptyList()); + } + // 拼接数据 + Map receivablePriceMap = receivableService.getReceivablePriceMapByContractId( + convertSet(pageResult.getList(), CrmContractDO::getId)); + return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 id、name 等精简字段 + .setId(contract.getId()).setName(contract.getName()).setAuditStatus(contract.getAuditStatus()) + .setTotalPrice(contract.getTotalPrice()) + .setTotalReceivablePrice(receivablePriceMap.getOrDefault(contract.getId(), BigDecimal.ZERO)))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java new file mode 100644 index 0000000..c39cf92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 合同配置 Response VO") +@Data +public class CrmContractConfigRespVO { + + @Schema(description = "是否开启提前提醒", example = "true") + private Boolean notifyEnabled; + + @Schema(description = "提前提醒天数", example = "2") + private Integer notifyDays; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java new file mode 100644 index 0000000..2eb79d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; + +import cn.hutool.core.util.BooleanUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import java.util.Objects; + +@Schema(description = "管理后台 - CRM 合同配置 Request VO") +@Data +public class CrmContractConfigSaveReqVO { + + @Schema(description = "是否开启提前提醒", example = "true") + @DiffLogField(name = "是否开启提前提醒") + private Boolean notifyEnabled; + + @Schema(description = "提前提醒天数", example = "2") + @DiffLogField(name = "提前提醒天数") + private Integer notifyDays; + + @AssertTrue(message = "提前提醒天数不能为空") + @JsonIgnore + public boolean isNotifyDaysValid() { + if (!BooleanUtil.isTrue(getNotifyEnabled())) { + return true; + } + return Objects.nonNull(getNotifyDays()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java new file mode 100644 index 0000000..74f8008 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 合同分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmContractPageReqVO extends PageParam { + + /** + * 过期类型 - 即将过期 + */ + public static final Integer EXPIRY_TYPE_ABOUT_TO_EXPIRE = 1; + /** + * 过期类型 - 已过期 + */ + public static final Integer EXPIRY_TYPE_EXPIRED = 2; + + @Schema(description = "合同编号", example = "XYZ008") + private String no; + + @Schema(description = "合同名称", example = "王五") + private String name; + + @Schema(description = "客户编号", example = "18336") + private Long customerId; + + @Schema(description = "商机编号", example = "10864") + private Long businessId; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "审批状态", example = "20") + @InEnum(CrmAuditStatusEnum.class) + private Integer auditStatus; + + @Schema(description = "过期类型", example = "1") + private Integer expiryType; // 过期类型,为 null 时则表示全部 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java new file mode 100644 index 0000000..a01bc11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java @@ -0,0 +1,162 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - CRM 合同 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmContractRespVO { + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @ExcelProperty("合同编号") + private Long id; + + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @ExcelProperty("合同名称") + private String name; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101") + @ExcelProperty("合同编号") + private String no; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") + @ExcelProperty("客户编号") + private Long customerId; + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "商机编号", example = "10864") + @ExcelProperty("商机编号") + private Long businessId; + @Schema(description = "商机名称", example = "10864") + @ExcelProperty("商机名称") + private String businessName; + + @Schema(description = "最后跟进时间") + @ExcelProperty("最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("负责人的用户编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "工作流编号", example = "1043") + @ExcelProperty("工作流编号") + private String processInstanceId; + + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("审批状态") + private Integer auditStatus; + + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("下单日期") + private LocalDateTime orderDate; + + @Schema(description = "开始时间") + @ExcelProperty("开始时间") + private LocalDateTime startTime; + + @Schema(description = "结束时间") + @ExcelProperty("结束时间") + private LocalDateTime endTime; + + @Schema(description = "产品总金额", example = "19510") + @ExcelProperty("产品总金额") + private BigDecimal totalProductPrice; + + @Schema(description = "整单折扣") + @ExcelProperty("整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "合同金额", example = "5617") + @ExcelProperty("合同金额") + private BigDecimal totalPrice; + + @Schema(description = "已回款金额", example = "5617") + @ExcelProperty("已回款金额") + private BigDecimal totalReceivablePrice; + + @Schema(description = "客户签约人编号", example = "18546") + private Long signContactId; + @Schema(description = "客户签约人", example = "小豆") + @ExcelProperty("客户签约人") + private String signContactName; + + @Schema(description = "公司签约人", example = "14036") + private Long signUserId; + @Schema(description = "公司签约人", example = "小明") + @ExcelProperty("公司签约人") + private String signUserName; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人", example = "25682") + @ExcelProperty("创建人") + private String creator; + + @Schema(description = "创建人名字", example = "test") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "产品列表") + private List products; + + @Schema(description = "产品列表") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Product { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private Long productId; + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private String productNo; + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private Integer productUnit; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal productPrice; + + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal contractPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + private BigDecimal count; + + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal totalPrice; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java new file mode 100644 index 0000000..9e06296 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; + +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmBusinessParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmContactParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 合同创建/更新 Request VO") +@Data +public class CrmContractSaveReqVO { + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + private Long id; + + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @DiffLogField(name = "合同名称") + @NotNull(message = "合同名称不能为空") + private String name; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) + @NotNull(message = "客户编号不能为空") + private Long customerId; + + @Schema(description = "商机编号", example = "10864") + @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME) + private Long businessId; + + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) + @NotNull(message = "负责人不能为空") + private Long ownerUserId; + + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) + @DiffLogField(name = "下单日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotNull(message = "下单日期不能为空") + private LocalDateTime orderDate; + + @Schema(description = "开始时间") + @DiffLogField(name = "开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "结束时间") + @DiffLogField(name = "结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") + @DiffLogField(name = "整单折扣") + @NotNull(message = "整单折扣不能为空") + private BigDecimal discountPercent; + + @Schema(description = "合同金额", example = "5617") + @DiffLogField(name = "合同金额") + private BigDecimal totalPrice; + + @Schema(description = "客户签约人编号", example = "18546") + @DiffLogField(name = "客户签约人", function = CrmContactParseFunction.NAME) + private Long signContactId; + + @Schema(description = "公司签约人", example = "14036") + @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME) + private Long signUserId; + + @Schema(description = "备注", example = "你猜") + @DiffLogField(name = "备注") + private String remark; + + @Schema(description = "产品列表") + private List products; + + @Schema(description = "产品列表") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Product { + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "产品单价不能为空") + private BigDecimal productPrice; + + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "合同价格不能为空") + private BigDecimal contractPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + @NotNull(message = "产品数量不能为空") + private Integer count; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java new file mode 100644 index 0000000..e234a02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 合同转移 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CrmContractTransferReqVO { + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "联系人编号不能为空") + private Long id; + + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(value = CrmPermissionLevelEnum.class) + private Integer oldOwnerPermissionLevel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java new file mode 100644 index 0000000..68e7a48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -0,0 +1,316 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; + +@Tag(name = "管理后台 - CRM 客户") +@RestController +@RequestMapping("/crm/customer") +@Validated +public class CrmCustomerController { + + @Resource + private CrmCustomerService customerService; + @Resource + private CrmCustomerPoolConfigService customerPoolConfigService; + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建客户") + @PreAuthorize("@ss.hasPermission('crm:customer:create')") + public CommonResult createCustomer(@Valid @RequestBody CrmCustomerSaveReqVO createReqVO) { + return success(customerService.createCustomer(createReqVO, getLoginUserId())); + } + + @PutMapping("/update") + @Operation(summary = "更新客户") + @PreAuthorize("@ss.hasPermission('crm:customer:update')") + public CommonResult updateCustomer(@Valid @RequestBody CrmCustomerSaveReqVO updateReqVO) { + customerService.updateCustomer(updateReqVO); + return success(true); + } + + @PutMapping("/update-deal-status") + @Operation(summary = "更新客户的成交状态") + @Parameters({ + @Parameter(name = "id", description = "客户编号", required = true), + @Parameter(name = "dealStatus", description = "成交状态", required = true) + }) + public CommonResult updateCustomerDealStatus(@RequestParam("id") Long id, + @RequestParam("dealStatus") Boolean dealStatus) { + customerService.updateCustomerDealStatus(id, dealStatus); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除客户") + @Parameter(name = "id", description = "客户编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:customer:delete')") + public CommonResult deleteCustomer(@RequestParam("id") Long id) { + customerService.deleteCustomer(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得客户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult getCustomer(@RequestParam("id") Long id) { + // 1. 获取客户 + CrmCustomerDO customer = customerService.getCustomer(id); + // 2. 拼接数据 + return success(buildCustomerDetail(customer)); + } + + public CrmCustomerRespVO buildCustomerDetail(CrmCustomerDO customer) { + if (customer == null) { + return null; + } + return buildCustomerDetailList(singletonList(customer)).get(0); + } + + @GetMapping("/page") + @Operation(summary = "获得客户分页") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { + // 1. 查询客户分页 + PageResult pageResult = customerService.getCustomerPage(pageVO, getLoginUserId()); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 2. 拼接数据 + return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); + } + + public List buildCustomerDetailList(List list) { + if (CollUtil.isEmpty(list)) { + return java.util.Collections.emptyList(); + } + // 1.1 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.2 获取距离进入公海的时间 + Map poolDayMap = getPoolDayMap(list); + // 2. 转换成 VO + return BeanUtils.toBean(list, CrmCustomerRespVO.class, customerVO -> { + customerVO.setAreaName(AreaUtils.format(customerVO.getAreaId())); + // 2.1 设置创建人、负责人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(customerVO.getCreator()), + user -> customerVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, customerVO.getOwnerUserId(), user -> { + customerVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> customerVO.setOwnerUserDeptName(dept.getName())); + }); + // 2.2 设置距离进入公海的时间 + if (customerVO.getOwnerUserId() != null) { + customerVO.setPoolDay(poolDayMap.get(customerVO.getId())); + } + }); + } + + @GetMapping("/put-pool-remind-page") + @Operation(summary = "获得待进入公海客户分页") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult> getPutPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { + // 1. 查询客户分页 + PageResult pageResult = customerService.getPutPoolRemindCustomerPage(pageVO, getLoginUserId()); + // 2. 拼接数据 + return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/put-pool-remind-count") + @Operation(summary = "获得待进入公海客户数量") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult getPutPoolRemindCustomerCount() { + return success(customerService.getPutPoolRemindCustomerCount(getLoginUserId())); + } + + @GetMapping("/today-contact-count") + @Operation(summary = "获得今日需联系客户数量") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult getTodayContactCustomerCount() { + return success(customerService.getTodayContactCustomerCount(getLoginUserId())); + } + + @GetMapping("/follow-count") + @Operation(summary = "获得分配给我、待跟进的线索数量的客户数量") + @PreAuthorize("@ss.hasPermission('crm:customer:query')") + public CommonResult getFollowCustomerCount() { + return success(customerService.getFollowCustomerCount(getLoginUserId())); + } + + /** + * 获取距离进入公海的时间 Map + * + * @param list 客户列表 + * @return key 客户编号, value 距离进入公海的时间 + */ + private Map getPoolDayMap(List list) { + CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); + if (poolConfig == null || !poolConfig.getEnabled()) { + return MapUtil.empty(); + } + list = CollectionUtils.filterList(list, customer -> { + // 特殊:如果没负责人,则说明已经在公海,不用计算 + if (customer.getOwnerUserId() == null) { + return false; + } + // 已成交 or 已锁定,不进入公海 + return !customer.getDealStatus() && !customer.getLockStatus(); + }); + return convertMap(list, CrmCustomerDO::getId, customer -> { + // 1.1 未成交放入公海天数 + long dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getOwnerTime()); + // 1.2 未跟进放入公海天数 + LocalDateTime lastTime = customer.getOwnerTime(); + if (customer.getContactLastTime() != null && customer.getContactLastTime().isAfter(lastTime)) { + lastTime = customer.getContactLastTime(); + } + long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime); + // 2. 返回最小的天数 + long poolDay = Math.min(dealExpireDay, contactExpireDay); + return poolDay > 0 ? poolDay : 0; + }); + } + + @GetMapping(value = "/simple-list") + @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项") + public CommonResult> getCustomerSimpleList() { + CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO(); + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 + List list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList(); + return success(convertList(list, customer -> // 只返回 id、name 精简字段 + new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出客户 Excel") + @PreAuthorize("@ss.hasPermission('crm:customer:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportCustomerExcel(@Valid CrmCustomerPageReqVO pageVO, + HttpServletResponse response) throws IOException { + pageVO.setPageSize(PAGE_SIZE_NONE); // 不分页 + List list = customerService.getCustomerPage(pageVO, getLoginUserId()).getList(); + // 导出 Excel + ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class, + buildCustomerDetailList(list)); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得导入客户模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List list = Arrays.asList( + CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1) + .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") + .areaId(null).detailAddress("").remark("").build(), + CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1) + .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") + .areaId(null).detailAddress("").remark("").build() + ); + // 输出 + ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list); + } + + @PostMapping("/import") + @Operation(summary = "导入客户") + @PreAuthorize("@ss.hasPermission('crm:customer:import')") + public CommonResult importExcel(@Valid CrmCustomerImportReqVO importReqVO) + throws Exception { + List list = ExcelUtils.read(importReqVO.getFile(), CrmCustomerImportExcelVO.class); + return success(customerService.importCustomerList(list, importReqVO)); + } + + @PutMapping("/transfer") + @Operation(summary = "转移客户") + @PreAuthorize("@ss.hasPermission('crm:customer:update')") + public CommonResult transferCustomer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) { + customerService.transferCustomer(reqVO, getLoginUserId()); + return success(true); + } + + @PutMapping("/lock") + @Operation(summary = "锁定/解锁客户") + @PreAuthorize("@ss.hasPermission('crm:customer:update')") + public CommonResult lockCustomer(@Valid @RequestBody CrmCustomerLockReqVO lockReqVO) { + customerService.lockCustomer(lockReqVO, getLoginUserId()); + return success(true); + } + + // ==================== 公海相关操作 ==================== + + @PutMapping("/put-pool") + @Operation(summary = "数据放入公海") + @Parameter(name = "id", description = "客户编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:customer:update')") + public CommonResult putCustomerPool(@RequestParam("id") Long id) { + customerService.putCustomerPool(id); + return success(true); + } + + @PutMapping("/receive") + @Operation(summary = "领取公海客户") + @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3") + @PreAuthorize("@ss.hasPermission('crm:customer:receive')") + public CommonResult receiveCustomer(@RequestParam(value = "ids") List ids) { + customerService.receiveCustomer(ids, getLoginUserId(), Boolean.TRUE); + return success(true); + } + + @PutMapping("/distribute") + @Operation(summary = "分配公海给对应负责人") + @PreAuthorize("@ss.hasPermission('crm:customer:distribute')") + public CommonResult distributeCustomer(@Valid @RequestBody CrmCustomerDistributeReqVO distributeReqVO) { + customerService.receiveCustomer(distributeReqVO.getIds(), distributeReqVO.getOwnerUserId(), Boolean.FALSE); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java new file mode 100644 index 0000000..82a326c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerLimitConfigService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; + +@Tag(name = "管理后台 - CRM 客户限制配置") +@RestController +@RequestMapping("/crm/customer-limit-config") +@Validated +public class CrmCustomerLimitConfigController { + + @Resource + private CrmCustomerLimitConfigService customerLimitConfigService; + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建客户限制配置") + @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:create')") + public CommonResult createCustomerLimitConfig(@Valid @RequestBody CrmCustomerLimitConfigSaveReqVO createReqVO) { + return success(customerLimitConfigService.createCustomerLimitConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新客户限制配置") + @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:update')") + public CommonResult updateCustomerLimitConfig(@Valid @RequestBody CrmCustomerLimitConfigSaveReqVO updateReqVO) { + customerLimitConfigService.updateCustomerLimitConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除客户限制配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:delete')") + public CommonResult deleteCustomerLimitConfig(@RequestParam("id") Long id) { + customerLimitConfigService.deleteCustomerLimitConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得客户限制配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") + public CommonResult getCustomerLimitConfig(@RequestParam("id") Long id) { + CrmCustomerLimitConfigDO limitConfig = customerLimitConfigService.getCustomerLimitConfig(id); + // 拼接数据 + Map userMap = adminUserApi.getUserMap(limitConfig.getUserIds()); + Map deptMap = deptApi.getDeptMap(limitConfig.getDeptIds()); + return success(BeanUtils.toBean(limitConfig, CrmCustomerLimitConfigRespVO.class, configVO -> { + configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); + configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); + })); + } + + @GetMapping("/page") + @Operation(summary = "获得客户限制配置分页") + @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") + public CommonResult> getCustomerLimitConfigPage(@Valid CrmCustomerLimitConfigPageReqVO pageVO) { + PageResult pageResult = customerLimitConfigService.getCustomerLimitConfigPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 拼接数据 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getUserIds, Collection::stream)); + Map deptMap = deptApi.getDeptMap( + convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getDeptIds, Collection::stream)); + return success(BeanUtils.toBean(pageResult, CrmCustomerLimitConfigRespVO.class, configVO -> { + configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); + configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); + })); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java new file mode 100644 index 0000000..5c56635 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 客户公海配置") +@RestController +@RequestMapping("/crm/customer-pool-config") +@Validated +public class CrmCustomerPoolConfigController { + + @Resource + private CrmCustomerPoolConfigService customerPoolConfigService; + + @GetMapping("/get") + @Operation(summary = "获取客户公海规则设置") + @PreAuthorize("@ss.hasPermission('crm:customer-pool-config:query')") + public CommonResult getCustomerPoolConfig() { + CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); + return success(BeanUtils.toBean(poolConfig, CrmCustomerPoolConfigRespVO.class)); + } + + @PutMapping("/save") + @Operation(summary = "更新客户公海规则设置") + @PreAuthorize("@ss.hasPermission('crm:customer-pool-config:update')") + public CommonResult saveCustomerPoolConfig(@Valid @RequestBody CrmCustomerPoolConfigSaveReqVO updateReqVO) { + customerPoolConfigService.saveCustomerPoolConfig(updateReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java new file mode 100644 index 0000000..4f8b0d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - CRM 客户分配公海给对应负责人 Request VO") +@Data +public class CrmCustomerDistributeReqVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024]") + @NotEmpty(message = "客户编号不能为空") + private List ids; + + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "负责人不能为空") + private Long ownerUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java new file mode 100644 index 0000000..a45e911 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; +import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunction; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; + +/** + * 客户 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +public class CrmCustomerImportExcelVO { + + @ExcelProperty("客户名称") + private String name; + + @ExcelProperty("手机") + private String mobile; + + @ExcelProperty("电话") + private String telephone; + + @ExcelProperty("QQ") + private String qq; + + @ExcelProperty("微信") + private String wechat; + + @ExcelProperty("邮箱") + private String email; + + @ExcelProperty(value = "地区", converter = AreaConvert.class) + @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunction.NAME) + private Integer areaId; + + @ExcelProperty("详细地址") + private String detailAddress; + + @ExcelProperty(value = "所属行业", converter = DictConvert.class) + @DictFormat(CRM_CUSTOMER_INDUSTRY) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_INDUSTRY) + private Integer industryId; + + @ExcelProperty(value = "客户等级", converter = DictConvert.class) + @DictFormat(CRM_CUSTOMER_LEVEL) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_LEVEL) + private Integer level; + + @ExcelProperty(value = "客户来源", converter = DictConvert.class) + @DictFormat(CRM_CUSTOMER_SOURCE) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_SOURCE) + private Integer source; + + @ExcelProperty("备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java new file mode 100644 index 0000000..bbf7163 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 客户导入 Request VO") +@Data +@Builder +public class CrmCustomerImportReqVO { + + @Schema(description = "Excel 文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "Excel 文件不能为空") + private MultipartFile file; + + @Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否支持更新不能为空") + private Boolean updateSupport; + + @Schema(description = "负责人", example = "1") + private Long ownerUserId; // 为 null 则客户进入公海 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java new file mode 100644 index 0000000..dda5bc5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 客户导入 Response VO") +@Data +@Builder +public class CrmCustomerImportRespVO { + + @Schema(description = "创建成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List createCustomerNames; + + @Schema(description = "更新成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List updateCustomerNames; + + @Schema(description = "导入失败的客户集合,key 为客户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) + private Map failureCustomerNames; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java new file mode 100644 index 0000000..10bf2e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户锁定/解锁 Request VO") +@Data +public class CrmCustomerLockReqVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long id; + + @Schema(description = "客户锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Boolean lockStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java new file mode 100644 index 0000000..73af5d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 客户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmCustomerPageReqVO extends PageParam { + + /** + * 联系状态 - 今日需联系 + */ + public static final int CONTACT_TODAY = 1; + /** + * 联系状态 - 已逾期 + */ + public static final int CONTACT_EXPIRED = 2; + /** + * 联系状态 - 已联系 + */ + public static final int CONTACT_ALREADY = 3; + + @Schema(description = "客户名称", example = "赵六") + private String name; + + @Schema(description = "手机", example = "18000000000") + private String mobile; + + @Schema(description = "所属行业", example = "1") + private Integer industryId; + + @Schema(description = "客户等级", example = "1") + private Integer level; + + @Schema(description = "客户来源", example = "1") + private Integer source; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean pool; // null 则表示为不是公海数据 + + @Schema(description = "联系状态", example = "1") + private Integer contactStatus; // backlog 查询条件 + + @Schema(description = "跟进状态", example = "true") + private Boolean followUpStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java new file mode 100644 index 0000000..2361299 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 客户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmCustomerRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty("客户名称") + private String name; + + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "跟进状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean followUpStatus; + + @Schema(description = "最后跟进时间") + @ExcelProperty("最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") + @ExcelProperty("最后跟进内容") + private String contactLastContent; + + @Schema(description = "下次联系时间") + @ExcelProperty("下次联系时间") + private LocalDateTime contactNextTime; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("负责人的用户编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "锁定状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean lockStatus; + + @Schema(description = "成交状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "成交状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean dealStatus; + + @Schema(description = "手机", example = "25682") + @ExcelProperty("手机") + private String mobile; + + @Schema(description = "电话", example = "25682") + @ExcelProperty("电话") + private String telephone; + + @Schema(description = "QQ", example = "25682") + @ExcelProperty("QQ") + private String qq; + + @Schema(description = "wechat", example = "25682") + @ExcelProperty("wechat") + private String wechat; + + @Schema(description = "email", example = "25682") + @ExcelProperty("email") + private String email; + + @Schema(description = "地区编号", example = "1024") + @ExcelProperty("地区编号") + private Integer areaId; + @Schema(description = "地区名称", example = "北京市") + @ExcelProperty("地区名称") + private String areaName; + @Schema(description = "详细地址", example = "北京市成华大道") + @ExcelProperty("详细地址") + private String detailAddress; + + @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "所属行业", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) + private Integer industryId; + + @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "客户等级", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) + private Integer level; + + @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @ExcelProperty(value = "客户来源", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) + private Integer source; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "距离加入公海时间", example = "1") + private Long poolDay; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java new file mode 100644 index 0000000..daedb78 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAreaParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; + +@Schema(description = "管理后台 - CRM 客户新增/修改 Request VO") +@Data +public class CrmCustomerSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @DiffLogField(name = "客户名称") + @NotEmpty(message = "客户名称不能为空") + private String name; + + @Schema(description = "下次联系时间") + @DiffLogField(name = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime contactNextTime; + + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + @NotNull(message = "负责人的用户编号不能为空") + private Long ownerUserId; + + @Schema(description = "手机", example = "18000000000") + @DiffLogField(name = "手机") + @Mobile + private String mobile; + + @Schema(description = "电话", example = "18000000000") + @DiffLogField(name = "电话") + @Telephone + private String telephone; + + @Schema(description = "QQ", example = "123456789") + @DiffLogField(name = "QQ") + @Size(max = 20, message = "QQ长度不能超过 20 个字符") + private String qq; + + @Schema(description = "微信", example = "123456789") + @DiffLogField(name = "微信") + @Size(max = 255, message = "微信长度不能超过 255 个字符") + private String wechat; + + @Schema(description = "邮箱", example = "123456789@qq.com") + @DiffLogField(name = "邮箱") + @Email(message = "邮箱格式不正确") + @Size(max = 255, message = "邮箱长度不能超过 255 个字符") + private String email; + + @Schema(description = "地区编号", example = "20158") + @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) + private Integer areaId; + + @Schema(description = "详细地址", example = "北京市海淀区") + @DiffLogField(name = "详细地址") + private String detailAddress; + + @Schema(description = "所属行业", example = "1") + @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) + @DictFormat(CRM_CUSTOMER_INDUSTRY) + private Integer industryId; + + @Schema(description = "客户等级", example = "2") + @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) + @InEnum(CrmCustomerLevelEnum.class) + private Integer level; + + @Schema(description = "客户来源", example = "3") + @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) + private Integer source; + + @Schema(description = "备注", example = "随便") + @DiffLogField(name = "备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java new file mode 100644 index 0000000..79578f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; + +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - CRM 客户转移 Request VO") +@Data +public class CrmCustomerTransferReqVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "客户编号不能为空") + private Long id; + + /** + * 新负责人的用户编号 + */ + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + /** + * 老负责人加入团队后的权限级别。如果 null 说明移除 + * + * 关联 {@link CrmPermissionLevelEnum} + */ + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer oldOwnerPermissionLevel; + + /** + * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。选中时,也一起转移 + */ + @Schema(description = "同时转移", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + private List toBizTypes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigPageReqVO.java new file mode 100644 index 0000000..37ce110 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigPageReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 客户限制配置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmCustomerLimitConfigPageReqVO extends PageParam { + + @Schema(description = "规则类型", example = "1") + private Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigRespVO.java new file mode 100644 index 0000000..8ff03ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig; + +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 客户限制配置 Response VO") +@Data +public class CrmCustomerLimitConfigRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27930") + private Long id; + + @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; + + @Schema(description = "规则适用人群") + private List userIds; + + @Schema(description = "规则适用部门") + private List deptIds; + + @Schema(description = "数量上限", requiredMode = Schema.RequiredMode.REQUIRED, example = "28384") + private Integer maxCount; + + @Schema(description = "成交客户是否占有拥有客户数") + private Boolean dealCountEnabled; + + @Schema(description = "规则适用人群名称") + private List users; + + @Schema(description = "规则适用部门名称") + private List depts; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java new file mode 100644 index 0000000..b7c2468 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig; + +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysDeptParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 客户限制配置创建/更新 Request VO") +@Data +public class CrmCustomerLimitConfigSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27930") + private Long id; + + @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "规则类型不能为空") + @DiffLogField(name = "规则类型") + private Integer type; + + @Schema(description = "规则适用人群") + @DiffLogField(name = "规则适用人群", function = SysAdminUserParseFunction.NAME) + private List userIds; + + @Schema(description = "规则适用部门") + @DiffLogField(name = "规则适用部门", function = SysDeptParseFunction.NAME) + private List deptIds; + + @Schema(description = "数量上限", requiredMode = Schema.RequiredMode.REQUIRED, example = "28384") + @NotNull(message = "数量上限不能为空") + @DiffLogField(name = "数量上限") + private Integer maxCount; + + @Schema(description = "成交客户是否占有拥有客户数(当 type = 1 时)") + @DiffLogField(name = "成交客户是否占有拥有客户数") + private Boolean dealCountEnabled; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigRespVO.java new file mode 100644 index 0000000..3408625 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 客户公海规则 Response VO") +@Data +public class CrmCustomerPoolConfigRespVO { + + @Schema(description = "是否启用客户公海", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否启用客户公海不能为空") + private Boolean enabled; + + @Schema(description = "未跟进放入公海天数", example = "2") + private Integer contactExpireDays; + + @Schema(description = "未成交放入公海天数", example = "2") + private Integer dealExpireDays; + + @Schema(description = "是否开启提前提醒", example = "true") + private Boolean notifyEnabled; + + @Schema(description = "提前提醒天数", example = "2") + private Integer notifyDays; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java new file mode 100644 index 0000000..877df82 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig; + +import cn.hutool.core.util.BooleanUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import java.util.Objects; + +@Schema(description = "管理后台 - CRM 客户公海配置的创建/更新 Request VO") +@Data +public class CrmCustomerPoolConfigSaveReqVO { + + @Schema(description = "是否启用客户公海", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @DiffLogField(name = "是否启用客户公海") + @NotNull(message = "是否启用客户公海不能为空") + private Boolean enabled; + + @Schema(description = "未跟进放入公海天数", example = "2") + @DiffLogField(name = "未跟进放入公海天数") + private Integer contactExpireDays; + + @Schema(description = "未成交放入公海天数", example = "2") + @DiffLogField(name = "未成交放入公海天数") + private Integer dealExpireDays; + + @Schema(description = "是否开启提前提醒", example = "true") + @DiffLogField(name = "是否开启提前提醒") + private Boolean notifyEnabled; + + @Schema(description = "提前提醒天数", example = "2") + @DiffLogField(name = "提前提醒天数") + private Integer notifyDays; + + @AssertTrue(message = "未成交放入公海天数不能为空") + @JsonIgnore + public boolean isDealExpireDaysValid() { + if (!BooleanUtil.isTrue(getEnabled())) { + return true; + } + return Objects.nonNull(getDealExpireDays()); + } + + @AssertTrue(message = "未跟进放入公海天数不能为空") + @JsonIgnore + public boolean isContactExpireDaysValid() { + if (!BooleanUtil.isTrue(getEnabled())) { + return true; + } + return Objects.nonNull(getContactExpireDays()); + } + + @AssertTrue(message = "提前提醒天数不能为空") + @JsonIgnore + public boolean isNotifyDaysValid() { + if (!BooleanUtil.isTrue(getNotifyEnabled())) { + return true; + } + return Objects.nonNull(getNotifyDays()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java new file mode 100644 index 0000000..867c4e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + + +@Tag(name = "管理后台 - 跟进记录") +@RestController +@RequestMapping("/crm/follow-up-record") +@Validated +public class CrmFollowUpRecordController { + + @Resource + private CrmFollowUpRecordService followUpRecordService; + @Resource + private CrmContactService contactService; + @Resource + private CrmBusinessService businessService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建跟进记录") + public CommonResult createFollowUpRecord(@Valid @RequestBody CrmFollowUpRecordSaveReqVO createReqVO) { + return success(followUpRecordService.createFollowUpRecord(createReqVO)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除跟进记录") + @Parameter(name = "id", description = "编号", required = true) + public CommonResult deleteFollowUpRecord(@RequestParam("id") Long id) { + followUpRecordService.deleteFollowUpRecord(id, getLoginUserId()); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得跟进记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getFollowUpRecord(@RequestParam("id") Long id) { + CrmFollowUpRecordDO followUpRecord = followUpRecordService.getFollowUpRecord(id); + return success(BeanUtils.toBean(followUpRecord, CrmFollowUpRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得跟进记录分页") + public CommonResult> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { + PageResult pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO); + // 1.1 查询联系人和商机 + Map contactMap = contactService.getContactMap( + convertSetByFlatMap(pageResult.getList(), item -> item.getContactIds().stream())); + Map businessMap = businessService.getBusinessMap( + convertSetByFlatMap(pageResult.getList(), item -> item.getBusinessIds().stream())); + // 1.2 查询用户 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), item -> Long.valueOf(item.getCreator()))); + // 2. 拼接数据 + PageResult voPageResult = BeanUtils.toBean(pageResult, CrmFollowUpRecordRespVO.class, record -> { + // 2.1 设置联系人和商机信息 + record.setBusinesses(new ArrayList<>()).setContacts(new ArrayList<>()); + record.getContactIds().forEach(id -> MapUtils.findAndThen(contactMap, id, contact -> + record.getContacts().add(new CrmBusinessRespVO().setId(contact.getId()).setName(contact.getName())))); + record.getBusinessIds().forEach(id -> MapUtils.findAndThen(businessMap, id, business -> + record.getBusinesses().add(new CrmBusinessRespVO().setId(business.getId()).setName(business.getName())))); + // 2.2 设置用户信息 + MapUtils.findAndThen(userMap, Long.valueOf(record.getCreator()), user -> record.setCreatorName(user.getNickname())); + }); + return success(voPageResult); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java new file mode 100644 index 0000000..78c28a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 跟进记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmFollowUpRecordPageReqVO extends PageParam { + + @Schema(description = "数据类型", example = "2") + private Integer bizType; + + @Schema(description = "数据编号", example = "5564") + private Long bizId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java new file mode 100644 index 0000000..1ce10b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_FOLLOW_UP_TYPE; + +@Schema(description = "管理后台 - 跟进记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmFollowUpRecordRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28800") + private Long id; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer bizType; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5564") + private Long bizId; + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @DictFormat(CRM_FOLLOW_UP_TYPE) + private Integer type; + + @Schema(description = "跟进内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime nextTime; + + @Schema(description = "关联的商机编号数组") + private List businessIds; + @Schema(description = "关联的商机数组") + private List businesses; + + @Schema(description = "关联的联系人编号数组") + private List contactIds; + @Schema(description = "关联的联系人名称数组") + private List contacts; + + @Schema(description = "图片") + private List picUrls; + @Schema(description = "附件") + private List fileUrls; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java new file mode 100644 index 0000000..27960a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 跟进记录新增/修改 Request VO") +@Data +public class CrmFollowUpRecordSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28800") + private Long id; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "数据类型不能为空") + private Integer bizType; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5564") + @NotNull(message = "数据编号不能为空") + private Long bizId; + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "跟进类型不能为空") + private Integer type; + + @Schema(description = "跟进内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "跟进内容不能为空") + private String content; + + @Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "下次联系时间不能为空") + private LocalDateTime nextTime; + + @Schema(description = "关联的商机编号数组") + private List businessIds; + @Schema(description = "关联的联系人编号数组") + private List contactIds; + + @Schema(description = "图片") + private List picUrls; + @Schema(description = "附件") + private List fileUrls; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java new file mode 100644 index 0000000..da4f04a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.crm.controller.admin.operatelog; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogRespVO; +import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +@Tag(name = "管理后台 - CRM 操作日志") +@RestController +@RequestMapping("/crm/operate-log") +@Validated +public class CrmOperateLogController { + + @Resource + private OperateLogApi operateLogApi; + + /** + * {@link CrmBizTypeEnum} 与 {@link LogRecordConstants} 的映射关系 + */ + private static final Map BIZ_TYPE_MAP = new HashMap<>(); + + static { + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CLUE.getType(), CRM_CLUE_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CUSTOMER.getType(), CRM_CUSTOMER_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTACT.getType(), CRM_CONTACT_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_BUSINESS.getType(), CRM_BUSINESS_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTRACT.getType(), CRM_CONTRACT_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_PRODUCT.getType(), CRM_PRODUCT_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), CRM_RECEIVABLE_TYPE); + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), CRM_RECEIVABLE_PLAN_TYPE); + } + + @GetMapping("/page") + @Operation(summary = "获得操作日志") + public CommonResult> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { + OperateLogPageReqDTO reqDTO = new OperateLogPageReqDTO(); + reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 + reqDTO.setType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); + return success(BeanUtils.toBean(operateLogApi.getOperateLogPage(reqDTO), CrmOperateLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogPageReqVO.java new file mode 100644 index 0000000..7bed826 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogPageReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 操作日志 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmOperateLogPageReqVO extends PageParam { + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmBizTypeEnum.class) + @NotNull(message = "数据类型不能为空") + private Integer bizType; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "数据编号不能为空") + private Long bizId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java new file mode 100644 index 0000000..8e458a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 操作日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmOperateLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long id; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String userName; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer userType; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private String type; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "修改客户") + private String subType; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long bizId; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "将什么从什么改为了什么") + private String action; + + @Schema(description = "编号", example = "{orderId: 1}") + private String extra; + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-01") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.http b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.http new file mode 100644 index 0000000..1ef2bc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.http @@ -0,0 +1,32 @@ +### 请求 /add +POST {{baseUrl}}/crm/permission/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "userId": 1, + "bizType": 2, + "bizId": 2, + "level": 1 +} + +### 请求 /update +PUT {{baseUrl}}/crm/permission/update +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "userId": 1, + "bizType": 2, + "bizId": 2, + "level": 1, + "id": 1 +} + +### 请求 /delete +DELETE {{baseUrl}}/crm/permission/delete?bizType=2&bizId=1&id=1 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java new file mode 100644 index 0000000..1a829ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.crm.controller.admin.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.google.common.collect.Multimaps; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - CRM 数据权限") +@RestController +@RequestMapping("/crm/permission") +@Validated +public class CrmPermissionController { + + @Resource + private CrmPermissionService permissionService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @Resource + private PostApi postApi; + + @PostMapping("/create") + @Operation(summary = "创建数据权限") + public CommonResult create(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) { + permissionService.createPermission(reqVO, getLoginUserId()); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "编辑数据权限") + @CrmPermission(bizTypeValue = "#updateReqVO.bizType", bizId = "#updateReqVO.bizId" + , level = CrmPermissionLevelEnum.OWNER) + public CommonResult updatePermission(@Valid @RequestBody CrmPermissionUpdateReqVO updateReqVO) { + permissionService.updatePermission(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除数据权限") + @Parameter(name = "ids", description = "数据权限编号", required = true, example = "1024") + public CommonResult deletePermission(@RequestParam("ids") Collection ids) { + permissionService.deletePermissionBatch(ids, getLoginUserId()); + return success(true); + } + + @DeleteMapping("/delete-self") + @Operation(summary = "删除自己的数据权限") + @Parameter(name = "id", description = "数据权限编号", required = true, example = "1024") + public CommonResult deleteSelfPermission(@RequestParam("id") Long id) { + permissionService.deleteSelfPermission(id, getLoginUserId()); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获得数据权限列表") + @Parameters({ + @Parameter(name = "bizType", description = "CRM 类型", required = true, example = "2"), + @Parameter(name = "bizId", description = "CRM 类型数据编号", required = true, example = "1024") + }) + public CommonResult> getPermissionList(@RequestParam("bizType") Integer bizType, + @RequestParam("bizId") Long bizId) { + List permissions = permissionService.getPermissionListByBiz(bizType, bizId); + if (CollUtil.isEmpty(permissions)) { + return success(Collections.emptyList()); + } + + // 查询相关数据 + Map userMap = adminUserApi.getUserMap( + convertSet(permissions, CrmPermissionDO::getUserId)); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + Map postMap = postApi.getPostMap( + convertSetByFlatMap(userMap.values(), AdminUserRespDTO::getPostIds, + item -> item != null ? item.stream() : Stream.empty())); + // 拼接数据 + return success(CollectionUtils.convertList(BeanUtils.toBean(permissions, CrmPermissionRespVO.class), item -> { + findAndThen(userMap, item.getUserId(), user -> { + item.setNickname(user.getNickname()); + findAndThen(deptMap, user.getDeptId(), deptRespDTO -> item.setDeptName(deptRespDTO.getName())); + if (CollUtil.isEmpty(user.getPostIds())) { + item.setPostNames(Collections.emptySet()); + return; + } + List postList = MapUtils.getList(Multimaps.forMap(postMap), user.getPostIds()); + item.setPostNames(CollectionUtils.convertSet(postList, PostRespDTO::getName)); + }); + return item; + })); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java new file mode 100644 index 0000000..28985ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.crm.controller.admin.permission.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - CRM 数据权限 Response VO") +@Data +public class CrmPermissionRespVO { + + @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "CRM 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmBizTypeEnum.class) + @NotNull(message = "CRM 类型不能为空") + private Integer bizType; + + @Schema(description = "CRM 类型数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "CRM 类型数据编号不能为空") + private Long bizId; + + @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmPermissionLevelEnum.class) + @NotNull(message = "权限级别不能为空") + private Integer level; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String deptName; + + @Schema(description = "岗位名称数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[BOOS,经理]") + private Set postNames; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-01-01 00:00:00") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java new file mode 100644 index 0000000..ec66dcb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.controller.admin.permission.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +import java.util.List; + +@Schema(description = "管理后台 - CRM 数据权限创建/更新 Request VO") +@Data +public class CrmPermissionSaveReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "CRM 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmBizTypeEnum.class) + @NotNull(message = "CRM 类型不能为空") + private Integer bizType; + + @Schema(description = "CRM 类型数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "CRM 类型数据编号不能为空") + private Long bizId; + + @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmPermissionLevelEnum.class) + @NotNull(message = "权限级别不能为空") + private Integer level; + + /** + * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。 + * 选中时,同时添加对应的权限 + */ + @Schema(description = "同时添加", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + private List toBizTypes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java new file mode 100644 index 0000000..d49f566 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.controller.admin.permission.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - CRM 数据权限更新 Request VO") +@Data +public class CrmPermissionUpdateReqVO { + + @Schema(description = "数据权限编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2]") + @NotNull(message = "数据权限编号列表不能为空") + private List ids; + + @Schema(description = "Crm 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmBizTypeEnum.class) + @NotNull(message = "Crm 类型不能为空") + private Integer bizType; + + @Schema(description = "Crm 类型数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "Crm 类型数据编号不能为空") + private Long bizId; + + @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmPermissionLevelEnum.class) + @NotNull(message = "权限级别不能为空") + private Integer level; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductCategoryController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductCategoryController.java new file mode 100644 index 0000000..dec0d62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductCategoryController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 产品分类") +@RestController +@RequestMapping("/crm/product-category") +@Validated +public class CrmProductCategoryController { + + @Resource + private CrmProductCategoryService productCategoryService; + + @PostMapping("/create") + @Operation(summary = "创建产品分类") + @PreAuthorize("@ss.hasPermission('crm:product-category:create')") + public CommonResult createProductCategory(@Valid @RequestBody CrmProductCategoryCreateReqVO createReqVO) { + return success(productCategoryService.createProductCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品分类") + @PreAuthorize("@ss.hasPermission('crm:product-category:update')") + public CommonResult updateProductCategory(@Valid @RequestBody CrmProductCategoryCreateReqVO updateReqVO) { + productCategoryService.updateProductCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:product-category:delete')") + public CommonResult deleteProductCategory(@RequestParam("id") Long id) { + productCategoryService.deleteProductCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:product-category:query')") + public CommonResult getProductCategory(@RequestParam("id") Long id) { + CrmProductCategoryDO category = productCategoryService.getProductCategory(id); + return success(BeanUtils.toBean(category, CrmProductCategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得产品分类列表") + @PreAuthorize("@ss.hasPermission('crm:product-category:query')") + public CommonResult> getProductCategoryList(@Valid CrmProductCategoryListReqVO listReqVO) { + List list = productCategoryService.getProductCategoryList(listReqVO); + return success(BeanUtils.toBean(list, CrmProductCategoryRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java new file mode 100644 index 0000000..933cf48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.translate.core.TranslateUtils; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - CRM 产品") +@RestController +@RequestMapping("/crm/product") +@Validated +public class CrmProductController { + + @Resource + private CrmProductService productService; + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建产品") + @PreAuthorize("@ss.hasPermission('crm:product:create')") + public CommonResult createProduct(@Valid @RequestBody CrmProductSaveReqVO createReqVO) { + return success(productService.createProduct(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品") + @PreAuthorize("@ss.hasPermission('crm:product:update')") + public CommonResult updateProduct(@Valid @RequestBody CrmProductSaveReqVO updateReqVO) { + productService.updateProduct(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:product:delete')") + public CommonResult deleteProduct(@RequestParam("id") Long id) { + productService.deleteProduct(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:product:query')") + public CommonResult getProduct(@RequestParam("id") Long id) { + CrmProductDO product = productService.getProduct(id); + return success(BeanUtils.toBean(product, CrmProductRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") + public CommonResult> getProductSimpleList() { + List list = productService.getProductListByStatus(CrmProductStatusEnum.ENABLE.getStatus()); + return success(convertList(list, product -> new CrmProductRespVO().setId(product.getId()).setName(product.getName()) + .setUnit(product.getUnit()).setNo(product.getNo()).setPrice(product.getPrice()))); + } + + @GetMapping("/page") + @Operation(summary = "获得产品分页") + @PreAuthorize("@ss.hasPermission('crm:product:query')") + public CommonResult> getProductPage(@Valid CrmProductPageReqVO pageVO) { + PageResult pageResult = productService.getProductPage(pageVO); + return success(BeanUtils.toBean(pageResult, CrmProductRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品 Excel") + @PreAuthorize("@ss.hasPermission('crm:product:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductExcel(@Valid CrmProductPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = productService.getProductPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品.xls", "数据", CrmProductRespVO.class, + TranslateUtils.translate(BeanUtils.toBean(list, CrmProductRespVO.class))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryCreateReqVO.java new file mode 100644 index 0000000..8b77e97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.category; + +import com.mzt.logapi.starter.annotation.DiffLogField; +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - CRM 产品分类创建/更新 Request VO") +@Data +public class CrmProductCategoryCreateReqVO{ + + @Schema(description = "分类编号", example = "23902") + private Long id; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotNull(message = "分类名称不能为空") + @DiffLogField(name = "分类名称") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4680") + @NotNull(message = "父级编号不能为空") + private Long parentId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryListReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryListReqVO.java new file mode 100644 index 0000000..6144c95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryListReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.category; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 产品分类列表 Request VO") +@Data +public class CrmProductCategoryListReqVO { + + @ExcelProperty("名称") + private String name; + + @ExcelProperty("父级 id") + private Long parentId; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryRespVO.java new file mode 100644 index 0000000..4cea8e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/category/CrmProductCategoryRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 产品分类 Response VO") +@Data +public class CrmProductCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23902") + private Long id; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4680") + private Long parentId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductPageReqVO.java new file mode 100644 index 0000000..39b1090 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.product; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 产品分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmProductPageReqVO extends PageParam { + + @Schema(description = "产品名称", example = "李四") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java new file mode 100644 index 0000000..43d2c74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.product; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 产品 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmProductRespVO implements VO { + + @Schema(description = "产品编号", example = "20529") + @ExcelProperty("产品编号") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "好产品") + @ExcelProperty("产品名称") + private String name; + + @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "12306") + @ExcelProperty("产品编码") + private String no; + + @Schema(description = "单位", example = "2") + @ExcelProperty(value = "单位", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CRM_PRODUCT_UNIT) + private Integer unit; + + @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + @ExcelProperty("价格,单位:分") + private BigDecimal price; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") + @ExcelProperty(value = "单位", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CRM_PRODUCT_STATUS) + private Integer status; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Trans(type = TransType.SIMPLE, target = CrmProductCategoryDO.class, fields = "name", ref = "categoryName") + private Long categoryId; + @Schema(description = "产品分类名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "衣服") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "产品描述", example = "你说的对") + @ExcelProperty("产品描述") + private String description; + + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31926") + @Trans(type = TransType.RPC, targetClassName = "cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO", + fields = "nickname", ref = "ownerUserName") + private Long ownerUserId; + @Schema(description = "负责人的用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @ExcelProperty("负责人") + private String ownerUserName; + + @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Trans(type = TransType.RPC, targetClassName = "cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO", + fields = "nickname", ref = "creatorName") + private String creator; + @Schema(description = "创建人名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @ExcelProperty("创建人") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java new file mode 100644 index 0000000..1c1a660 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.crm.controller.admin.product.vo.product; + +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmProductStatusParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmProductUnitParseFunction; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 产品创建/修改 Request VO") +@Data +public class CrmProductSaveReqVO { + + @Schema(description = "产品编号", example = "20529") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "好产品") + @NotNull(message = "产品名称不能为空") + @DiffLogField(name = "产品名称") + private String name; + + @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "12306") + @NotNull(message = "产品编码不能为空") + @DiffLogField(name = "产品编码") + private String no; + + @Schema(description = "单位", example = "2") + @DiffLogField(name = "单位", function = CrmProductUnitParseFunction.NAME) + private Integer unit; + + @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + @NotNull(message = "价格不能为空") + @DiffLogField(name = "价格") + private BigDecimal price; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") + @NotNull(message = "状态不能为空") + @DiffLogField(name = "状态", function = CrmProductStatusParseFunction.NAME) + private Integer status; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "产品分类编号不能为空") + @DiffLogField(name = "产品分类编号") + private Long categoryId; + + @Schema(description = "产品描述", example = "你说的对") + @DiffLogField(name = "产品描述") + private String description; + + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31926") + @NotNull(message = "负责人的用户编号不能为空") + private Long ownerUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java new file mode 100644 index 0000000..ddcf1e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - CRM 回款") +@RestController +@RequestMapping("/crm/receivable") +@Validated +public class CrmReceivableController { + + @Resource + private CrmReceivableService receivableService; + @Resource + private CrmContractService contractService; + @Resource + private CrmCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @PostMapping("/create") + @Operation(summary = "创建回款") + @PreAuthorize("@ss.hasPermission('crm:receivable:create')") + public CommonResult createReceivable(@Valid @RequestBody CrmReceivableSaveReqVO createReqVO) { + return success(receivableService.createReceivable(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新回款") + @PreAuthorize("@ss.hasPermission('crm:receivable:update')") + public CommonResult updateReceivable(@Valid @RequestBody CrmReceivableSaveReqVO updateReqVO) { + receivableService.updateReceivable(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除回款") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:receivable:delete')") + public CommonResult deleteReceivable(@RequestParam("id") Long id) { + receivableService.deleteReceivable(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得回款") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:receivable:query')") + public CommonResult getReceivable(@RequestParam("id") Long id) { + CrmReceivableDO receivable = receivableService.getReceivable(id); + return success(buildReceivableDetail(receivable)); + } + + private CrmReceivableRespVO buildReceivableDetail(CrmReceivableDO receivable) { + if (receivable == null) { + return null; + } + return buildReceivableDetailList(Collections.singletonList(receivable)).get(0); + } + + @GetMapping("/page") + @Operation(summary = "获得回款分页") + @PreAuthorize("@ss.hasPermission('crm:receivable:query')") + public CommonResult> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) { + PageResult pageResult = receivableService.getReceivablePage(pageReqVO, getLoginUserId()); + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-customer") + @Operation(summary = "获得回款分页,基于指定客户") + public CommonResult> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) { + Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); + PageResult pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO); + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出回款 Excel") + @PreAuthorize("@ss.hasPermission('crm:receivable:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportReceivableExcel(@Valid CrmReceivablePageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PAGE_SIZE_NONE); + List list = receivableService.getReceivablePage(exportReqVO, getLoginUserId()).getList(); + // 导出 Excel + ExcelUtils.write(response, "回款.xls", "数据", CrmReceivableRespVO.class, + buildReceivableDetailList(list)); + } + + private List buildReceivableDetailList(List receivableList) { + if (CollUtil.isEmpty(receivableList)) { + return Collections.emptyList(); + } + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(receivableList, CrmReceivableDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.3 获得合同列表 + Map contractMap = contractService.getContractMap( + convertSet(receivableList, CrmReceivableDO::getContractId)); + // 2. 拼接结果 + return BeanUtils.toBean(receivableList, CrmReceivableRespVO.class, (receivableVO) -> { + // 2.1 拼接客户名称 + findAndThen(customerMap, receivableVO.getCustomerId(), customer -> receivableVO.setCustomerName(customer.getName())); + // 2.2 拼接负责人、创建人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(receivableVO.getCreator()), + user -> receivableVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, receivableVO.getOwnerUserId(), user -> { + receivableVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> receivableVO.setOwnerUserDeptName(dept.getName())); + }); + // 2.3 拼接合同信息 + findAndThen(contractMap, receivableVO.getContractId(), contract -> + receivableVO.setContract(BeanUtils.toBean(contract, CrmContractRespVO.class))); + }); + } + + @PutMapping("/submit") + @Operation(summary = "提交回款审批") + @PreAuthorize("@ss.hasPermission('crm:receivable:update')") + public CommonResult submitContract(@RequestParam("id") Long id) { + receivableService.submitReceivable(id, getLoginUserId()); + return success(true); + } + + @GetMapping("/audit-count") + @Operation(summary = "获得待审核回款数量") + @PreAuthorize("@ss.hasPermission('crm:receivable:query')") + public CommonResult getAuditReceivableCount() { + return success(receivableService.getAuditReceivableCount(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java new file mode 100644 index 0000000..74ba2e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivablePlanService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - CRM 回款计划") +@RestController +@RequestMapping("/crm/receivable-plan") +@Validated +public class CrmReceivablePlanController { + + @Resource + private CrmReceivablePlanService receivablePlanService; + @Resource + private CrmReceivableService receivableService; + @Resource + private CrmContractService contractService; + @Resource + private CrmCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建回款计划") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:create')") + public CommonResult createReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO createReqVO) { + return success(receivablePlanService.createReceivablePlan(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新回款计划") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:update')") + public CommonResult updateReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO updateReqVO) { + receivablePlanService.updateReceivablePlan(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除回款计划") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:delete')") + public CommonResult deleteReceivablePlan(@RequestParam("id") Long id) { + receivablePlanService.deleteReceivablePlan(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得回款计划") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") + public CommonResult getReceivablePlan(@RequestParam("id") Long id) { + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(id); + return success(buildReceivablePlanDetail(receivablePlan)); + } + + private CrmReceivablePlanRespVO buildReceivablePlanDetail(CrmReceivablePlanDO receivablePlan) { + if (receivablePlan == null) { + return null; + } + return buildReceivableDetailList(Collections.singletonList(receivablePlan)).get(0); + } + + @GetMapping("/page") + @Operation(summary = "获得回款计划分页") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") + public CommonResult> getReceivablePlanPage(@Valid CrmReceivablePlanPageReqVO pageReqVO) { + PageResult pageResult = receivablePlanService.getReceivablePlanPage(pageReqVO, getLoginUserId()); + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/page-by-customer") + @Operation(summary = "获得回款计划分页,基于指定客户") + public CommonResult> getReceivablePlanPageByCustomer(@Valid CrmReceivablePlanPageReqVO pageReqVO) { + Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); + PageResult pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出回款计划 Excel") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportReceivablePlanExcel(@Valid CrmReceivablePlanPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PAGE_SIZE_NONE); + List list = receivablePlanService.getReceivablePlanPage(exportReqVO, getLoginUserId()).getList(); + // 导出 Excel + ExcelUtils.write(response, "回款计划.xls", "数据", CrmReceivablePlanRespVO.class, + buildReceivableDetailList(list)); + } + + private List buildReceivableDetailList(List receivablePlanList) { + if (CollUtil.isEmpty(receivablePlanList)) { + return Collections.emptyList(); + } + // 1.1 获取客户 Map + Map customerMap = customerService.getCustomerMap( + convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + // 1.3 获得合同 Map + Map contractMap = contractService.getContractMap( + convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); + // 1.4 获得回款 Map + Map receivableMap = receivableService.getReceivableMap( + convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); + // 2. 拼接数据 + return BeanUtils.toBean(receivablePlanList, CrmReceivablePlanRespVO.class, (receivablePlanVO) -> { + // 2.1 拼接客户信息 + findAndThen(customerMap, receivablePlanVO.getCustomerId(), customer -> receivablePlanVO.setCustomerName(customer.getName())); + // 2.2 拼接用户信息 + findAndThen(userMap, receivablePlanVO.getOwnerUserId(), user -> receivablePlanVO.setOwnerUserName(user.getNickname())); + findAndThen(userMap, Long.parseLong(receivablePlanVO.getCreator()), user -> receivablePlanVO.setCreatorName(user.getNickname())); + // 2.3 拼接合同信息 + findAndThen(contractMap, receivablePlanVO.getContractId(), contract -> receivablePlanVO.setContractNo(contract.getNo())); + // 2.4 拼接回款信息 + receivablePlanVO.setReceivable(BeanUtils.toBean(receivableMap.get(receivablePlanVO.getReceivableId()), CrmReceivableRespVO.class)); + }); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") + @Parameters({ + @Parameter(name = "customerId", description = "客户编号", required = true), + @Parameter(name = "contractId", description = "合同编号", required = true) + }) + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") + public CommonResult> getReceivablePlanSimpleList(@RequestParam("customerId") Long customerId, + @RequestParam("contractId") Long contractId) { + CrmReceivablePlanPageReqVO pageReqVO = new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId); + pageReqVO.setPageNo(PAGE_SIZE_NONE); + PageResult pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); + return success(convertList(pageResult.getList(), receivablePlan -> new CrmReceivablePlanRespVO() // 只返回 id、period 等信息 + .setId(receivablePlan.getId()).setPeriod(receivablePlan.getPeriod()).setReceivableId(receivablePlan.getReceivableId()) + .setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType()))); + } + + @GetMapping("/remind-count") + @Operation(summary = "获得待回款提醒数量") + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") + public CommonResult getReceivablePlanRemindCount() { + return success(receivablePlanService.getReceivablePlanRemindCount(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java new file mode 100644 index 0000000..b730128 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 回款计划分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmReceivablePlanPageReqVO extends PageParam { + + /** + * 提醒类型 - 待回款 + */ + public final static Integer REMIND_TYPE_NEEDED = 1; + /** + * 提醒类型 - 已逾期 + */ + public final static Integer REMIND_TYPE_EXPIRED = 2; + /** + * 提醒类型 - 已回款 + */ + public final static Integer REMIND_TYPE_RECEIVED = 3; + + @Schema(description = "客户编号", example = "18026") + private Long customerId; + + @Schema(description = "合同编号", example = "H3473") + private String contractNo; + + @Schema(description = "合同编号", example = "3473") + private Long contractId; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "提醒类型", example = "1") + private Integer remindType; // 提醒类型,为 null 时则表示全部 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java new file mode 100644 index 0000000..ad1ce3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; + +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 回款计划 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmReceivablePlanRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("期数") + private Integer period; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("客户编号") + private Long customerId; + @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @ExcelProperty("客户名字") + private String customerName; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("合同编号") + private Long contractId; + @Schema(description = "合同编号", example = "Q110") + @ExcelProperty("合同编号") + private String contractNo; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("负责人编号") + private Long ownerUserId; + @Schema(description = "负责人", example = "test") + @ExcelProperty("负责人") + private String ownerUserName; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("计划回款日期") + private LocalDateTime returnTime; + + @Schema(description = "计划回款方式", example = "1") + @ExcelProperty("计划回款方式") + private Integer returnType; + + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @ExcelProperty("计划回款金额") + private BigDecimal price; + + @Schema(description = "回款编号", example = "19852") + @ExcelProperty("回款编号") + private Long receivableId; + @Schema(description = "回款信息") + @ExcelProperty("回款信息") + private CrmReceivableRespVO receivable; + + @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("提前几天提醒") + private Integer remindDays; + + @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("提醒日期") + private LocalDateTime remindTime; + + @Schema(description = "备注", example = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java new file mode 100644 index 0000000..cefb02a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 回款计划新增/修改 Request VO") +@Data +public class CrmReceivablePlanSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long id; + + @Schema(description = "客户编号", hidden = true, example = "2") + private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "合同编号不能为空") + private Long contractId; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "负责人编号不能为空") + private Long ownerUserId; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @NotNull(message = "计划回款日期不能为空") + private LocalDateTime returnTime; + + @Schema(description = "回款方式", example = "1") + private Integer returnType; + + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @NotNull(message = "计划回款金额不能为空") + private BigDecimal price; + + @Schema(description = "提前几天提醒", example = "1") + private Integer remindDays; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java new file mode 100644 index 0000000..415816c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 回款分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmReceivablePageReqVO extends PageParam { + + @Schema(description = "回款编号") + private String no; + + @Schema(description = "回款计划编号", example = "31177") + private Long planId; + + @Schema(description = "客户编号", example = "4963") + private Long customerId; + + @Schema(description = "合同编号", example = "4963") + private Long contractId; + + @Schema(description = "场景类型", example = "1") + @InEnum(CrmSceneTypeEnum.class) + private Integer sceneType; // 场景类型,为 null 时则表示全部 + + @Schema(description = "审批状态", example = "20") + @InEnum(CrmAuditStatusEnum.class) + private Integer auditStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java new file mode 100644 index 0000000..12dcbaa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; + +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 回款 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmReceivableRespVO { + + @Schema(description = "编号", example = "25787") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "回款编号", example = "31177") + @ExcelProperty("回款编号") + private String no; + + @Schema(description = "回款计划编号", example = "1024") + @ExcelProperty("回款计划编号") + private Long planId; + + @Schema(description = "回款方式", example = "2") + @ExcelProperty("回款方式") + private Integer returnType; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @ExcelProperty("回款金额") + private BigDecimal price; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("计划回款日期") + private LocalDateTime returnTime; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("客户编号") + private Long customerId; + @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @ExcelProperty("客户名字") + private String customerName; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("合同编号") + private Long contractId; + @Schema(description = "合同信息") + @ExcelProperty("合同信息") + private CrmContractRespVO contract; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("负责人的用户编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "工作流编号", example = "1043") + @ExcelProperty("工作流编号") + private String processInstanceId; + + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("审批状态") + private Integer auditStatus; + + @Schema(description = "工作流编号", example = "备注") + @ExcelProperty("工作流编号") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人", example = "25682") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "test") + @ExcelProperty("创建人名字") + private String creatorName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java new file mode 100644 index 0000000..1064fc9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 回款新增/修改 Request VO") +@Data +public class CrmReceivableSaveReqVO { + + @Schema(description = "编号", example = "25787") + private Long id; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) + @NotNull(message = "负责人编号不能为空") + private Long ownerUserId; + + @Schema(description = "客户编号", example = "2") + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) + private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @DiffLogField(name = "合同", function = CrmContractParseFunction.NAME) + @NotNull(message = "合同编号不能为空") + private Long contractId; + + @Schema(description = "回款计划编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @DiffLogField(name = "合同", function = CrmReceivablePlanParseFunction.NAME) + private Long planId; + + @Schema(description = "回款方式", example = "2") + @DiffLogField(name = "回款方式", function = CrmReceivableReturnTypeParseFunction.NAME) + @InEnum(CrmReceivableReturnTypeEnum.class) + private Integer returnType; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @DiffLogField(name = "回款金额") + @NotNull(message = "回款金额不能为空") + private BigDecimal price; + + @Schema(description = "回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @NotNull(message = "回款日期不能为空") + @DiffLogField(name = "回款日期") + private LocalDateTime returnTime; + + @Schema(description = "备注", example = "备注") + @DiffLogField(name = "备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http new file mode 100644 index 0000000..6b96051 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -0,0 +1,65 @@ +# == 1. 客户总量分析 == +### 1.1 客户总量分析(按日期) +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&interval=2×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 1.2 客户总量统计(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +# == 2. 客户跟进次数分析 == +### 2.1 客户跟进次数分析(按日期) +GET {{baseUrl}}/crm/statistics-customer/get-follow-up-summary-by-date?deptId=100&interval=2×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 2.2 客户总量统计(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-follow-up-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +# == 3. 客户跟进方式分析 == +### 3.1 客户跟进方式分析 +GET {{baseUrl}}/crm/statistics-customer/get-follow-up-summary-by-type?deptId=100&interval=2×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +# == 4. 客户成交周期 == +### 4.1 合同摘要信息(客户转化率页面) +GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100&interval=2×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +# == 5. 客户成交周期 == +### 5.1 获取客户公海分析(按日期) +GET {{baseUrl}}/crm/statistics-customer/get-pool-summary-by-date?deptId=100&interval=2×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 5.2 获取客户公海分析(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-pool-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +# == 6. 客户成交周期 == +### 6.1 客户成交周期(按日期) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&interval=2×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 6.2 获取客户成交周期(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 6.3 获取客户成交周期(按区域) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-area?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 6.4 获取客户成交周期(按产品) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-product?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java new file mode 100644 index 0000000..f9586e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 客户统计") +@RestController +@RequestMapping("/crm/statistics-customer") +@Validated +public class CrmStatisticsCustomerController { + + @Resource + private CrmStatisticsCustomerService customerService; + + @GetMapping("/get-customer-summary-by-date") + @Operation(summary = "获取客户总量分析(按日期)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerSummaryByDate(reqVO)); + } + + @GetMapping("/get-customer-summary-by-user") + @Operation(summary = "获取客户总量分析(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerSummaryByUser(reqVO)); + } + + @GetMapping("/get-follow-up-summary-by-date") + @Operation(summary = "获取客户跟进次数分析(按日期)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getFollowupSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByDate(reqVO)); + } + + @GetMapping("/get-follow-up-summary-by-user") + @Operation(summary = "获取客户跟进次数分析(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getFollowUpSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByUser(reqVO)); + } + + @GetMapping("/get-follow-up-summary-by-type") + @Operation(summary = "获取客户跟进次数分析(按类型)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getFollowUpSummaryByType(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByType(reqVO)); + } + + @GetMapping("/get-contract-summary") + @Operation(summary = "获取客户的首次合同、回款信息列表", description = "用于【客户转化率】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getContractSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getContractSummary(reqVO)); + } + + @GetMapping("/get-pool-summary-by-date") + @Operation(summary = "获取公海客户分析(按日期)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getPoolSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getPoolSummaryByDate(reqVO)); + } + + @GetMapping("/get-pool-summary-by-user") + @Operation(summary = "获取公海客户分析(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getPoolSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getPoolSummaryByUser(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-date") + @Operation(summary = "获取客户成交周期(按日期)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByDate(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-user") + @Operation(summary = "获取客户成交周期(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByUser(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-area") + @Operation(summary = "获取客户成交周期(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByArea(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByArea(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-product") + @Operation(summary = "获取客户成交周期(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByProduct(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByProduct(reqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java new file mode 100644 index 0000000..17451e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.business.CrmBusinessController; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 销售漏斗") +@RestController +@RequestMapping("/crm/statistics-funnel") +@Validated +public class CrmStatisticsFunnelController { + + @Resource + private CrmStatisticsFunnelService funnelService; + + @GetMapping("/get-funnel-summary") + @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面的【销售漏斗分析】") + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") + public CommonResult getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) { + return success(funnelService.getFunnelSummary(reqVO)); + } + + @GetMapping("/get-business-summary-by-end-status") + @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面的【销售漏斗分析】") + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") + public CommonResult> getBusinessSummaryByEndStatus(@Valid CrmStatisticsFunnelReqVO reqVO) { + return success(funnelService.getBusinessSummaryByEndStatus(reqVO)); + } + + @GetMapping("/get-business-summary-by-date") + @Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") + public CommonResult> getBusinessSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) { + return success(funnelService.getBusinessSummaryByDate(reqVO)); + } + + @GetMapping("/get-business-inversion-rate-summary-by-date") + @Operation(summary = "获取商机转化率分析(按日期)", description = "用于【销售漏斗】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") + public CommonResult> getBusinessInversionRateSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) { + return success(funnelService.getBusinessInversionRateSummaryByDate(reqVO)); + } + + @GetMapping("/get-business-page-by-date") + @Operation(summary = "获得商机分页(按日期)", description = "用于【销售漏斗】页面的【新增商机分析】") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult> getBusinessPageByDate(@Valid CrmStatisticsFunnelReqVO pageVO) { + PageResult pageResult = funnelService.getBusinessPageByDate(pageVO); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); + } + + private List buildBusinessDetailList(List list) { + return SpringUtil.getBean(CrmBusinessController.class).buildBusinessDetailList(list); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java new file mode 100644 index 0000000..6f705aa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPerformanceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - CRM 员工业绩统计") +@RestController +@RequestMapping("/crm/statistics-performance") +@Validated +public class CrmStatisticsPerformanceController { + + @Resource + private CrmStatisticsPerformanceService performanceService; + + @GetMapping("/get-contract-count-performance") + @Operation(summary = "合同数量统计", description = "用于【合同数量分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getContractCountPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getContractCountPerformance(performanceReqVO)); + } + + @GetMapping("/get-contract-price-performance") + @Operation(summary = "合同金额统计") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getContractPriceStaffPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getContractPricePerformance(performanceReqVO)); + } + + @GetMapping("/get-receivable-price-performance") + @Operation(summary = "回款金额统计") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getReceivablePriceStaffPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getReceivablePricePerformance(performanceReqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java new file mode 100644 index 0000000..101b9c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPortraitService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 客户画像") +@RestController +@RequestMapping("/crm/statistics-portrait") +@Validated +public class CrmStatisticsPortraitController { + + @Resource + private CrmStatisticsPortraitService statisticsPortraitService; + + @GetMapping("/get-customer-area-summary") + @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerAreaSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByArea(reqVO)); + } + + @GetMapping("/get-customer-industry-summary") + @Operation(summary = "获取客户行业统计数据", description = "用于【客户行业分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerIndustrySummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByIndustry(reqVO)); + } + + @GetMapping("/get-customer-level-summary") + @Operation(summary = "获取客户级别统计数据", description = "用于【客户级别分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerLevelSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByLevel(reqVO)); + } + + @GetMapping("/get-customer-source-summary") + @Operation(summary = "获取客户来源统计数据", description = "用于【客户来源分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerSourceSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryBySource(reqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http new file mode 100644 index 0000000..e878ba1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http @@ -0,0 +1,9 @@ +### 合同金额排行榜 +GET {{baseUrl}}/crm/statistics-rank/get-contract-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 回款金额排行榜 +GET {{baseUrl}}/crm/statistics-rank/get-receivable-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java new file mode 100644 index 0000000..020381d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsRankService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 排行榜统计") +@RestController +@RequestMapping("/crm/statistics-rank") +@Validated +public class CrmStatisticsRankController { + + @Resource + private CrmStatisticsRankService rankService; + + @GetMapping("/get-contract-price-rank") + @Operation(summary = "获得合同金额排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getContractPriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContractPriceRank(rankingReqVO)); + } + + @GetMapping("/get-receivable-price-rank") + @Operation(summary = "获得回款金额排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getReceivablePriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getReceivablePriceRank(rankingReqVO)); + } + + @GetMapping("/get-contract-count-rank") + @Operation(summary = "获得签约合同数量排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getContractCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContractCountRank(rankingReqVO)); + } + + @GetMapping("/get-product-sales-rank") + @Operation(summary = "获得产品销量排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getProductSalesRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getProductSalesRank(rankingReqVO)); + } + + @GetMapping("/get-customer-count-rank") + @Operation(summary = "获得新增客户数排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getCustomerCountRank(rankingReqVO)); + } + + @GetMapping("/get-contacts-count-rank") + @Operation(summary = "获得新增联系人数排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getContactsCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContactsCountRank(rankingReqVO)); + } + + @GetMapping("/get-follow-count-rank") + @Operation(summary = "获得跟进次数排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getFollowCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getFollowCountRank(rankingReqVO)); + } + + @GetMapping("/get-follow-customer-count-rank") + @Operation(summary = "获得跟进客户数排行榜") + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") + public CommonResult> getFollowCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getFollowCustomerCountRank(rankingReqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java new file mode 100644 index 0000000..bde0029 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户客户统计响应 Base Response VO + * + * 目的:可以统一拼接子 VO 的 ownerUserId、ownerUserName 属性 + */ +@Data +public class CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String ownerUserName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java new file mode 100644 index 0000000..fa03d46 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 客户转化率分析 VO") +@Data +public class CrmStatisticsCustomerContractSummaryRespVO { + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String customerName; + + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示合同") + private String contractName; + + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") + private BigDecimal totalPrice; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") + private BigDecimal receivablePrice; + + @Schema(description = "客户行业编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer industryId; + + @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer source; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String ownerUserName; + + @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String creator; + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "源码") + private String creatorUserName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-01 13:24:26") + private LocalDateTime createTime; + + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02 00:00:00") + private LocalDateTime orderDate; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java new file mode 100644 index 0000000..3698378 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户成交周期分析(按区域) VO") +@Data +public class CrmStatisticsCustomerDealCycleByAreaRespVO { + + @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @JsonIgnore + private Integer areaId; + + @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") + private String areaName; + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java new file mode 100644 index 0000000..62facb0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户成交周期分析(按日期) VO") +@Data +public class CrmStatisticsCustomerDealCycleByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java new file mode 100644 index 0000000..442c195 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户成交周期分析(按产品) VO") +@Data +public class CrmStatisticsCustomerDealCycleByProductRespVO { + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示产品") + private String productName; + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java new file mode 100644 index 0000000..1c394b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 成交周期分析(按用户) VO") +@Data +public class CrmStatisticsCustomerDealCycleByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java new file mode 100644 index 0000000..620a008 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 数据统计的员工客户分析 Request VO") +@Data +public class CrmStatisticsCustomerReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") + private Integer interval; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java new file mode 100644 index 0000000..7ffcb20 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户总量分析(按日期) VO") +@Data +public class CrmStatisticsCustomerSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCreateCount; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java new file mode 100644 index 0000000..fa8372b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 客户总量分析(按用户) VO") +@Data +public class CrmStatisticsCustomerSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCreateCount; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount; + + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal contractPrice; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal receivablePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java new file mode 100644 index 0000000..9040c1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按日期) VO") +@Data +public class CrmStatisticsFollowUpSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpRecordCount; + + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpCustomerCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java new file mode 100644 index 0000000..d39f1cc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按类型) VO") +@Data +public class CrmStatisticsFollowUpSummaryByTypeRespVO { + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpType; + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpRecordCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java new file mode 100644 index 0000000..0651356 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按用户) VO") +@Data +public class CrmStatisticsFollowUpSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpRecordCount; + + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followUpCustomerCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByDateRespVO.java new file mode 100644 index 0000000..ce09a99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByDateRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 公海客户分析(按日期) VO") +@Data +public class CrmStatisticsPoolSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "进入公海客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerPutCount; + + @Schema(description = "公海领取客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerTakeCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByUserRespVO.java new file mode 100644 index 0000000..fb59e84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsPoolSummaryByUserRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 公海客户分析(按用户) VO") +@Data +public class CrmStatisticsPoolSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "进入公海客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerPutCount; + + @Schema(description = "公海领取客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerTakeCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelSummaryRespVO.java new file mode 100644 index 0000000..38d1c11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelSummaryRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - CRM 销售漏斗 Response VO") +@NoArgsConstructor +@AllArgsConstructor +@Data +public class CrmStatisticFunnelSummaryRespVO { + + @Schema(description = "客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long customerCount; + + @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessCount; + + @Schema(description = "赢单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessWinCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessInversionRateSummaryByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessInversionRateSummaryByDateRespVO.java new file mode 100644 index 0000000..b7650a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessInversionRateSummaryByDateRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 商机转化率分析(按日期) VO") +@Data +public class CrmStatisticsBusinessInversionRateSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessCount; + + @Schema(description = "赢单商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessWinCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByDateRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByDateRespVO.java new file mode 100644 index 0000000..1f8056c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByDateRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 新增商机分析(按日期) VO") +@Data +public class CrmStatisticsBusinessSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessCreateCount; + + @Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal totalPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByEndStatusRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByEndStatusRespVO.java new file mode 100644 index 0000000..023fdb8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByEndStatusRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 商机结束状态统计 Response VO") +@NoArgsConstructor +@AllArgsConstructor +@Data +public class CrmStatisticsBusinessSummaryByEndStatusRespVO { + + @Schema(description = "结束状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer endStatus; + + @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessCount; + + @Schema(description = "商机总金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal totalPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java new file mode 100644 index 0000000..85ba52e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 销售漏斗 Request VO") +@Data +public class CrmStatisticsFunnelReqVO extends PageParam { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") + private Integer interval; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java new file mode 100644 index 0000000..58b5399 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 员工业绩统计 Request VO") +@Data +public class CrmStatisticsPerformanceReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + *

+ * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") + private List userIds; + + // TODO @scholar:应该传递的是 int year;年份 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "时间范围不能为空") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java new file mode 100644 index 0000000..480e219 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.math.BigDecimal; + + +@Schema(description = "管理后台 - CRM 员工业绩统计 Response VO") +@Data +public class CrmStatisticsPerformanceRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "当月统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal currentMonthCount; + + @Schema(description = "上月统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private BigDecimal lastMonthCount; + + @Schema(description = "去年同期统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private BigDecimal lastYearCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java new file mode 100644 index 0000000..3420e7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户省份分析 VO") +@Data +public class CrmStatisticCustomerAreaRespVO { + + @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer areaId; + @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") + private String areaName; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java new file mode 100644 index 0000000..84b8de7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户行业分析 VO") +@Data +public class CrmStatisticCustomerIndustryRespVO { + + @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer industryId; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java new file mode 100644 index 0000000..dea4eeb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户级别分析 VO") +@Data +public class CrmStatisticCustomerLevelRespVO { + + @Schema(description = "客户级别编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer level; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java new file mode 100644 index 0000000..61b9688 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户来源分析 VO") +@Data +public class CrmStatisticCustomerSourceRespVO { + + @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer source; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java new file mode 100644 index 0000000..eb65cb3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 客户画像 Request VO") +@Data +public class CrmStatisticsPortraitReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java new file mode 100644 index 0000000..3670032 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 排行榜统计 Request VO") +@Data +public class CrmStatisticsRankReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + *

+ * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") + private List userIds; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "时间范围不能为空") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java new file mode 100644 index 0000000..feb2f3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + + +@Schema(description = "管理后台 - CRM 排行榜统计 Response VO") +@Data +public class CrmStatisticsRankRespVO { + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + + @Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String nickname; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String deptName; + + /** + * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 + * + * 1. 金额:合同金额排行、回款金额排行 + * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 + * + * 为什么使用 BigDecimal 的原因: + */ + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal count; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/app/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/app/package-info.java new file mode 100644 index 0000000..78d8563 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.crm.controller.app; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/package-info.java new file mode 100644 index 0000000..8354b31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.crm.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/package-info.java new file mode 100644 index 0000000..6fbc525 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.crm.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java new file mode 100644 index 0000000..a30ece2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.business; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * CRM 商机 DO + * + * @author ljlleo + */ +@TableName("crm_business") +@KeySequence("crm_business_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 商机名称 + */ + private String name; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + + /** + * 跟进状态 + */ + private Boolean followUpStatus; + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + + /** + * 商机状态组编号 + * + * 关联 {@link CrmBusinessStatusTypeDO#getId()} + */ + private Long statusTypeId; + /** + * 商机状态编号 + * + * 关联 {@link CrmBusinessStatusDO#getId()} + */ + private Long statusId; + /** + * 结束状态 + * + * 枚举 {@link CrmBusinessEndStatusEnum} + */ + private Integer endStatus; + /** + * 结束时的备注 + */ + private String endRemark; + + /** + * 预计成交日期 + */ + private LocalDateTime dealTime; + /** + * 产品总金额,单位:元 + * + * productPrice = ∑({@link CrmBusinessProductDO#getTotalPrice()}) + */ + private BigDecimal totalProductPrice; + /** + * 整单折扣,百分比 + */ + private BigDecimal discountPercent; + /** + * 商机总金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java new file mode 100644 index 0000000..2f66fc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.business; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * CRM 商机产品关联表 DO + * + * CrmBusinessDO : CrmBusinessProductDO = 1 : N + * + * @author lzxhqs + */ +@TableName("crm_business_product") +@KeySequence("crm_business_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessProductDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 商机编号 + * + * 关联 {@link CrmBusinessDO#getId()} + */ + private Long businessId; + /** + * 产品编号 + * + * 关联 {@link CrmProductDO#getId()} + */ + private Long productId; + /** + * 产品单价,单位:元 + * + * 冗余 {@link CrmProductDO#getPrice()} + */ + private BigDecimal productPrice; + /** + * 商机价格, 单位:元 + */ + private BigDecimal businessPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总计价格,单位:元 + * + * totalPrice = businessPrice * count + */ + private BigDecimal totalPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java new file mode 100644 index 0000000..5d7b8bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.business; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * CRM 商机状态 DO + * + * 注意,它是个配置表 + * + * @author ljlleo + */ +@TableName("crm_business_status") +@KeySequence("crm_business_status_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessStatusDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 状态类型编号 + * + * 关联 {@link CrmBusinessStatusTypeDO#getId()} + */ + private Long typeId; + /** + * 状态名 + */ + private String name; + /** + * 赢单率,百分比 + */ + private Integer percent; + /** + * 排序 + */ + private Integer sort; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java new file mode 100644 index 0000000..95b7a1f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.business; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.List; + +/** + * CRM 商机状态组 DO + * + * 注意,它是个配置表 + * + * @author ljlleo + */ +@TableName(value = "crm_business_status_type", autoResultMap = true) +@KeySequence("crm_business_status_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessStatusTypeDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 状态类型名 + */ + private String name; + + /** + * 使用的部门编号 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List deptIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java new file mode 100644 index 0000000..3af6fee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java @@ -0,0 +1,128 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.clue; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * CRM 线索 DO + * + * @author Wanwan + */ +@TableName("crm_clue") +@KeySequence("crm_clue_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmClueDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + /** + * 线索名称 + */ + private String name; + + /** + * 跟进状态 + */ + private Boolean followUpStatus; + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 最后跟进内容 + */ + private String contactLastContent; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + + /** + * 转化状态 + * + * true 表示已转换,会更新 {@link #customerId} 字段 + */ + private Boolean transformStatus; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + + /** + * 手机号 + */ + private String mobile; + /** + * 电话 + */ + private String telephone; + /** + * QQ + */ + private String qq; + /** + * wechat + */ + private String wechat; + /** + * email + */ + private String email; + /** + * 所在地 + * + * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 + */ + private Integer areaId; + /** + * 详细地址 + */ + private String detailAddress; + /** + * 所属行业 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} + */ + private Integer industryId; + /** + * 客户等级 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} + */ + private Integer level; + /** + * 客户来源 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} + */ + private Integer source; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/package-info.java new file mode 100644 index 0000000..929b9b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/package-info.java @@ -0,0 +1,4 @@ +/** + * 线索 + */ +package cn.iocoder.yudao.module.crm.dal.dataobject.clue; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java new file mode 100644 index 0000000..46185a5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.contact; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * CRM 联系人与商机的关联 DO + * + * @author 芋道源码 + */ +@TableName("crm_contact_business") +@KeySequence("crm_contact_business_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmContactBusinessDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 联系人编号 + * + * 关联 {@link CrmContactDO#getId()} 字段 + */ + private Long contactId; + /** + * 商机编号 + * + * 关联 {@link CrmBusinessDO#getId()} 字段 + */ + private Long businessId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java new file mode 100644 index 0000000..5a891eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.contact; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * CRM 联系人 DO + * + * @author 芋道源码 + */ +@TableName("crm_contact") +@KeySequence("crm_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmContactDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 联系人姓名 + */ + private String name; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 最后跟进内容 + */ + private String contactLastContent; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + + /** + * 负责人用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + + /** + * 手机号 + */ + private String mobile; + /** + * 电话 + */ + private String telephone; + /** + * 电子邮箱 + */ + private String email; + /** + * QQ + */ + private Long qq; + /** + * 微信 + */ + private String wechat; + /** + * 所在地 + * + * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 + */ + private Integer areaId; + /** + * 详细地址 + */ + private String detailAddress; + /** + * 性别 + * + * 枚举 {@link cn.iocoder.yudao.module.system.enums.common.SexEnum} + */ + private Integer sex; + /** + * 是否关键决策人 + */ + private Boolean master; + /** + * 职位 + */ + private String post; + /** + * 直属上级 + * + * 关联 {@link CrmContactDO#id} + */ + private Long parentId; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/package-info.java new file mode 100644 index 0000000..dfe0898 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/package-info.java @@ -0,0 +1,4 @@ +/** + * 联系人 + */ +package cn.iocoder.yudao.module.crm.dal.dataobject.contact; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java new file mode 100644 index 0000000..ab0c2d2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.contract; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.*; +import lombok.*; + +@TableName("crm_contract_config") +@KeySequence("crm_contract_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmContractConfigDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 是否开启提前提醒 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Boolean notifyEnabled; + /** + * 提前提醒天数 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Integer notifyDays; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java new file mode 100644 index 0000000..89f4fd9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java @@ -0,0 +1,123 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.contract; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * CRM 合同 DO + * + * @author dhb52 + */ +@TableName("crm_contract") +@KeySequence("crm_contract_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmContractDO extends BaseDO { + + /** + * 合同编号 + */ + @TableId + private Long id; + /** + * 合同名称 + */ + private String name; + /** + * 合同编号 + */ + private String no; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + /** + * 商机编号,非必须 + * + * 关联 {@link CrmBusinessDO#getId()} + */ + private Long businessId; + + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + + /** + * 工作流编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 审批状态 + * + * 枚举 {@link CrmAuditStatusEnum} + */ + private Integer auditStatus; + + /** + * 下单日期 + */ + private LocalDateTime orderDate; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 结束时间 + */ + private LocalDateTime endTime; + /** + * 产品总金额,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 整单折扣 + */ + private BigDecimal discountPercent; + /** + * 合同总金额,单位:分 + */ + private BigDecimal totalPrice; + /** + * 客户签约人,非必须 + * + * 关联 {@link CrmContactDO#getId()} + */ + private Long signContactId; + /** + * 公司签约人,非必须 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long signUserId; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java new file mode 100644 index 0000000..6bb3e6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.contract; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * CRM 合同产品关联表 DO + * + * @author HUIHUI + */ +@TableName("crm_contract_product") +@KeySequence("crm_contract_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmContractProductDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 合同编号 + * + * 关联 {@link CrmContractDO#getId()} + */ + private Long contractId; + /** + * 产品编号 + * + * 关联 {@link CrmProductDO#getId()} + */ + private Long productId; + /** + * 产品单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 合同价格, 单位:元 + */ + private BigDecimal contractPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总计价格,单位:元 + * + * totalPrice = businessPrice * count + */ + private BigDecimal totalPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java new file mode 100644 index 0000000..76d5111 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java @@ -0,0 +1,127 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.customer; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * CRM 客户 DO + * + * @author Wanwan + */ +@TableName(value = "crm_customer") +@KeySequence("crm_customer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmCustomerDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 客户名称 + */ + private String name; + + /** + * 跟进状态 + */ + private Boolean followUpStatus; + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 最后跟进内容 + */ + private String contactLastContent; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + /** + * 成为负责人的时间 + */ + private LocalDateTime ownerTime; + + /** + * 锁定状态 + */ + private Boolean lockStatus; + /** + * 成交状态 + */ + private Boolean dealStatus; + + /** + * 手机 + */ + private String mobile; + /** + * 电话 + */ + private String telephone; + /** + * QQ + */ + private String qq; + /** + * wechat + */ + private String wechat; + /** + * email + */ + private String email; + /** + * 所在地 + * + * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 + */ + private Integer areaId; + /** + * 详细地址 + */ + private String detailAddress; + /** + * 所属行业 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} + */ + private Integer industryId; + /** + * 客户等级 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} + */ + private Integer level; + /** + * 客户来源 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} + */ + private Integer source; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerLimitConfigDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerLimitConfigDO.java new file mode 100644 index 0000000..df3d3be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerLimitConfigDO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.customer; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.List; + +/** + * 客户限制配置 DO + * + * @author Wanwan + */ +@TableName(value = "crm_customer_limit_config", autoResultMap = true) +@KeySequence("crm_customer_limit_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmCustomerLimitConfigDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 规则类型 + *

+ * 枚举 {@link CrmCustomerLimitConfigTypeEnum} + */ + private Integer type; + /** + * 规则适用人群 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List userIds; + /** + * 规则适用部门 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List deptIds; + /** + * 数量上限 + */ + private Integer maxCount; + /** + * 成交客户是否占有拥有客户数 + * + * 当且仅当 {@link #type} 为 1 时,进行使用 + */ + private Boolean dealCountEnabled; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerPoolConfigDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerPoolConfigDO.java new file mode 100644 index 0000000..76f20dc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerPoolConfigDO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.customer; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.*; +import lombok.*; + +/** + * 客户公海配置 DO + * + * @author Wanwan + */ +@TableName(value = "crm_customer_pool_config") +@KeySequence("crm_customer_pool_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmCustomerPoolConfigDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 是否启用客户公海 + */ + private Boolean enabled; + /** + * 未跟进放入公海天数 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Integer contactExpireDays; + /** + * 未成交放入公海天数 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Integer dealExpireDays; + /** + * 是否开启提前提醒 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Boolean notifyEnabled; + /** + * 提前提醒天数 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Integer notifyDays; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java new file mode 100644 index 0000000..a01d47a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.followup; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 跟进记录 DO + * + * 用于记录客户、联系人的每一次跟进 + * + * @author 芋道源码 + */ +@TableName(value = "crm_follow_up_record", autoResultMap = true) +@KeySequence("crm_follow_up_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmFollowUpRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 数据类型 + * + * 枚举 {@link CrmBizTypeEnum} + */ + private Integer bizType; + /** + * 数据编号 + * + * 关联 {@link CrmBizTypeEnum} 对应模块 DO 的 id 字段 + */ + private Long bizId; + + /** + * 跟进类型 + * + * 关联 {@link DictTypeConstants#CRM_FOLLOW_UP_TYPE} 字典 + */ + private Integer type; + /** + * 跟进内容 + */ + private String content; + /** + * 下次联系时间 + */ + private LocalDateTime nextTime; + + /** + * 图片 + */ + @TableField(typeHandler = StringListTypeHandler.class) + private List picUrls; + /** + * 附件 + */ + @TableField(typeHandler = StringListTypeHandler.class) + private List fileUrls; + + /** + * 关联的商机编号数组 + * + * 关联 {@link CrmBusinessDO#getId()} + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List businessIds; + /** + * 关联的联系人编号数组 + * + * 关联 {@link CrmContactDO#getId()} + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List contactIds; + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java new file mode 100644 index 0000000..59e47a5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * CRM 数据权限 DO + * + * @author HUIHUI + */ +@TableName("crm_permission") +@KeySequence("crm_permission_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmPermissionDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + + /** + * 数据类型 + * + * 枚举 {@link CrmBizTypeEnum} + */ + private Integer bizType; + /** + * 数据编号 + * + * 关联 {@link CrmBizTypeEnum} 对应模块 DO 的 id 字段 + */ + private Long bizId; + + /** + * 用户编号 + * + * 关联 AdminUser 的 id 字段 + */ + private Long userId; + + /** + * 权限级别 + * + * 关联 {@link CrmPermissionLevelEnum} + */ + private Integer level; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductCategoryDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductCategoryDO.java new file mode 100644 index 0000000..e0f4d62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductCategoryDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 产品分类 DO + * + * @author ZanGe丶 + */ +@TableName("crm_product_category") +@KeySequence("crm_product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmProductCategoryDO extends BaseDO { + + /** + * 父分类编号 - 根分类 + */ + public static final Long PARENT_ID_NULL = 0L; + /** + * 限定分类层级 + */ + public static final int CATEGORY_LEVEL = 2; + + /** + * 分类编号 + */ + @TableId + private Long id; + /** + * 分类名称 + */ + private String name; + /** + * 父级编号 + * + * 关联 {@link CrmProductCategoryDO#getId()} + */ + private Long parentId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java new file mode 100644 index 0000000..caeeb53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * CRM 产品 DO + * + * @author ZanGe丶 + */ +@TableName("crm_product") +@KeySequence("crm_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmProductDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品名称 + */ + private String name; + /** + * 产品编码 + */ + private String no; + /** + * 单位 + * + * 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT} + */ + private Integer unit; + /** + * 价格,单位:元 + */ + private BigDecimal price; + /** + * 状态 + * + * 关联 {@link CrmProductStatusEnum} + */ + private Integer status; + /** + * 产品分类 ID + * + * 关联 {@link CrmProductCategoryDO#getId()} 字段 + */ + private Long categoryId; + /** + * 产品描述 + */ + private String description; + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/package-info.java new file mode 100644 index 0000000..4c7282d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/package-info.java @@ -0,0 +1,4 @@ +/** + * 产品表 + */ +package cn.iocoder.yudao.module.crm.dal.dataobject.product; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java new file mode 100644 index 0000000..269cac6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 回款 DO + * + * @author 赤焰 + */ +@TableName("crm_receivable") +@KeySequence("crm_receivable_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmReceivableDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 回款编号 + */ + private String no; + /** + * 回款计划编号 + * + * 关联 {@link CrmReceivablePlanDO#getId()},非必须 + */ + private Long planId; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + /** + * 合同编号 + * + * 关联 {@link CrmContractDO#getId()} + */ + private Long contractId; + /** + * 负责人编号,关联 {@link AdminUserRespDTO#getId()} + */ + private Long ownerUserId; + + /** + * 回款日期 + */ + private LocalDateTime returnTime; + /** + * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} + */ + private Integer returnType; + /** + * 计划回款金额,单位:元 + */ + private BigDecimal price; + /** + * 备注 + */ + private String remark; + + /** + * 工作流编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 审批状态 + * + * 枚举 {@link CrmAuditStatusEnum} + */ + private Integer auditStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java new file mode 100644 index 0000000..5ddefc5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * CRM 回款计划 DO + * + * @author 芋道源码 + */ +@TableName("crm_receivable_plan") +@KeySequence("crm_receivable_plan_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmReceivablePlanDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 期数 + */ + private Integer period; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + /** + * 合同编号 + * + * 关联 {@link CrmContractDO#getId()} + */ + private Long contractId; + + /** + * 负责人编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + + /** + * 计划回款日期 + */ + private LocalDateTime returnTime; + /** + * 计划回款类型 + * + * 枚举 {@link CrmReceivableReturnTypeEnum} + */ + private Integer returnType; + /** + * 计划回款金额,单位:元 + */ + private BigDecimal price; + + /** + * 回款编号,关联 {@link CrmReceivableDO#getId()} + */ + private Long receivableId; + + /** + * 提前几天提醒 + */ + private Integer remindDays; + /** + * 提醒日期 + */ + private LocalDateTime remindTime; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java new file mode 100644 index 0000000..ba347bc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.business; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 商机 Mapper + * + * @author ljlleo + */ +@Mapper +public interface CrmBusinessMapper extends BaseMapperX { + + default int updateOwnerUserIdById(Long id, Long ownerUserId) { + return update(new LambdaUpdateWrapper() + .eq(CrmBusinessDO::getId, id) + .set(CrmBusinessDO::getOwnerUserId, ownerUserId)); + } + + default PageResult selectPageByCustomerId(CrmBusinessPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号 + .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) + .orderByDesc(CrmBusinessDO::getId)); + } + + default PageResult selectPageByContactId(CrmBusinessPageReqVO pageReqVO, Collection businessIds) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .in(CrmBusinessDO::getId, businessIds) // 指定商机编号 + .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) + .orderByDesc(CrmBusinessDO::getId)); + } + + default PageResult selectPage(CrmBusinessPageReqVO pageReqVO, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), + CrmBusinessDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + // 拼接自身的查询条件 + query.selectAll(CrmBusinessDO.class) + .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) + .orderByDesc(CrmBusinessDO::getId); + return selectJoinPage(pageReqVO, CrmBusinessDO.class, query); + } + + default Long selectCountByStatusTypeId(Long statusTypeId) { + return selectCount(CrmBusinessDO::getStatusTypeId, statusTypeId); + } + + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmBusinessDO::getCustomerId, customerId) + .eq(CrmBusinessDO::getOwnerUserId, ownerUserId)); + } + + default PageResult selectPage(CrmStatisticsFunnelReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .in(CrmBusinessDO::getOwnerUserId, pageVO.getUserIds()) + .betweenIfPresent(CrmBusinessDO::getCreateTime, pageVO.getTimes())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java new file mode 100644 index 0000000..a91a0fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.business; + + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 商机产品 Mapper + * + * @author lzxhqs + */ +@Mapper +public interface CrmBusinessProductMapper extends BaseMapperX { + + default List selectListByBusinessId(Long businessId) { + return selectList(CrmBusinessProductDO::getBusinessId, businessId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java new file mode 100644 index 0000000..dfe7afc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.business; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 商机状态 Mapper + * + * @author ljlleo + */ +@Mapper +public interface CrmBusinessStatusMapper extends BaseMapperX { + + default int deleteByTypeId(Long typeId) { + return delete(CrmBusinessStatusDO::getTypeId, typeId); + } + + default List selectListByTypeId(Long typeId) { + return selectList(CrmBusinessStatusDO::getTypeId, typeId); + } + + default CrmBusinessStatusDO selectByTypeIdAndId(Long statusTypeId, Long statusId) { + return selectOne(CrmBusinessStatusDO::getTypeId, statusTypeId, + CrmBusinessStatusDO::getId, statusId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java new file mode 100644 index 0000000..3444e58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.business; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 商机状态组 Mapper + * + * @author ljlleo + */ +@Mapper +public interface CrmBusinessStatusTypeMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .orderByDesc(CrmBusinessStatusTypeDO::getId)); + } + + default CrmBusinessStatusTypeDO selectByName(String name) { + return selectOne(CrmBusinessStatusTypeDO::getName, name); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java new file mode 100644 index 0000000..d0665c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.clue; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 线索 Mapper + * + * @author Wanwan + */ +@Mapper +public interface CrmClueMapper extends BaseMapperX { + + default PageResult selectPage(CrmCluePageReqVO pageReqVO, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), + CrmClueDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); + // 拼接自身的查询条件 + query.selectAll(CrmClueDO.class) + .likeIfPresent(CrmClueDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmClueDO::getTransformStatus, pageReqVO.getTransformStatus()) + .likeIfPresent(CrmClueDO::getTelephone, pageReqVO.getTelephone()) + .likeIfPresent(CrmClueDO::getMobile, pageReqVO.getMobile()) + .eqIfPresent(CrmClueDO::getIndustryId, pageReqVO.getIndustryId()) + .eqIfPresent(CrmClueDO::getLevel, pageReqVO.getLevel()) + .eqIfPresent(CrmClueDO::getSource, pageReqVO.getSource()) + .eqIfPresent(CrmClueDO::getFollowUpStatus, pageReqVO.getFollowUpStatus()) + .orderByDesc(CrmClueDO::getId); + return selectJoinPage(pageReqVO, CrmClueDO.class, query); + } + + default List selectBatchIds(Collection ids, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), ids, userId); + query.selectAll(CrmClueDO.class).in(CrmClueDO::getId, ids).orderByDesc(CrmClueDO::getId); + // 拼接自身的查询条件 + return selectJoinList(CrmClueDO.class, query); + } + + default Long selectCountByFollow(Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), + CrmClueDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 未跟进 + 未转化 + query.eq(CrmClueDO::getFollowUpStatus, false) + .eq(CrmClueDO::getTransformStatus, false); + return selectCount(query); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/package-info.java new file mode 100644 index 0000000..f9978e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/package-info.java @@ -0,0 +1,4 @@ +/** + * 线索 + */ +package cn.iocoder.yudao.module.crm.dal.mysql.clue; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java new file mode 100644 index 0000000..7bff0c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.contact; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * CRM 联系人商机关联 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmContactBusinessMapper extends BaseMapperX { + + default CrmContactBusinessDO selectByContactIdAndBusinessId(Long contactId, Long businessId) { + return selectOne(CrmContactBusinessDO::getContactId, contactId, + CrmContactBusinessDO::getBusinessId, businessId); + } + + default void deleteByContactIdAndBusinessId(Long contactId, Collection businessIds) { + delete(new LambdaQueryWrapper() + .eq(CrmContactBusinessDO::getContactId, contactId) + .in(CrmContactBusinessDO::getBusinessId, businessIds)); + } + + default void deleteByBusinessIdAndContactId(Long businessId, List contactIds) { + delete(new LambdaQueryWrapper() + .eq(CrmContactBusinessDO::getBusinessId, businessId) + .in(CrmContactBusinessDO::getContactId, contactIds)); + } + + default List selectListByContactId(Long contactId) { + return selectList(CrmContactBusinessDO::getContactId, contactId); + } + + default List selectListByBusinessId(Long businessId) { + return selectList(CrmContactBusinessDO::getBusinessId, businessId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java new file mode 100644 index 0000000..75f2a75 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.contact; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * CRM 联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmContactMapper extends BaseMapperX { + + default int updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { + return update(new LambdaUpdateWrapper() + .eq(CrmContactDO::getCustomerId, customerId) + .set(CrmContactDO::getOwnerUserId, ownerUserId)); + } + + default PageResult selectPageByCustomerId(CrmContactPageReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .eq(CrmContactDO::getCustomerId, pageVO.getCustomerId()) // 指定客户编号 + .likeIfPresent(CrmContactDO::getName, pageVO.getName()) + .eqIfPresent(CrmContactDO::getMobile, pageVO.getMobile()) + .eqIfPresent(CrmContactDO::getTelephone, pageVO.getTelephone()) + .eqIfPresent(CrmContactDO::getEmail, pageVO.getEmail()) + .eqIfPresent(CrmContactDO::getQq, pageVO.getQq()) + .eqIfPresent(CrmContactDO::getWechat, pageVO.getWechat()) + .orderByDesc(CrmContactDO::getId)); + } + + default PageResult selectPageByBusinessId(CrmContactPageReqVO pageVO, Collection ids) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .in(CrmContactDO::getId, ids) // 指定联系人编号 + .likeIfPresent(CrmContactDO::getName, pageVO.getName()) + .eqIfPresent(CrmContactDO::getMobile, pageVO.getMobile()) + .eqIfPresent(CrmContactDO::getTelephone, pageVO.getTelephone()) + .eqIfPresent(CrmContactDO::getEmail, pageVO.getEmail()) + .eqIfPresent(CrmContactDO::getQq, pageVO.getQq()) + .eqIfPresent(CrmContactDO::getWechat, pageVO.getWechat()) + .orderByDesc(CrmContactDO::getId)); + } + + default PageResult selectPage(CrmContactPageReqVO pageReqVO, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), + CrmContactDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + // 拼接自身的查询条件 + query.selectAll(CrmContactDO.class) + .likeIfPresent(CrmContactDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmContactDO::getMobile, pageReqVO.getMobile()) + .eqIfPresent(CrmContactDO::getTelephone, pageReqVO.getTelephone()) + .eqIfPresent(CrmContactDO::getEmail, pageReqVO.getEmail()) + .eqIfPresent(CrmContactDO::getQq, pageReqVO.getQq()) + .eqIfPresent(CrmContactDO::getWechat, pageReqVO.getWechat()) + .orderByDesc(CrmContactDO::getId); + return selectJoinPage(pageReqVO, CrmContactDO.class, query); + } + + default List selectListByCustomerId(Long customerId) { + return selectList(CrmContactDO::getCustomerId, customerId); + } + + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return selectList(CrmContactDO::getCustomerId, customerId, + CrmContactDO::getOwnerUserId, ownerUserId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java new file mode 100644 index 0000000..64e6f91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.contract; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 合同配置 Mapper + * + * @author Wanwan + */ +@Mapper +public interface CrmContractConfigMapper extends BaseMapperX { + + default CrmContractConfigDO selectOne() { + return selectOne(new QueryWrapperX().limitN(1)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java new file mode 100644 index 0000000..14d7432 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.contract; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * CRM 合同 Mapper + * + * @author dhb52 + */ +@Mapper +public interface CrmContractMapper extends BaseMapperX { + + default CrmContractDO selectByNo(String no) { + return selectOne(CrmContractDO::getNo, no); + } + + default PageResult selectPageByCustomerId(CrmContractPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) + .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) + .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) + .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) + .orderByDesc(CrmContractDO::getId)); + } + + default PageResult selectPageByBusinessId(CrmContractPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) + .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) + .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) + .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) + .orderByDesc(CrmContractDO::getId)); + } + + default PageResult selectPage(CrmContractPageReqVO pageReqVO, Long userId, CrmContractConfigDO config) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), + CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + // 拼接自身的查询条件 + query.selectAll(CrmContractDO.class) + .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) + .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) + .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) + .eqIfPresent(CrmContractDO::getAuditStatus, pageReqVO.getAuditStatus()) + .orderByDesc(CrmContractDO::getId); + + // Backlog: 即将到期的合同 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); + if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) { // 即将到期 + query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) + .between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(config.getNotifyDays())); + } else if (CrmContractPageReqVO.EXPIRY_TYPE_EXPIRED.equals(pageReqVO.getExpiryType())) { // 已到期 + query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) + .lt(CrmContractDO::getEndTime, endOfToday); + } + return selectJoinPage(pageReqVO, CrmContractDO.class, query); + } + + default List selectBatchIds(Collection ids, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 构建数据权限连表条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), ids, userId); + // 拼接自身的查询条件 + query.selectAll(CrmContractDO.class).in(CrmContractDO::getId, ids).orderByDesc(CrmContractDO::getId); + return selectJoinList(CrmContractDO.class, query); + } + + default Long selectCountByContactId(Long contactId) { + return selectCount(CrmContractDO::getSignContactId, contactId); + } + + default Long selectCountByBusinessId(Long businessId) { + return selectCount(CrmContractDO::getBusinessId, businessId); + } + + default Long selectCountByAudit(Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), + CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 未审核 + query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); + return selectCount(query); + } + + default Long selectCountByRemind(Long userId, CrmContractConfigDO config) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), + CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 即将到期 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); + query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) // 必须审批通过! + .between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(config.getNotifyDays())); + return selectCount(query); + } + + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmContractDO::getCustomerId, customerId) + .eq(CrmContractDO::getOwnerUserId, ownerUserId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java new file mode 100644 index 0000000..feafbc4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.contract; + + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 合同产品 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CrmContractProductMapper extends BaseMapperX { + + default List selectListByContractId(Long contractId) { + return selectList(new LambdaQueryWrapperX().eq(CrmContractProductDO::getContractId, contractId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java new file mode 100644 index 0000000..08beaf8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 客户限制配置 Mapper + * + * @author Wanwan + */ +@Mapper +public interface CrmCustomerLimitConfigMapper extends BaseMapperX { + + default PageResult selectPage(CrmCustomerLimitConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CrmCustomerLimitConfigDO::getType, reqVO.getType()) + .orderByDesc(CrmCustomerLimitConfigDO::getId)); + } + + default List selectListByTypeAndUserIdAndDeptId( + Integer type, Long userId, Long deptId) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .eq(CrmCustomerLimitConfigDO::getType, type); + query.apply("FIND_IN_SET({0}, user_ids) > 0", userId); + if (deptId != null) { + query.apply("FIND_IN_SET({0}, dept_ids) > 0", deptId); + } + return selectList(query); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java new file mode 100644 index 0000000..5034453 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java @@ -0,0 +1,189 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.customer; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 客户 Mapper + * + * @author Wanwan + */ +@Mapper +public interface CrmCustomerMapper extends BaseMapperX { + + default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) { + return selectCount(new LambdaUpdateWrapper() + .eq(CrmCustomerDO::getLockStatus, lockStatus) + .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); + } + + default Long selectCountByDealStatusAndOwnerUserId(@Nullable Boolean dealStatus, Long ownerUserId) { + return selectCount(new LambdaQueryWrapperX() + .eqIfPresent(CrmCustomerDO::getDealStatus, dealStatus) + .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); + } + + default int updateOwnerUserIdById(Long id, Long ownerUserId) { + return update(new LambdaUpdateWrapper() + .eq(CrmCustomerDO::getId, id) + .set(CrmCustomerDO::getOwnerUserId, ownerUserId)); + } + + default PageResult selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), pageReqVO.getPool()); + // 拼接自身的查询条件 + query.selectAll(CrmCustomerDO.class) + .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName()) + .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile()) + .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId()) + .eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel()) + .eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource()) + .eqIfPresent(CrmCustomerDO::getFollowUpStatus, pageReqVO.getFollowUpStatus()); + + // backlog 查询 + if (ObjUtil.isNotNull(pageReqVO.getContactStatus())) { + Assert.isNull(pageReqVO.getPool(), "pool 必须是 null"); + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); + if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_TODAY)) { // 今天需联系 + query.between(CrmCustomerDO::getContactNextTime, beginOfToday, endOfToday); + } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_EXPIRED)) { // 已逾期 + query.lt(CrmCustomerDO::getContactNextTime, beginOfToday); + } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_ALREADY)) { // 已联系 + query.between(CrmCustomerDO::getContactLastTime, beginOfToday, endOfToday); + } else { + throw new IllegalArgumentException("未知联系状态:" + pageReqVO.getContactStatus()); + } + } + return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); + } + + default List selectBatchIds(Collection ids, Long ownerUserId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, ownerUserId); + // 拼接自身的查询条件 + query.selectAll(CrmCustomerDO.class).in(CrmCustomerDO::getId, ids).orderByDesc(CrmCustomerDO::getId); + return selectJoinList(CrmCustomerDO.class, query); + } + + default CrmCustomerDO selectByCustomerName(String name) { + return selectOne(CrmCustomerDO::getName, name); + } + + default PageResult selectPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO, + CrmCustomerPoolConfigDO poolConfig, + Long ownerUserId) { + final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, ownerUserId); + return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class)); + } + + default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO, + CrmCustomerPoolConfigDO poolConfigDO, + Long userId) { + final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfigDO, userId); + return selectCount(query); + } + + static MPJLambdaWrapperX buildPutPoolRemindCustomerQuery(CrmCustomerPageReqVO pageReqVO, + CrmCustomerPoolConfigDO poolConfig, + Long ownerUserId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), null); + + // 未锁定 + 未成交 + query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false); + + // 情况一:未成交提醒日期区间 + Integer dealExpireDays = poolConfig.getDealExpireDays(); + LocalDateTime startDealRemindTime = LocalDateTime.now().minusDays(dealExpireDays); + LocalDateTime endDealRemindTime = LocalDateTime.now() + .minusDays(Math.max(dealExpireDays - poolConfig.getNotifyDays(), 0)); + // 情况二:未跟进提醒日期区间 + Integer contactExpireDays = poolConfig.getContactExpireDays(); + LocalDateTime startContactRemindTime = LocalDateTime.now().minusDays(contactExpireDays); + LocalDateTime endContactRemindTime = LocalDateTime.now() + .minusDays(Math.max(contactExpireDays - poolConfig.getNotifyDays(), 0)); + query.and(q -> { + // 情况一:成交超时提醒 + q.between(CrmCustomerDO::getOwnerTime, startDealRemindTime, endDealRemindTime) + // 情况二:跟进超时提醒 + .or(w -> w.between(CrmCustomerDO::getOwnerTime, startContactRemindTime, endContactRemindTime) + .and(p -> p.between(CrmCustomerDO::getContactLastTime, startContactRemindTime, endContactRemindTime) + .or().isNull(CrmCustomerDO::getContactLastTime))); + }); + return query; + } + + /** + * 获得需要过期到公海的客户列表 + * + * @return 客户列表 + */ + default List selectListByAutoPool(CrmCustomerPoolConfigDO poolConfig) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.gt(CrmCustomerDO::getOwnerUserId, 0); + // 未锁定 + 未成交 + query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false); + // 已经超时 + LocalDateTime dealExpireTime = LocalDateTime.now().minusDays(poolConfig.getDealExpireDays()); + LocalDateTime contactExpireTime = LocalDateTime.now().minusDays(poolConfig.getContactExpireDays()); + query.and(q -> { + // 情况一:成交超时 + q.lt(CrmCustomerDO::getOwnerTime, dealExpireTime) + // 情况二:跟进超时 + .or(w -> w.lt(CrmCustomerDO::getOwnerTime, contactExpireTime) + .and(p -> p.lt(CrmCustomerDO::getContactLastTime, contactExpireTime) + .or().isNull(CrmCustomerDO::getContactLastTime))); + }); + return selectList(query); + } + + default Long selectCountByTodayContact(Long ownerUserId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 今天需联系 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); + query.between(CrmCustomerDO::getContactNextTime, beginOfToday, endOfToday); + return selectCount(query); + } + + default Long selectCountByFollow(Long ownerUserId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 未跟进 + query.eq(CrmClueDO::getFollowUpStatus, false); + return selectCount(query); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java new file mode 100644 index 0000000..06cf44e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.customer; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 客户公海配置 Mapper + * + * @author Wanwan + */ +@Mapper +public interface CrmCustomerPoolConfigMapper extends BaseMapperX { + + default CrmCustomerPoolConfigDO selectOne() { + return selectOne(new LambdaQueryWrapperX().last("LIMIT 1")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java new file mode 100644 index 0000000..45e2b41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.followup; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 跟进记录 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmFollowUpRecordMapper extends BaseMapperX { + + default PageResult selectPage(CrmFollowUpRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CrmFollowUpRecordDO::getBizType, reqVO.getBizType()) + .eqIfPresent(CrmFollowUpRecordDO::getBizId, reqVO.getBizId()) + .orderByDesc(CrmFollowUpRecordDO::getId)); + } + + default void deleteByBiz(Integer bizType, Long bizId) { + delete(new LambdaQueryWrapperX() + .eq(CrmFollowUpRecordDO::getBizType, bizType) + .eq(CrmFollowUpRecordDO::getBizId, bizId)); + } + + default List selectListByBiz(Integer bizType, Collection bizIds) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmFollowUpRecordDO::getBizType, bizType) + .in(CrmFollowUpRecordDO::getBizId, bizIds)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java new file mode 100644 index 0000000..07b7b6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.permission; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * crm 数据权限 mapper + * + * @author HUIHUI + */ +@Mapper +public interface CrmPermissionMapper extends BaseMapperX { + + default CrmPermissionDO selectByBizTypeAndBizIdByUserId(Integer bizType, Long bizId, Long userId) { + return selectOne(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId) + .eq(CrmPermissionDO::getUserId, userId)); + } + + default List selectByBizTypeAndBizId(Integer bizType, Long bizId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId)); + } + + default List selectByBizTypeAndBizIds(Integer bizType, Collection bizIds) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .in(CrmPermissionDO::getBizId, bizIds)); + } + + default List selectListByBizTypeAndUserId(Integer bizType, Long userId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getUserId, userId)); + } + + default List selectListByBizTypeAndBizIdAndLevel(Integer bizType, Long bizId, Integer level) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId) + .eq(CrmPermissionDO::getLevel, level)); + } + + default CrmPermissionDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(CrmPermissionDO::getId, id, + CrmPermissionDO::getUserId, userId); + } + + default CrmPermissionDO selectByBizAndUserId(Integer bizType, Long bizId, Long userId) { + return selectOne(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId) + .eq(CrmPermissionDO::getUserId, userId)); + } + + default int deletePermission(Integer bizType, Long bizId) { + return delete(new LambdaQueryWrapperX() + .eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId)); + } + + default Long selectListByBiz(Collection bizTypes, Collection bizIds, Collection userIds) { + return selectCount(new LambdaQueryWrapperX() + .in(CrmPermissionDO::getBizType, bizTypes) + .in(CrmPermissionDO::getBizId, bizIds) + .in(CrmPermissionDO::getUserId, userIds)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/package-info.java new file mode 100644 index 0000000..ff0e16b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.permission; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductCategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductCategoryMapper.java new file mode 100644 index 0000000..3cced73 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductCategoryMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.product; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 产品分类 Mapper + * + * @author ZanGe丶 + */ +@Mapper +public interface CrmProductCategoryMapper extends BaseMapperX { + + default List selectList(CrmProductCategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(CrmProductCategoryDO::getName, reqVO.getName()) + .eqIfPresent(CrmProductCategoryDO::getParentId, reqVO.getParentId()) + .orderByDesc(CrmProductCategoryDO::getId)); + } + + default CrmProductCategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(CrmProductCategoryDO::getParentId, parentId, CrmProductCategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(CrmProductCategoryDO::getParentId, parentId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java new file mode 100644 index 0000000..4d1d618 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 产品 Mapper + * + * @author ZanGe丶 + */ +@Mapper +public interface CrmProductMapper extends BaseMapperX { + + default PageResult selectPage(CrmProductPageReqVO reqVO) { + return selectPage(reqVO, new MPJLambdaWrapperX() + .likeIfPresent(CrmProductDO::getName, reqVO.getName()) + .eqIfPresent(CrmProductDO::getStatus, reqVO.getStatus()) + .orderByDesc(CrmProductDO::getId)); + } + + default CrmProductDO selectByNo(String no) { + return selectOne(CrmProductDO::getNo, no); + } + + default Long selectCountByCategoryId(Long categoryId) { + return selectCount(CrmProductDO::getCategoryId, categoryId); + } + + default List selectListByStatus(Integer status) { + return selectList(CrmProductDO::getStatus, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java new file mode 100644 index 0000000..0c821c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.receivable; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 回款 Mapper + * + * @author 赤焰 + */ +@Mapper +public interface CrmReceivableMapper extends BaseMapperX { + + default CrmReceivableDO selectByNo(String no) { + return selectOne(CrmReceivableDO::getNo, no); + } + + default PageResult selectPageByCustomerId(CrmReceivablePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 + .eqIfPresent(CrmReceivableDO::getNo, reqVO.getNo()) + .eqIfPresent(CrmReceivableDO::getContractId, reqVO.getContractId()) + .eqIfPresent(CrmReceivableDO::getPlanId, reqVO.getPlanId()) + .orderByDesc(CrmReceivableDO::getId)); + } + + default PageResult selectPage(CrmReceivablePageReqVO pageReqVO, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), + CrmReceivableDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + // 拼接自身的查询条件 + query.selectAll(CrmReceivableDO.class) + .eqIfPresent(CrmReceivableDO::getNo, pageReqVO.getNo()) + .eqIfPresent(CrmReceivableDO::getPlanId, pageReqVO.getPlanId()) + .eqIfPresent(CrmReceivableDO::getContractId, pageReqVO.getContractId()) + .eqIfPresent(CrmReceivableDO::getAuditStatus, pageReqVO.getAuditStatus()) + .orderByDesc(CrmReceivableDO::getId); + return selectJoinPage(pageReqVO, CrmReceivableDO.class, query); + } + + default List selectBatchIds(Collection ids, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), ids, userId); + // 拼接自身的查询条件 + query.selectAll(CrmReceivableDO.class).in(CrmReceivableDO::getId, ids).orderByDesc(CrmReceivableDO::getId); + return selectJoinList(CrmReceivableDO.class, query); + } + + default Long selectCountByAudit(Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), + CrmReceivableDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 未审核 + query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); + return selectCount(query); + } + + default List selectListByContractIdAndStatus(Long contractId, Collection auditStatuses) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmReceivableDO::getContractId, contractId) + .in(CrmReceivableDO::getAuditStatus, auditStatuses)); + } + + default Map selectReceivablePriceMapByContractId(Collection contractIds) { + if (CollUtil.isEmpty(contractIds)) { + return Collections.emptyMap(); + } + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("contract_id, SUM(price) AS total_price") + .in("audit_status", CrmAuditStatusEnum.DRAFT.getStatus(), // 草稿 + 审批中 + 审批通过 + CrmAuditStatusEnum.PROCESS, CrmAuditStatusEnum.APPROVE.getStatus()) + .groupBy("contract_id") + .in("contract_id", contractIds)); + // 获得金额 + return convertMap(result, obj -> (Long) obj.get("contract_id"), obj -> (BigDecimal) obj.get("total_price")); + } + + default Long selectCountByContractId(Long contractId) { + return selectCount(CrmReceivableDO::getContractId, contractId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java new file mode 100644 index 0000000..4d53897 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.receivable; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * 回款计划 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmReceivablePlanMapper extends BaseMapperX { + + default CrmReceivablePlanDO selectMaxPeriodByContractId(Long contractId) { + return selectOne(new MPJLambdaWrapperX() + .eq(CrmReceivablePlanDO::getContractId, contractId) + .orderByDesc(CrmReceivablePlanDO::getPeriod) + .last("LIMIT 1")); + } + + default PageResult selectPageByCustomerId(CrmReceivablePlanPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + if (Objects.nonNull(reqVO.getContractNo())) { // 根据合同编号检索 + query.innerJoin(CrmContractDO.class, on -> on.like(CrmContractDO::getNo, reqVO.getContractNo()) + .eq(CrmContractDO::getId, CrmReceivablePlanDO::getContractId)); + } + query.eq(CrmReceivablePlanDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 + .eqIfPresent(CrmReceivablePlanDO::getContractId, reqVO.getContractId()) + .orderByDesc(CrmReceivablePlanDO::getPeriod); + return selectJoinPage(reqVO, CrmReceivablePlanDO.class, query); + } + + default PageResult selectPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), + CrmReceivablePlanDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + // 拼接自身的查询条件 + query.selectAll(CrmReceivablePlanDO.class) + .eqIfPresent(CrmReceivablePlanDO::getCustomerId, pageReqVO.getCustomerId()) + .eqIfPresent(CrmReceivablePlanDO::getContractId, pageReqVO.getContractId()) + .orderByDesc(CrmReceivablePlanDO::getPeriod); + if (Objects.nonNull(pageReqVO.getContractNo())) { // 根据合同编号检索 + query.innerJoin(CrmContractDO.class, on -> on.like(CrmContractDO::getNo, pageReqVO.getContractNo()) + .eq(CrmContractDO::getId, CrmReceivablePlanDO::getContractId)); + } + + // Backlog: 回款提醒类型 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款 + query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 + .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 + .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 + } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期 + query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 + .ge(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期 + } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款 + query.isNotNull(CrmReceivablePlanDO::getReceivableId); + } + return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query); + } + + default List selectBatchIds(Collection ids, Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 拼接数据权限的查询条件 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), ids, userId); + // 拼接自身的查询条件 + query.selectAll(CrmReceivablePlanDO.class).in(CrmReceivablePlanDO::getId, ids).orderByDesc(CrmReceivablePlanDO::getId); + return selectJoinList(CrmReceivablePlanDO.class, query); + } + + default Long selectReceivablePlanCountByRemind(Long userId) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); + // 我负责的 + 非公海 + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), + CrmReceivablePlanDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + // 未回款 + 已逾期 + 今天开始提醒 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 + .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 + .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 + return selectCount(query); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java new file mode 100644 index 0000000..171d432 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -0,0 +1,211 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * CRM 客户分析 Mapper + * + * @author dhb52 + */ +@Mapper +public interface CrmStatisticsCustomerMapper { + + /** + * 新建客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerCreateCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 成交客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 新建客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerCreateCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 成交客户数(按用户) + * + * @param reqVO 请求参数@param reqVO 请求参数@param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 合同总金额(按用户) + * + * @return 统计数据@return 统计数据@param reqVO 请求参数 + * @return 统计数据 + */ + List selectContractPriceGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 合同回款金额(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectReceivablePriceGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进次数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectFollowUpRecordCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectFollowUpCustomerCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进次数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectFollowUpRecordCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectFollowUpCustomerCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + + /** + * 首次合同、回款信息(用于【客户转化率】页面) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectContractSummary(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进次数(按类型) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectFollowUpRecordCountGroupByType(CrmStatisticsCustomerReqVO reqVO); + + + /** + * 进入公海客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 + default List selectPoolCustomerPutCountByDate(CrmStatisticsCustomerReqVO reqVO) { + LocalDateTime currrentDate = LocalDateTimeUtil.beginOfDay(reqVO.getTimes()[0]); + LocalDateTime endDate = LocalDateTimeUtil.endOfDay(reqVO.getTimes()[1]); + List voList = new ArrayList<>(); + while (currrentDate.isBefore(endDate)) { + voList.add(new CrmStatisticsPoolSummaryByDateRespVO() + .setTime(LocalDateTimeUtil.format(currrentDate, "yyyy-MM-dd")) + .setCustomerPutCount(RandomUtil.randomInt(0, 10)) + .setCustomerTakeCount(RandomUtil.randomInt(0, 10))); + currrentDate = currrentDate.plusDays(1); + } + + return voList; + } + + /** + * 公海领取客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 + default List selectPoolCustomerTakeCountByDate(CrmStatisticsCustomerReqVO reqVO) { + return selectPoolCustomerPutCountByDate(reqVO); + } + + /** + * 进入公海客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 + default List selectPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO) { + return convertList(reqVO.getUserIds(), userId -> + (CrmStatisticsPoolSummaryByUserRespVO) new CrmStatisticsPoolSummaryByUserRespVO() + .setCustomerPutCount(RandomUtil.randomInt(0, 10)) + .setCustomerTakeCount(RandomUtil.randomInt(0, 10)) + .setOwnerUserId(userId)); + } + + /** + * 公海领取客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 + default List selectPoolCustomerTakeCountByUser(CrmStatisticsCustomerReqVO reqVO) { + return selectPoolCustomerPutCountByUser(reqVO); + } + + /** + * 客户成交周期(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCycleGroupByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按区域) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCycleGroupByAreaId(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按产品) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectCustomerDealCycleGroupByProductId(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java new file mode 100644 index 0000000..d69fa62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessInversionRateSummaryByDateRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * CRM 销售漏斗 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CrmStatisticsFunnelMapper { + + Long selectCustomerCountByDate(CrmStatisticsFunnelReqVO reqVO); + + Long selectBusinessCountByDateAndEndStatus(@Param("reqVO") CrmStatisticsFunnelReqVO reqVO, @Param("status") Integer status); + + List selectBusinessSummaryListGroupByEndStatus(CrmStatisticsFunnelReqVO reqVO); + + List selectBusinessSummaryGroupByDate(CrmStatisticsFunnelReqVO reqVO); + + List selectBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java new file mode 100644 index 0000000..6467a09 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 员工业绩分析 Mapper + * + * @author scholar + */ +@Mapper +public interface CrmStatisticsPerformanceMapper { + + /** + * 员工签约合同数量 + * + * @param performanceReqVO 参数 + * @return 员工签约合同数量 + */ + List selectContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工签约合同金额 + * + * @param performanceReqVO 参数 + * @return 员工签约合同金额 + */ + List selectContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工回款金额 + * + * @param performanceReqVO 参数 + * @return 员工回款金额 + */ + List selectReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java new file mode 100644 index 0000000..a7c9427 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 数据画像 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CrmStatisticsPortraitMapper { + + List selectSummaryListGroupByAreaId(CrmStatisticsPortraitReqVO reqVO); + + List selectCustomerIndustryListGroupByIndustryId(CrmStatisticsPortraitReqVO reqVO); + + List selectCustomerSourceListGroupBySource(CrmStatisticsPortraitReqVO reqVO); + + List selectCustomerLevelListGroupByLevel(CrmStatisticsPortraitReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java new file mode 100644 index 0000000..d58241c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 排行榜统计 Mapper + * + * @author anhaohao + */ +@Mapper +public interface CrmStatisticsRankMapper { + + /** + * 查询合同金额排行榜 + * + * @param rankReqVO 参数 + * @return 合同金额排行榜 + */ + List selectContractPriceRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询回款金额排行榜 + * + * @param rankReqVO 参数 + * @return 回款金额排行榜 + */ + List selectReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询签约合同数量排行榜 + * + * @param rankReqVO 参数 + * @return 签约合同数量排行榜 + */ + List selectContractCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询产品销量排行榜 + * + * @param rankReqVO 参数 + * @return 产品销量排行榜 + */ + List selectProductSalesRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询新增客户数排行榜 + * + * @param rankReqVO 参数 + * @return 新增客户数排行榜 + */ + List selectCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询联系人数量排行榜 + * + * @param rankReqVO 参数 + * @return 联系人数量排行榜 + */ + List selectContactsCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询跟进次数排行榜 + * + * @param rankReqVO 参数 + * @return 跟进次数排行榜 + */ + List selectFollowCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 查询跟进客户数排行榜 + * + * @param rankReqVO 参数 + * @return 跟进客户数排行榜 + */ + List selectFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..2932c1d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.dal.redis; + +/** + * CRM Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 序号的缓存 + * + * KEY 格式:trade_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String NO = "crm:seq_no:"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java new file mode 100644 index 0000000..68f0835 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.dal.redis.no; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.crm.dal.redis.RedisKeyConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + + +/** + * Crm 订单序号的 Redis DAO + * + * @author HUIHUI + */ +@Repository +public class CrmNoRedisDAO { + + /** + * 合同 {@link cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO} + */ + public static final String CONTRACT_NO_PREFIX = "HT"; + + /** + * 回款 {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO} + */ + public static final String RECEIVABLE_PREFIX = "HK"; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增 + * 例如说:QTRK 202109 000001 (没有中间空格) + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); + String key = RedisKeyConstants.NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofDays(1L)); + return noPrefix + String.format("%06d", no); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java new file mode 100644 index 0000000..8f0a889 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.framework.excel.core; + +import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 地区下拉框数据源的 {@link ExcelColumnSelectFunction} 实现类 + * + * @author HUIHUI + */ +@Service +public class AreaExcelColumnSelectFunction implements ExcelColumnSelectFunction { + + public static final String NAME = "getCrmAreaNameList"; // 防止和别的模块重名 + + @Override + public String getName() { + return NAME; + } + + @Override + public List getOptions() { + // 获取地区下拉数据 + // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? + Area area = AreaUtils.getArea(Area.ID_CHINA); + return AreaUtils.getAreaNodePathList(area.getChildren()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java new file mode 100644 index 0000000..c2deef8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java @@ -0,0 +1,4 @@ +/** + * crm 模块的 excel 拓展封装 + */ +package cn.iocoder.yudao.module.crm.framework.excel; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBusinessParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBusinessParseFunction.java new file mode 100644 index 0000000..0b4f51c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBusinessParseFunction.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * CRM 商机的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmBusinessParseFunction implements IParseFunction { + + public static final String NAME = "getBusinessById"; + + @Resource + private CrmBusinessService businessService; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + CrmBusinessDO businessDO = businessService.getBusiness(Long.parseLong(value.toString())); + return businessDO == null ? "" : businessDO.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java new file mode 100644 index 0000000..da1d7a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * CRM 联系人的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmContactParseFunction implements IParseFunction { + + public static final String NAME = "getContactById"; + + @Resource + private CrmContactService contactService; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + CrmContactDO contactDO = contactService.getContact(Long.parseLong(value.toString())); + return contactDO == null ? "" : contactDO.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java new file mode 100644 index 0000000..7d9060b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * CRM 合同的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmContractParseFunction implements IParseFunction { + + public static final String NAME = "getContractById"; + + @Resource + private CrmContractService contractService; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + CrmContractDO contract = contractService.getContract(Long.parseLong(value.toString())); + return contract == null ? "" : contract.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java new file mode 100644 index 0000000..dd0b1c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; + +/** + * 行业的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmCustomerIndustryParseFunction implements IParseFunction { + + public static final String NAME = "getCustomerIndustry"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java new file mode 100644 index 0000000..eedd1d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL; + +/** + * 客户等级的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmCustomerLevelParseFunction implements IParseFunction { + + public static final String NAME = "getCustomerLevel"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_LEVEL, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java new file mode 100644 index 0000000..7ba53a5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * CRM 客户的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmCustomerParseFunction implements IParseFunction { + + public static final String NAME = "getCustomerById"; + + @Resource + private CrmCustomerService customerService; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + CrmCustomerDO crmCustomerDO = customerService.getCustomer(Long.parseLong(value.toString())); + return crmCustomerDO == null ? "" : crmCustomerDO.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java new file mode 100644 index 0000000..d1a0233 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE; + +/** + * CRM 客户来源的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmCustomerSourceParseFunction implements IParseFunction { + + public static final String NAME = "getCustomerSource"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_SOURCE, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java new file mode 100644 index 0000000..446de10 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 产品状态的 {@link IParseFunction} 实现类 + * + * @author anhaohao + */ +@Component +@Slf4j +public class CrmProductStatusParseFunction implements IParseFunction { + + public static final String NAME = "getProductStatusName"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CRM_PRODUCT_STATUS, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java new file mode 100644 index 0000000..cec152e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 产品单位的 {@link IParseFunction} 实现类 + * + * @author anhaohao + */ +@Component +@Slf4j +public class CrmProductUnitParseFunction implements IParseFunction { + + public static final String NAME = "getProductUnitName"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CRM_PRODUCT_UNIT, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java new file mode 100644 index 0000000..e9943eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivablePlanService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * CRM 回款计划的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class CrmReceivablePlanParseFunction implements IParseFunction { + + public static final String NAME = "getReceivablePlanServiceById"; + + @Resource + private CrmReceivablePlanService receivablePlanService; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(Long.parseLong(value.toString())); + return receivablePlan == null ? "" : receivablePlan.getPeriod().toString(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java new file mode 100644 index 0000000..3da7fe4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_RECEIVABLE_RETURN_TYPE; + +/** + * CRM 回款方式的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class CrmReceivableReturnTypeParseFunction implements IParseFunction { + + public static final String NAME = "getReceivableReturnType"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(CRM_RECEIVABLE_RETURN_TYPE, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAdminUserParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAdminUserParseFunction.java new file mode 100644 index 0000000..d419fb4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAdminUserParseFunction.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 管理员名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class SysAdminUserParseFunction implements IParseFunction { + + public static final String NAME = "getAdminUserById"; + + @Resource + private AdminUserApi adminUserApi; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取用户信息 + AdminUserRespDTO user = adminUserApi.getUser(Long.parseLong(value.toString())); + if (user == null) { + log.warn("[apply][获取用户{{}}为空", value); + return ""; + } + // 返回格式 芋道源码(13888888888) + String nickname = user.getNickname(); + if (StrUtil.isEmpty(user.getMobile())) { + return nickname; + } + return StrUtil.format("{}({})", nickname, user.getMobile()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAreaParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAreaParseFunction.java new file mode 100644 index 0000000..3ccc769 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysAreaParseFunction.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 地名的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class SysAreaParseFunction implements IParseFunction { + + public static final String NAME = "getArea"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return AreaUtils.format(Integer.parseInt(value.toString())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java new file mode 100644 index 0000000..0e722a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 是否类型的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class SysBooleanParseFunction implements IParseFunction { + + public static final String NAME = "getBoolean"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysDeptParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysDeptParseFunction.java new file mode 100644 index 0000000..c44dc2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysDeptParseFunction.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 管理员名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class SysDeptParseFunction implements IParseFunction { + + public static final String NAME = "getDeptById"; + + @Resource + private DeptApi deptApi; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取部门信息 + DeptRespDTO dept = deptApi.getDept(Long.parseLong(value.toString())); + if (dept == null) { + log.warn("[apply][获取部门{{}}为空", value); + return ""; + } + return dept.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java new file mode 100644 index 0000000..c8a9a99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 行业的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class SysSexParseFunction implements IParseFunction { + + public static final String NAME = "getSex"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java new file mode 100644 index 0000000..413b652 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java @@ -0,0 +1,4 @@ +/** + * crm 模块的 operatelog 拓展封装 + */ +package cn.iocoder.yudao.module.crm.framework.operatelog; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/package-info.java new file mode 100644 index 0000000..281e36c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 crm 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.crm.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java new file mode 100644 index 0000000..9ef6d4d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.framework.permission.core.annotations; + +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; + +/** + * CRM 数据操作权限校验 AOP 注解 + * + * @author HUIHUI + */ +@Target({METHOD, ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface CrmPermission { + + /** + * CRM 类型 + */ + CrmBizTypeEnum[] bizType() default {}; + + /** + * CRM 类型扩展,通过 Spring EL 表达式获取到 {@link #bizType()} + * + * 目的:用于 CrmPermissionController 团队权限校验 + */ + String bizTypeValue() default ""; + + /** + * 数据编号,通过 Spring EL 表达式获取 + */ + String bizId(); + + /** + * 操作所需权限级别 + */ + CrmPermissionLevelEnum level(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java new file mode 100644 index 0000000..deeb04e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.crm.framework.permission.core.aop; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED; + +/** + * Crm 数据权限校验 AOP 切面 + * + * @author HUIHUI + */ +@Component +@Aspect +@Slf4j +public class CrmPermissionAspect { + + @Resource + private CrmPermissionService crmPermissionService; + + @Before("@annotation(crmPermission)") + public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) { + // 1.1 获取相关属性值 + Map expressionValues = parseExpressions(joinPoint, crmPermission); + Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ? + crmPermission.bizType()[0].getType() : (Integer) expressionValues.get(crmPermission.bizTypeValue()); // 模块类型 + // 1.2 处理兼容多个 bizId 的情况 + Object object = expressionValues.get(crmPermission.bizId()); // 模块数据编号 + Set bizIds = new HashSet<>(); + if (object instanceof Collection) { + bizIds.addAll(convertSet((Collection) object, item -> Long.parseLong(item.toString()))); + } else { + bizIds.add(Long.parseLong(object.toString())); + } + Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别 + + // 2. 逐个校验权限 + List permissionList = crmPermissionService.getPermissionListByBiz(bizType, bizIds); + Map> multiMap = convertMultiMap(permissionList, CrmPermissionDO::getBizId); + bizIds.forEach(bizId -> validatePermission(bizType, multiMap.get(bizId), permissionLevel)); + } + + private void validatePermission(Integer bizType, List bizPermissions, Integer permissionLevel) { + // 1. 如果是超级管理员则直接通过 + if (CrmPermissionUtils.isCrmAdmin()) { + return; + } + // 1.1 没有数据权限的情况 + if (CollUtil.isEmpty(bizPermissions)) { + // 公海数据如果没有团队成员大家也因该有读权限才对 + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + return; + } + // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针 + throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); + } else { // 1.2 有数据权限但是没有负责人的情况 + if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) { + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + return; + } + } + } + + // 2.1 情况一:如果自己是负责人,则默认有所有权限 + CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), getUserId())); + if (userPermission != null) { + if (CrmPermissionLevelEnum.isOwner(userPermission.getLevel())) { + return; + } + // 2.2 情况二:校验自己是否有读权限 + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + if (CrmPermissionLevelEnum.isRead(userPermission.getLevel()) // 校验当前用户是否有读权限 + || CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 + return; + } + } + // 2.3 情况三:校验自己是否有写权限 + if (CrmPermissionLevelEnum.isWrite(permissionLevel)) { + if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 + return; + } + } + } + // 2.4 没有权限,抛出异常 + log.info("[doBefore][userId({}) 要求权限({}) 实际权限({}) 数据校验错误]", // 打个 info 日志,方便后续排查问题、审计 + getUserId(), permissionLevel, toJsonString(userPermission)); + throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); + } + + /** + * 获得用户编号 + * + * @return 用户编号 + */ + private static Long getUserId() { + return WebFrameworkUtils.getLoginUserId(); + } + + private static Map parseExpressions(JoinPoint joinPoint, CrmPermission crmPermission) { + // 1. 需要解析的表达式 + List expressionStrings = new ArrayList<>(2); + expressionStrings.add(crmPermission.bizId()); + if (StrUtil.isNotEmpty(crmPermission.bizTypeValue())) { // 为空则表示 bizType 有值 + expressionStrings.add(crmPermission.bizTypeValue()); + } + // 2. 执行解析 + return SpringExpressionUtils.parseExpressions(joinPoint, expressionStrings); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java new file mode 100644 index 0000000..d895fe9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.framework.permission.core; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java new file mode 100644 index 0000000..97f76db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java @@ -0,0 +1,4 @@ +/** + * crm 模块的 permission 拓展封装 + */ +package cn.iocoder.yudao.module.crm.framework.permission; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java new file mode 100644 index 0000000..4f50375 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * crm 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class CrmWebConfiguration { + + /** + * crm 模块的 API 分组 + */ + @Bean + public GroupedOpenApi crmGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("crm"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java new file mode 100644 index 0000000..09de726 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * crm 模块的 web 拓展封装 + */ +package cn.iocoder.yudao.module.crm.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/customer/CrmCustomerAutoPutPoolJob.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/customer/CrmCustomerAutoPutPoolJob.java new file mode 100644 index 0000000..06f8d74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/customer/CrmCustomerAutoPutPoolJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.job.customer; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 客户自动掉入公海 Job + * + * @author 芋道源码 + */ +@Component +public class CrmCustomerAutoPutPoolJob implements JobHandler { + + @Resource + private CrmCustomerService customerService; + + @Override + @TenantJob + public String execute(String param) { + int count = customerService.autoPutCustomerPool(); + return String.format("掉入公海客户 %s 个", count); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java new file mode 100644 index 0000000..2214e6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java @@ -0,0 +1,4 @@ +/** + * 定时任务 + */ +package cn.iocoder.yudao.module.crm.job; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/package-info.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/package-info.java new file mode 100644 index 0000000..2ea5f9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/package-info.java @@ -0,0 +1,10 @@ +/** + * crm 包下,客户关系管理(Customer Relationship Management)。 + * 例如说:客户、联系人、商机、合同、回款等等 + * + * 1. Controller URL:以 /crm/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 crm_ 开头,方便在数据库中区分 + * + * 注意,由于 Crm 模块下,容易和其它模块重名,所以类名都加载 Crm 的前缀~ + */ +package cn.iocoder.yudao.module.crm; diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java new file mode 100644 index 0000000..d03da42 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java @@ -0,0 +1,206 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 商机 Service 接口 + * + * @author ljlleo + */ +public interface CrmBusinessService { + + /** + * 创建商机 + * + * @param createReqVO 创建信息 + * @param userId 用户编号 + * @return 编号 + */ + Long createBusiness(@Valid CrmBusinessSaveReqVO createReqVO, Long userId); + + /** + * 更新商机 + * + * @param updateReqVO 更新信息 + */ + void updateBusiness(@Valid CrmBusinessSaveReqVO updateReqVO); + + /** + * 更新商机相关跟进信息 + * + * @param id 编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 + */ + void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); + + /** + * 更新商机的下次联系时间 + * + * @param ids 编号数组 + * @param contactNextTime 下次联系时间 + */ + void updateBusinessContactNextTime(Collection ids, LocalDateTime contactNextTime); + + /** + * 更新商机的状态 + * + * @param reqVO 更新请求 + */ + void updateBusinessStatus(CrmBusinessUpdateStatusReqVO reqVO); + + /** + * 删除商机 + * + * @param id 编号 + */ + void deleteBusiness(Long id); + + /** + * 商机转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId); + + /** + * 获得商机 + * + * @param id 编号 + * @return 商机 + */ + CrmBusinessDO getBusiness(Long id); + + /** + * 校验商机是否有效 + * + * @param id 编号 + * @return 商机 + */ + CrmBusinessDO validateBusiness(Long id); + + /** + * 获得商机列表 + * + * @param ids 编号 + * @return 商机列表 + */ + List getBusinessList(Collection ids); + + /** + * 获得商机 Map + * + * @param ids 编号 + * @return 商机 Map + */ + default Map getBusinessMap(Collection ids) { + return convertMap(getBusinessList(ids), CrmBusinessDO::getId); + } + + /** + * 获得指定商机编号的产品列表 + * + * @param businessId 商机编号 + * @return 商机产品列表 + */ + List getBusinessProductListByBusinessId(Long businessId); + + /** + * 获得商机分页 + * + * 数据权限:基于 {@link CrmBusinessDO} + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 商机分页 + */ + PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId); + + /** + * 获得商机分页,基于指定客户 + * + * 数据权限:基于 {@link CrmCustomerDO} 读取 + * + * @param pageReqVO 分页查询 + * @return 商机分页 + */ + PageResult getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO); + + /** + * 获得商机分页,基于指定联系人 + * + * 数据权限:基于 {@link CrmContactDO} 读取 + * + * @param pageReqVO 分页参数 + * @return 商机分页 + */ + PageResult getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO); + + /** + * 获取关联客户的商机数量 + * + * @param customerId 客户编号 + * @return 数量 + */ + Long getBusinessCountByCustomerId(Long customerId); + + /** + * 获得使用指定商机状态组的商机数量 + * + * @param statusTypeId 商机状态组编号 + * @return 数量 + */ + Long getBusinessCountByStatusTypeId(Long statusTypeId); + + /** + * 获得商机状态名称 + * + * @param endStatus 结束状态 + * @param status 商机状态 + * @return 商机状态名称 + */ + default String getBusinessStatusName(Integer endStatus, CrmBusinessStatusDO status) { + if (endStatus != null) { + return CrmBusinessEndStatusEnum.fromStatus(endStatus).getName(); + } + return status.getName(); + } + + /** + * 获得商机列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 商机列表 + */ + List getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + + /** + * 获得商机分页,目前用于【数据统计】 + * + * @param pageVO 请求 + * @return 商机分页 + */ + PageResult getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java new file mode 100644 index 0000000..3fad07b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -0,0 +1,384 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper; +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * 商机 Service 实现类 + * + * @author ljlleo + */ +@Service +@Validated +public class CrmBusinessServiceImpl implements CrmBusinessService { + + @Resource + private CrmBusinessMapper businessMapper; + @Resource + private CrmBusinessProductMapper businessProductMapper; + + @Resource + private CrmBusinessStatusService businessStatusService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmContractService contractService; + @Resource + private CrmCustomerService customerService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmContactService contactService; + @Resource + private CrmPermissionService permissionService; + @Resource + private CrmContactBusinessService contactBusinessService; + @Resource + private CrmProductService productService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_CREATE_SUB_TYPE, bizNo = "{{#business.id}}", + success = CRM_BUSINESS_CREATE_SUCCESS) + public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) { + // 1.1 校验产品项的有效性 + List businessProducts = validateBusinessProducts(createReqVO.getProducts()); + // 1.2 校验关联字段 + validateRelationDataExists(createReqVO); + + // 2.1 插入商机 + CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class); + business.setStatusId(businessStatusService.getBusinessStatusListByTypeId(createReqVO.getStatusTypeId()).get(0).getId()); // 默认状态 + calculateTotalPrice(business, businessProducts); + businessMapper.insert(business); + // 2.2 插入商机关联商品 + if (CollUtil.isNotEmpty(businessProducts)) { + businessProducts.forEach(item -> item.setBusinessId(business.getId())); + businessProductMapper.insertBatch(businessProducts); + } + + // 3. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(business.getOwnerUserId()) + .setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()).setBizId(business.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 在联系人的详情页,如果直接【新建商机】,则需要关联下 + if (createReqVO.getContactId() != null) { + contactBusinessService.createContactBusinessList(new CrmContactBusinessReqVO().setContactId(createReqVO.getContactId()) + .setBusinessIds(Collections.singletonList(business.getId()))); + } + + // 5. 记录操作日志上下文 + LogRecordContext.putVariable("business", business); + return business.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_BUSINESS_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateBusiness(CrmBusinessSaveReqVO updateReqVO) { + updateReqVO.setOwnerUserId(null).setStatusTypeId(null); // 不允许更新的字段 + // 1.1 校验存在 + CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); + // 1.2 校验产品项的有效性 + List businessProducts = validateBusinessProducts(updateReqVO.getProducts()); + // 1.3 校验关联字段 + validateRelationDataExists(updateReqVO); + + // 2.1 更新商机 + CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class); + calculateTotalPrice(updateObj, businessProducts); + businessMapper.updateById(updateObj); + // 2.2 更新商机关联商品 + updateBusinessProduct(updateObj.getId(), businessProducts); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class)); + LogRecordContext.putVariable("businessName", oldBusiness.getName()); + } + + @Override + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", + success = CRM_BUSINESS_FOLLOW_UP_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { + // 1. 校验存在 + CrmBusinessDO business = validateBusinessExists(id); + + // 2. 更新联系人的跟进信息 + businessMapper.updateById(new CrmBusinessDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) + .setContactLastTime(LocalDateTime.now())); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("businessName", business.getName()); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE) + public void updateBusinessContactNextTime(Collection ids, LocalDateTime contactNextTime) { + businessMapper.updateBatch(convertList(ids, id -> new CrmBusinessDO().setId(id).setContactNextTime(contactNextTime))); + } + + private void updateBusinessProduct(Long id, List newList) { + List oldList = businessProductMapper.selectListByBusinessId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setBusinessId(id)); + businessProductMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + businessProductMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + businessProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessProductDO::getId)); + } + } + + private void validateRelationDataExists(CrmBusinessSaveReqVO saveReqVO) { + // 校验商机状态 + if (saveReqVO.getStatusTypeId() != null) { + businessStatusService.validateBusinessStatusType(saveReqVO.getStatusTypeId()); + } + // 校验客户 + if (saveReqVO.getCustomerId() != null) { + customerService.validateCustomer(saveReqVO.getCustomerId()); + } + // 校验联系人 + if (saveReqVO.getContactId() != null) { + contactService.validateContact(saveReqVO.getContactId()); + } + // 校验负责人 + if (saveReqVO.getOwnerUserId() != null) { + adminUserApi.validateUser(saveReqVO.getOwnerUserId()); + } + } + + private List validateBusinessProducts(List list) { + // 1. 校验产品存在 + productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.BusinessProduct::getProductId)); + // 2. 转化为 CrmBusinessProductDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, + item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); + } + + private void calculateTotalPrice(CrmBusinessDO business, List businessProducts) { + business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); + business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); + } + + @Override + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_BUSINESS_UPDATE_STATUS_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateBusinessStatus(CrmBusinessUpdateStatusReqVO reqVO) { + // 1.1 校验存在 + CrmBusinessDO business = validateBusinessExists(reqVO.getId()); + // 1.2 校验商机未结束 + if (business.getEndStatus() != null) { + throw exception(BUSINESS_UPDATE_STATUS_FAIL_END_STATUS); + } + // 1.3 校验商机状态 + CrmBusinessStatusDO status = null; + if (reqVO.getStatusId() != null) { + status = businessStatusService.validateBusinessStatus(business.getStatusTypeId(), reqVO.getStatusId()); + } + // 1.4 校验是不是状态没变更 + if ((reqVO.getStatusId() != null && reqVO.getStatusId().equals(business.getStatusId())) + || (reqVO.getEndStatus() != null && reqVO.getEndStatus().equals(business.getEndStatus()))) { + throw exception(BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS); + } + + // 2. 更新商机状态 + businessMapper.updateById(new CrmBusinessDO().setId(reqVO.getId()).setStatusId(reqVO.getStatusId()) + .setEndStatus(reqVO.getEndStatus())); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("businessName", business.getName()); + LogRecordContext.putVariable("oldStatusName", getBusinessStatusName(business.getEndStatus(), + businessStatusService.getBusinessStatus(business.getStatusId()))); + LogRecordContext.putVariable("newStatusName", getBusinessStatusName(reqVO.getEndStatus(), status)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_BUSINESS_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteBusiness(Long id) { + // 1.1 校验存在 + CrmBusinessDO business = validateBusinessExists(id); + // 1.2 校验是否关联合同 + validateContractExists(id); + + // 删除商机 + businessMapper.deleteById(id); + // 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("businessName", business.getName()); + } + + /** + * 删除校验合同是关联合同 + * + * @param businessId 商机id + * @author lzxhqs + */ + private void validateContractExists(Long businessId) { + if (contractService.getContractCountByBusinessId(businessId) > 0) { + throw exception(BUSINESS_DELETE_FAIL_CONTRACT_EXISTS); + } + } + + private CrmBusinessDO validateBusinessExists(Long id) { + CrmBusinessDO crmBusiness = businessMapper.selectById(id); + if (crmBusiness == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + return crmBusiness; + } + + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_BUSINESS_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) { + // 1 校验商机是否存在 + CrmBusinessDO business = validateBusinessExists(reqVO.getId()); + + // 2.1 数据权限转移 + permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_BUSINESS.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + // 2.2 设置新的负责人 + businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + + // 记录操作日志上下文 + LogRecordContext.putVariable("business", business); + } + + //======================= 查询相关 ======================= + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmBusinessDO getBusiness(Long id) { + return businessMapper.selectById(id); + } + + @Override + public CrmBusinessDO validateBusiness(Long id) { + return validateBusinessExists(id); + } + + @Override + public List getBusinessList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return businessMapper.selectBatchIds(ids); + } + + @Override + public List getBusinessProductListByBusinessId(Long businessId) { + return businessProductMapper.selectListByBusinessId(businessId); + } + + @Override + public PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId) { + return businessMapper.selectPage(pageReqVO, userId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) + public PageResult getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO) { + return businessMapper.selectPageByCustomerId(pageReqVO); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#pageReqVO.contactId", level = CrmPermissionLevelEnum.READ) + public PageResult getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO) { + // 1. 查询关联的商机编号 + List contactBusinessList = contactBusinessService.getContactBusinessListByContactId( + pageReqVO.getContactId()); + if (CollUtil.isEmpty(contactBusinessList)) { + return PageResult.empty(); + } + // 2. 查询商机分页 + return businessMapper.selectPageByContactId(pageReqVO, + convertSet(contactBusinessList, CrmContactBusinessDO::getBusinessId)); + } + + @Override + public Long getBusinessCountByCustomerId(Long customerId) { + return businessMapper.selectCount(CrmBusinessDO::getCustomerId, customerId); + } + + @Override + public Long getBusinessCountByStatusTypeId(Long statusTypeId) { + return businessMapper.selectCountByStatusTypeId(statusTypeId); + } + + @Override + public List getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return businessMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + + @Override + public PageResult getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) { + return businessMapper.selectPage(pageVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java new file mode 100644 index 0000000..285e984 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 商机状态 Service 接口 + * + * @author ljlleo + */ +public interface CrmBusinessStatusService { + + /** + * 创建商机状态 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBusinessStatus(@Valid CrmBusinessStatusSaveReqVO createReqVO); + + /** + * 更新商机状态 + * + * @param updateReqVO 更新信息 + */ + void updateBusinessStatus(@Valid CrmBusinessStatusSaveReqVO updateReqVO); + + /** + * 删除商机状态 + * + * @param id 编号 + */ + void deleteBusinessStatusType(Long id); + + /** + * 获得商机状态组 + * + * @param id 编号 + * @return 商机状态组 + */ + CrmBusinessStatusTypeDO getBusinessStatusType(Long id); + + /** + * 校验商机状态组 + * + * @param id 编号 + */ + void validateBusinessStatusType(Long id); + + /** + * 获得商机状态组列表 + * + * @return 商机状态组列表 + */ + List getBusinessStatusTypeList(); + + /** + * 获得商机状态组分页 + * + * @param pageReqVO 分页查询 + * @return 商机状态组分页 + */ + PageResult getBusinessStatusTypePage(PageParam pageReqVO); + + /** + * 获得商机状态组列表 + * + * @param ids 编号数组 + * @return 商机状态组列表 + */ + List getBusinessStatusTypeList(Collection ids); + + /** + * 获得商机状态组 Map + * + * @param ids 编号数组 + * @return 商机状态组 Map + */ + default Map getBusinessStatusTypeMap(Collection ids) { + return convertMap(getBusinessStatusTypeList(ids), CrmBusinessStatusTypeDO::getId); + } + + /** + * 获得指定类型的商机状态列表 + * + * @param typeId 商机状态组编号 + * @return 商机状态列表 + */ + List getBusinessStatusListByTypeId(Long typeId); + + /** + * 获得商机状态列表 + * + * @param ids 编号数组 + * @return 商机状态列表 + */ + List getBusinessStatusList(Collection ids); + + /** + * 获得商机状态 Map + * + * @param ids 编号数组 + * @return 商机状态 Map + */ + default Map getBusinessStatusMap(Collection ids) { + return convertMap(getBusinessStatusList(ids), CrmBusinessStatusDO::getId); + } + + /** + * 获得商机状态 + * + * @param id 编号 + * @return 商机状态 + */ + CrmBusinessStatusDO getBusinessStatus(Long id); + + /** + * 校验商机状态 + * + * @param statusTypeId 商机状态组编号 + * @param statusId 商机状态编号 + */ + CrmBusinessStatusDO validateBusinessStatus(Long statusTypeId, Long statusId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java new file mode 100644 index 0000000..3c2e0b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java @@ -0,0 +1,195 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusMapper; +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusTypeMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; + +/** + * 商机状态 Service 实现类 + * + * @author ljlleo + */ +@Service +@Validated +public class CrmBusinessStatusServiceImpl implements CrmBusinessStatusService { + + @Resource + private CrmBusinessStatusTypeMapper businessStatusTypeMapper; + @Resource + private CrmBusinessStatusMapper businessStatusMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmBusinessService businessService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createBusinessStatus(CrmBusinessStatusSaveReqVO createReqVO) { + // 1.1 检验名称是否存在 + validateBusinessStatusTypeNameUnique(createReqVO.getName(), null); + // 1.2 设置状态的排序 + int sort = 0; + for (CrmBusinessStatusSaveReqVO.Status status : createReqVO.getStatuses()) { + status.setSort(sort++); + } + + // 2.1 插入类型 + CrmBusinessStatusTypeDO statusType = BeanUtils.toBean(createReqVO, CrmBusinessStatusTypeDO.class); + businessStatusTypeMapper.insert(statusType); + // 2.2 插入状态 + List statuses = BeanUtils.toBean(createReqVO.getStatuses(), CrmBusinessStatusDO.class, + status -> status.setTypeId(statusType.getId())); + businessStatusMapper.insertBatch(statuses); + return statusType.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateBusinessStatus(CrmBusinessStatusSaveReqVO updateReqVO) { + // 1.1 校验存在 + validateBusinessStatusTypeExists(updateReqVO.getId()); + // 1.2 校验名称是否存在 + validateBusinessStatusTypeNameUnique(updateReqVO.getName(), updateReqVO.getId()); + // 1.3 设置状态的排序 + int sort = 0; + for (CrmBusinessStatusSaveReqVO.Status status : updateReqVO.getStatuses()) { + status.setSort(sort++); + } + // 1.4 已经使用,无法更新 + if (businessService.getBusinessCountByStatusTypeId(updateReqVO.getId()) > 0) { + throw exception(BUSINESS_STATUS_UPDATE_FAIL_USED); + } + + // 2.1 更新类型 + CrmBusinessStatusTypeDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessStatusTypeDO.class); + businessStatusTypeMapper.updateById(updateObj); + // 2.2 更新状态 + updateBusinessStatus(updateReqVO.getId(), BeanUtils.toBean(updateReqVO.getStatuses(), CrmBusinessStatusDO.class)); + } + + private void updateBusinessStatus(Long id, List newList) { + List oldList = businessStatusMapper.selectListByTypeId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setTypeId(id)); + businessStatusMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + businessStatusMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + businessStatusMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessStatusDO::getId)); + } + } + + private void validateBusinessStatusTypeExists(Long id) { + if (businessStatusTypeMapper.selectById(id) == null) { + throw exception(BUSINESS_STATUS_TYPE_NOT_EXISTS); + } + } + + private void validateBusinessStatusTypeNameUnique(String name, Long id) { + CrmBusinessStatusTypeDO statusType = businessStatusTypeMapper.selectByName(name); + if (statusType == null + || statusType.getId().equals(id)) { + return; + } + throw exception(BUSINESS_STATUS_TYPE_NAME_EXISTS); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBusinessStatusType(Long id) { + // 1.1 校验存在 + validateBusinessStatusTypeExists(id); + // 1.2 已经使用,无法更新 + if (businessService.getBusinessCountByStatusTypeId(id) > 0) { + throw exception(BUSINESS_STATUS_DELETE_FAIL_USED); + } + + // 2.1 删除类型 + businessStatusTypeMapper.deleteById(id); + // 2.2 删除状态 + businessStatusMapper.deleteByTypeId(id); + } + + @Override + public CrmBusinessStatusTypeDO getBusinessStatusType(Long id) { + return businessStatusTypeMapper.selectById(id); + } + + @Override + public void validateBusinessStatusType(Long id) { + validateBusinessStatusTypeExists(id); + } + + @Override + public List getBusinessStatusTypeList() { + return businessStatusTypeMapper.selectList(); + } + + @Override + public PageResult getBusinessStatusTypePage(PageParam pageReqVO) { + return businessStatusTypeMapper.selectPage(pageReqVO); + } + + @Override + public List getBusinessStatusTypeList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return businessStatusTypeMapper.selectBatchIds(ids); + } + + @Override + public List getBusinessStatusListByTypeId(Long typeId) { + List list = businessStatusMapper.selectListByTypeId(typeId); + list.sort(Comparator.comparingInt(CrmBusinessStatusDO::getSort)); + return list; + } + + @Override + public List getBusinessStatusList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return businessStatusMapper.selectBatchIds(ids); + } + + @Override + public CrmBusinessStatusDO getBusinessStatus(Long id) { + return businessStatusMapper.selectById(id); + } + + @Override + public CrmBusinessStatusDO validateBusinessStatus(Long statusTypeId, Long statusId) { + CrmBusinessStatusDO status = businessStatusMapper.selectByTypeIdAndId(statusTypeId, statusId); + if (status == null) { + throw exception(BUSINESS_STATUS_NOT_EXISTS); + } + return status; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java new file mode 100644 index 0000000..b325bfd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.crm.service.clue; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 线索 Service 接口 + * + * @author Wanwan + */ +public interface CrmClueService { + + /** + * 创建线索 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createClue(@Valid CrmClueSaveReqVO createReqVO); + + /** + * 更新线索 + * + * @param updateReqVO 更新信息 + */ + void updateClue(@Valid CrmClueSaveReqVO updateReqVO); + + /** + * 更新线索相关的跟进信息 + * + * @param id 编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 + */ + void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); + + /** + * 删除线索 + * + * @param id 编号 + */ + void deleteClue(Long id); + + /** + * 获得线索 + * + * @param id 编号 + * @return 线索 + */ + CrmClueDO getClue(Long id); + + /** + * 获得线索列表 + * + * @param ids 编号 + * @return 线索列表 + */ + List getClueList(Collection ids, Long userId); + + /** + * 获得线索分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 线索分页 + */ + PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId); + + /** + * 线索转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferClue(CrmClueTransferReqVO reqVO, Long userId); + + /** + * 线索转化为客户 + * + * @param id 线索编号 + * @param userId 用户编号 + */ + void transformClue(Long id, Long userId); + + /** + * 获得分配给我的、待跟进的线索数量 + * + * @param userId 用户编号 + * @return 数量 + */ + Long getFollowClueCount(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java new file mode 100644 index 0000000..3a9977d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -0,0 +1,241 @@ +package cn.iocoder.yudao.module.crm.service.clue; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; +import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; +import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.singleton; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_TRANSFORM_FAIL_ALREADY; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; + +/** + * 线索 Service 实现类 + * + * @author Wanwan + */ +@Service +@Validated +public class CrmClueServiceImpl implements CrmClueService { + + @Resource + private CrmClueMapper clueMapper; + + @Resource + private CrmCustomerService customerService; + @Resource + private CrmPermissionService crmPermissionService; + @Resource + private CrmFollowUpRecordService followUpRecordService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_CREATE_SUB_TYPE, bizNo = "{{#clue.id}}", + success = CRM_CLUE_CREATE_SUCCESS) + public Long createClue(CrmClueSaveReqVO createReqVO) { + // 1.1 校验关联数据 + validateRelationDataExists(createReqVO); + // 1.2 校验负责人是否存在 + adminUserApi.validateUser(createReqVO.getOwnerUserId()); + + // 2. 插入线索 + CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class); + clueMapper.insert(clue); + + // 3. 创建数据权限 + CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CLUE.getType()) + .setBizId(clue.getId()).setUserId(clue.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()); + crmPermissionService.createPermission(createReqBO); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("clue", clue); + return clue.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CLUE_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER) + public void updateClue(CrmClueSaveReqVO updateReq) { + Assert.notNull(updateReq.getId(), "线索编号不能为空"); + // 1.1 校验线索是否存在 + CrmClueDO oldClue = validateClueExists(updateReq.getId()); + // 1.2 校验关联数据 + validateRelationDataExists(updateReq); + + // 2. 更新线索 + CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class); + clueMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmCustomerSaveReqVO.class)); + LogRecordContext.putVariable("clueName", oldClue.getName()); + } + + private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { + // 校验负责人 + if (Objects.nonNull(reqVO.getOwnerUserId()) && + Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()))) { + throw exception(USER_NOT_EXISTS); + } + } + + @Override + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CLUE_FOLLOW_UP_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { + // 校验线索是否存在 + CrmClueDO oldClue = validateClueExists(id); + + // 更新线索 + clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) + .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("clueName", oldClue.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CLUE_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteClue(Long id) { + // 1. 校验存在 + CrmClueDO clue = validateClueExists(id); + + // 2. 删除 + clueMapper.deleteById(id); + + // 3. 删除数据权限 + crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CLUE.getType(), id); + + // 4. 删除跟进 + followUpRecordService.deleteFollowUpRecordByBiz(CrmBizTypeEnum.CRM_CLUE.getType(), id); + + // 5. 记录操作日志上下文 + LogRecordContext.putVariable("clueName", clue.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CLUE_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { + // 1 校验线索是否存在 + CrmClueDO clue = validateClueExists(reqVO.getId()); + + // 2.1 数据权限转移 + crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CLUE.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + // 2.2 设置新的负责人 + clueMapper.updateById(new CrmClueDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + + // 3. 记录转移日志 + LogRecordContext.putVariable("clue", clue); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSLATE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CLUE_TRANSLATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void transformClue(Long id, Long userId) { + // 1.1 校验线索都存在 + CrmClueDO clue = validateClueExists(id); + // 1.2 存在已经转化的 + if (clue.getTransformStatus()) { + throw exception(CLUE_TRANSFORM_FAIL_ALREADY); + } + + // 2.1 遍历线索(未转化的线索),创建对应的客户 + Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); + // 2.2 更新线索 + clueMapper.updateById(new CrmClueDO().setId(id).setTransformStatus(Boolean.TRUE).setCustomerId(customerId)); + // 2.3 复制跟进记录 + List followUpRecords = followUpRecordService.getFollowUpRecordByBiz( + CrmBizTypeEnum.CRM_CLUE.getType(), singleton(clue.getId())); + if (CollUtil.isNotEmpty(followUpRecords)) { + followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, record -> + BeanUtils.toBean(record, CrmFollowUpCreateReqBO.class) + .setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()).setBizId(customerId))); + } + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("clueName", clue.getName()); + } + + private CrmClueDO validateClueExists(Long id) { + CrmClueDO crmClueDO = clueMapper.selectById(id); + if (crmClueDO == null) { + throw exception(CLUE_NOT_EXISTS); + } + return crmClueDO; + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmClueDO getClue(Long id) { + return clueMapper.selectById(id); + } + + @Override + public List getClueList(Collection ids, Long userId) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return clueMapper.selectBatchIds(ids, userId); + } + + @Override + public PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId) { + return clueMapper.selectPage(pageReqVO, userId); + } + + @Override + public Long getFollowClueCount(Long userId) { + return clueMapper.selectCountByFollow(userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java new file mode 100644 index 0000000..e3e94ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.crm.service.contact; + +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusiness2ReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * CRM 联系人与商机的关联 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmContactBusinessService { + + /** + * 创建联系人与商机的关联【通过联系人,关联商机】 + * + * @param createReqVO 创建信息 + */ + void createContactBusinessList(@Valid CrmContactBusinessReqVO createReqVO); + + /** + * 创建联系人与商机的关联【通过商机,关联联系人】 + * + * @param createReqVO 创建信息 + */ + void createContactBusinessList2(@Valid CrmContactBusiness2ReqVO createReqVO); + + /** + * 删除联系人与商机的关联【通过联系人,取关商机】 + * + * @param deleteReqVO 删除信息 + */ + void deleteContactBusinessList(@Valid CrmContactBusinessReqVO deleteReqVO); + + /** + * 删除联系人与商机的关联【通过商机,取关联系人】 + * + * @param deleteReqVO 删除信息 + */ + void deleteContactBusinessList2(@Valid CrmContactBusiness2ReqVO deleteReqVO); + + /** + * 删除联系人与商机的关联,基于联系人编号 + * + * @param contactId 联系人编号 + */ + void deleteContactBusinessByContactId(Long contactId); + + /** + * 获得联系人与商机的关联列表,基于联系人编号 + * + * @param contactId 联系人编号 + * @return 联系人商机关联 + */ + List getContactBusinessListByContactId(Long contactId); + + /** + * 获得联系人与商机的关联列表,基于商机编号 + * + * @param businessId 商机编号 + * @return 联系人商机关联 + */ + List getContactBusinessListByBusinessId(Long businessId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java new file mode 100644 index 0000000..c824946 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.crm.service.contact; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusiness2ReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactBusinessMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_NOT_EXISTS; + +/** + * 联系人与商机的关联 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmContactBusinessServiceImpl implements CrmContactBusinessService { + + @Resource + private CrmContactBusinessMapper contactBusinessMapper; + + @Resource + @Lazy // 延迟加载,为了解决延迟加载 + private CrmBusinessService businessService; + @Resource + @Lazy // 延迟加载,为了解决延迟加载 + private CrmContactService contactService; + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#createReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) + public void createContactBusinessList(CrmContactBusinessReqVO createReqVO) { + CrmContactDO contact = contactService.getContact(createReqVO.getContactId()); + if (contact == null) { + throw exception(CONTACT_NOT_EXISTS); + } + // 遍历处理,考虑到一般数量不会太多,代码处理简单 + List saveDOList = new ArrayList<>(); + createReqVO.getBusinessIds().forEach(businessId -> { + CrmBusinessDO business = businessService.getBusiness(businessId); + if (business == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + // 关联判重 + if (contactBusinessMapper.selectByContactIdAndBusinessId(createReqVO.getContactId(), businessId) != null) { + return; + } + saveDOList.add(new CrmContactBusinessDO(null, createReqVO.getContactId(), businessId)); + }); + // 批量插入 + if (CollUtil.isNotEmpty(saveDOList)) { + contactBusinessMapper.insertBatch(saveDOList); + } + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#createReqVO.businessId", level = CrmPermissionLevelEnum.WRITE) + public void createContactBusinessList2(CrmContactBusiness2ReqVO createReqVO) { + CrmBusinessDO business = businessService.getBusiness(createReqVO.getBusinessId()); + if (business == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + // 遍历处理,考虑到一般数量不会太多,代码处理简单 + List saveDOList = new ArrayList<>(); + createReqVO.getContactIds().forEach(contactId -> { + CrmContactDO contact = contactService.getContact(contactId); + if (contact == null) { + throw exception(CONTACT_NOT_EXISTS); + } + // 关联判重 + if (contactBusinessMapper.selectByContactIdAndBusinessId(contactId, createReqVO.getBusinessId()) != null) { + return; + } + saveDOList.add(new CrmContactBusinessDO(null, contactId, createReqVO.getBusinessId())); + }); + // 批量插入 + if (CollUtil.isNotEmpty(saveDOList)) { + contactBusinessMapper.insertBatch(saveDOList); + } + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#deleteReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) + public void deleteContactBusinessList(CrmContactBusinessReqVO deleteReqVO) { + CrmContactDO contact = contactService.getContact(deleteReqVO.getContactId()); + if (contact == null) { + throw exception(CONTACT_NOT_EXISTS); + } + // 直接删除 + contactBusinessMapper.deleteByContactIdAndBusinessId( + deleteReqVO.getContactId(), deleteReqVO.getBusinessIds()); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#deleteReqVO.businessId", level = CrmPermissionLevelEnum.WRITE) + public void deleteContactBusinessList2(CrmContactBusiness2ReqVO deleteReqVO) { + CrmBusinessDO business = businessService.getBusiness(deleteReqVO.getBusinessId()); + if (business == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + // 直接删除 + contactBusinessMapper.deleteByBusinessIdAndContactId( + deleteReqVO.getBusinessId(), deleteReqVO.getContactIds()); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.WRITE) + public void deleteContactBusinessByContactId(Long contactId) { + contactBusinessMapper.delete(CrmContactBusinessDO::getContactId, contactId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.READ) + public List getContactBusinessListByContactId(Long contactId) { + return contactBusinessMapper.selectListByContactId(contactId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#businessId", level = CrmPermissionLevelEnum.READ) + public List getContactBusinessListByBusinessId(Long businessId) { + return contactBusinessMapper.selectListByBusinessId(businessId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java new file mode 100644 index 0000000..24273db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.crm.service.contact; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 联系人 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmContactService { + + /** + * 创建联系人 + * + * @param createReqVO 创建信息 + * @param userId 用户编号 + * @return 编号 + */ + Long createContact(@Valid CrmContactSaveReqVO createReqVO, Long userId); + + /** + * 更新联系人 + * + * @param updateReqVO 更新信息 + */ + void updateContact(@Valid CrmContactSaveReqVO updateReqVO); + + /** + * 删除联系人 + * + * @param id 编号 + */ + void deleteContact(Long id); + + /** + * 联系人转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferContact(CrmContactTransferReqVO reqVO, Long userId); + + /** + * 更新指定客户的联系人的负责人 + * 数据权限基于 【客户】 + * + * @param customerId 客户编号 + * @param ownerUserId 用户编号 + */ + void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId); + + /** + * 更新联系人相关跟进信息 + * + * @param id 编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 + */ + void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); + + /** + * 更新联系人的下次联系时间 + * + * @param ids 编号数组 + * @param contactNextTime 下次联系时间 + */ + void updateContactContactNextTime(Collection ids, LocalDateTime contactNextTime); + + /** + * 获得联系人 + * + * @param id 编号 + * @return 联系人 + */ + CrmContactDO getContact(Long id); + + /** + * 校验联系人 + * + * @param id 编号 + */ + void validateContact(Long id); + + /** + * 获得联系人列表 + * + * @param ids 编号 + * @return 联系人列表 + */ + List getContactList(Collection ids); + + /** + * 获得联系人 Map + * + * @param ids 编号 + * @return 联系人 Map + */ + default Map getContactMap(Collection ids) { + return convertMap(getContactList(ids), CrmContactDO::getId); + } + + /** + * 获取联系人列表(校验权限) + * + * @param userId 用户编号 + * @return 联系人列表 + */ + List getContactList(Long userId); + + /** + * 获得联系人分页 + * + * 数据权限:基于 {@link CrmContactDO} + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 联系人分页 + */ + PageResult getContactPage(CrmContactPageReqVO pageReqVO, Long userId); + + /** + * 获得联系人分页 + * + * 数据权限:基于 {@link CrmCustomerDO} + * + * @param pageVO 分页查询 + * @return 联系人分页 + */ + PageResult getContactPageByCustomerId(CrmContactPageReqVO pageVO); + + /** + * 获得联系人分页 + * + * 数据权限:基于 {@link CrmBusinessDO} + * + * @param pageVO 分页查询 + * @return 联系人分页 + */ + PageResult getContactPageByBusinessId(CrmContactPageReqVO pageVO); + + /** + * 获取关联客户的联系人数量 + * + * @param customerId 客户编号 + * @return 数量 + */ + Long getContactCountByCustomerId(Long customerId); + + /** + * 获得联系人列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 联系人列表 + */ + List getContactListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java new file mode 100644 index 0000000..ab0fcfd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java @@ -0,0 +1,306 @@ +package cn.iocoder.yudao.module.crm.service.contact; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static java.util.Collections.singletonList; + +/** + * CRM 联系人 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmContactServiceImpl implements CrmContactService { + + @Resource + private CrmContactMapper contactMapper; + + @Resource + private CrmCustomerService customerService; + @Resource + private CrmPermissionService permissionService; + @Resource + @Lazy + private CrmContractService contractService; + @Resource + private CrmContactBusinessService contactBusinessService; + @Resource + private CrmBusinessService businessService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_CREATE_SUB_TYPE, bizNo = "{{#contact.id}}", + success = CRM_CONTACT_CREATE_SUCCESS) + public Long createContact(CrmContactSaveReqVO createReqVO, Long userId) { + createReqVO.setId(null); + // 1. 校验关联数据 + validateRelationDataExists(createReqVO); + + // 2. 插入联系人 + CrmContactDO contact = BeanUtils.toBean(createReqVO, CrmContactDO.class); + contactMapper.insert(contact); + + // 3. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) + .setBizType(CrmBizTypeEnum.CRM_CONTACT.getType()).setBizId(contact.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 如果有关联商机,则需要创建关联 + if (createReqVO.getBusinessId() != null) { + contactBusinessService.createContactBusinessList(new CrmContactBusinessReqVO() + .setContactId(contact.getId()).setBusinessIds(singletonList(createReqVO.getBusinessId()))); + } + + // 5. 记录操作日志 + LogRecordContext.putVariable("contact", contact); + return contact.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CONTACT_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateContact(CrmContactSaveReqVO updateReqVO) { + // 1.1 校验存在 + CrmContactDO oldContact = validateContactExists(updateReqVO.getId()); + // 1.2 校验关联数据 + validateRelationDataExists(updateReqVO); + + // 2. 更新联系人 + CrmContactDO updateObj = BeanUtils.toBean(updateReqVO, CrmContactDO.class); + contactMapper.updateById(updateObj); + + // 3. 记录操作日志 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContact, CrmContactSaveReqVO.class)); + LogRecordContext.putVariable("contactName", oldContact.getName()); + } + + /** + * 校验关联的数据都存在 + * + * @param saveReqVO 新增/修改请求 VO + */ + private void validateRelationDataExists(CrmContactSaveReqVO saveReqVO) { + // 1. 校验客户 + if (saveReqVO.getCustomerId() != null && customerService.getCustomer(saveReqVO.getCustomerId()) == null) { + customerService.validateCustomer(saveReqVO.getCustomerId()); + } + // 2. 校验负责人 + if (saveReqVO.getOwnerUserId() != null) { + adminUserApi.validateUser(saveReqVO.getOwnerUserId()); + } + // 3. 直属上级 + if (saveReqVO.getParentId() != null) { + validateContactExists(saveReqVO.getParentId()); + } + // 4. 如果有关联商机,则需要校验存在 + if (saveReqVO.getBusinessId() != null && businessService.getBusiness(saveReqVO.getBusinessId()) == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CONTACT_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteContact(Long id) { + // 1.1 校验存在 + CrmContactDO contact = validateContactExists(id); + // 1.2 校验是否关联合同 + if (contractService.getContractCountByContactId(id) > 0) { + throw exception(CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS); + } + + // 2. 删除联系人 + contactMapper.deleteById(id); + + // 4.1 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_CONTACT.getType(), id); + // 4.2 删除商机关联 + contactBusinessService.deleteContactBusinessByContactId(id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("contactName", contact.getName()); + } + + private CrmContactDO validateContactExists(Long id) { + CrmContactDO contact = contactMapper.selectById(id); + if (contact == null) { + throw exception(CONTACT_NOT_EXISTS); + } + return contact; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CONTACT_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferContact(CrmContactTransferReqVO reqVO, Long userId) { + // 1 校验联系人是否存在 + CrmContactDO contact = validateContactExists(reqVO.getId()); + + // 2.1 数据权限转移 + permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTACT.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + // 2.2 设置新的负责人 + contactMapper.updateById(new CrmContactDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + + // 3. 记录转移日志 + LogRecordContext.putVariable("contact", contact); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#customerId", level = CrmPermissionLevelEnum.OWNER) + public void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { + // 1. 校验存在 + List contacts = contactMapper.selectListByCustomerId(customerId); + if (CollUtil.isEmpty(contacts)) { + return; + } + int count = contactMapper.updateOwnerUserIdByCustomerId(customerId, ownerUserId); + if (count == 0) { + throw exception(CONTACT_UPDATE_OWNER_USER_FAIL); + } + + // 2. 记录操作日志 + for (CrmContactDO contact : contacts) { + receiveContactLog(contact, ownerUserId); + } + } + + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_UPDATE_OWNER_USER_SUB_TYPE, bizNo = "{{#contact.id}", + success = CRM_CONTACT_UPDATE_OWNER_USER_SUCCESS) + public void receiveContactLog(CrmContactDO contact, Long ownerUserId) { + // 记录操作日志上下文 + LogRecordContext.putVariable("contact", contact); + LogRecordContext.putVariable("ownerUserId", ownerUserId); + } + + @Override + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", + success = CRM_CONTACT_FOLLOW_UP_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { + // 1. 校验存在 + CrmContactDO contact = validateContactExists(id); + + // 2. 更新联系人的跟进信息 + contactMapper.updateById(new CrmContactDO().setId(id).setContactNextTime(contactNextTime) + .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("contactName", contact.getName()); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE) + public void updateContactContactNextTime(Collection ids, LocalDateTime contactNextTime) { + contactMapper.updateBatch(convertList(ids, id -> new CrmContactDO().setId(id).setContactNextTime(contactNextTime))); + } + + //======================= 查询相关 ======================= + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmContactDO getContact(Long id) { + return contactMapper.selectById(id); + } + + @Override + public void validateContact(Long id) { + validateContactExists(id); + } + + @Override + public List getContactList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return contactMapper.selectBatchIds(ids); + } + + @Override + public List getContactList(Long userId) { + CrmContactPageReqVO reqVO = new CrmContactPageReqVO(); + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 + return contactMapper.selectPage(reqVO, userId).getList(); + } + + @Override + public PageResult getContactPage(CrmContactPageReqVO pageReqVO, Long userId) { + return contactMapper.selectPage(pageReqVO, userId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageVO.customerId", level = CrmPermissionLevelEnum.READ) + public PageResult getContactPageByCustomerId(CrmContactPageReqVO pageVO) { + return contactMapper.selectPageByCustomerId(pageVO); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#pageVO.businessId", level = CrmPermissionLevelEnum.READ) + public PageResult getContactPageByBusinessId(CrmContactPageReqVO pageVO) { + List contactBusinessList = contactBusinessService.getContactBusinessListByBusinessId(pageVO.getBusinessId()); + if (CollUtil.isEmpty(contactBusinessList)) { + return PageResult.empty(); + } + return contactMapper.selectPageByBusinessId(pageVO, convertSet(contactBusinessList, CrmContactBusinessDO::getContactId)); + } + + @Override + public Long getContactCountByCustomerId(Long customerId) { + return contactMapper.selectCount(CrmContactDO::getCustomerId, customerId); + } + + @Override + public List getContactListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return contactMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java new file mode 100644 index 0000000..39a0664 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.crm.service.contract; + +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; + +import javax.validation.Valid; + +/** + * 合同配置 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmContractConfigService { + + /** + * 获得合同配置 + * + * @return 合同配置 + */ + CrmContractConfigDO getContractConfig(); + + /** + * 保存合同配置 + * + * @param saveReqVO 更新信息 + */ + void saveContractConfig(@Valid CrmContractConfigSaveReqVO saveReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java new file mode 100644 index 0000000..2580cc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.crm.service.contract; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractConfigMapper; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Objects; + +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * 合同配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmContractConfigServiceImpl implements CrmContractConfigService { + + @Resource + private CrmContractConfigMapper contractConfigMapper; + + @Override + public CrmContractConfigDO getContractConfig() { + return contractConfigMapper.selectOne(); + } + + @Override + @LogRecord(type = CRM_CONTRACT_CONFIG_TYPE, subType = CRM_CONTRACT_CONFIG_SUB_TYPE, bizNo = "{{#configId}}", + success = CRM_CONTRACT_CONFIG_SUCCESS) + public void saveContractConfig(CrmContractConfigSaveReqVO saveReqVO) { + // 1. 存在,则进行更新 + CrmContractConfigDO dbConfig = getContractConfig(); + CrmContractConfigDO config = BeanUtils.toBean(saveReqVO, CrmContractConfigDO.class); + if (Objects.nonNull(dbConfig)) { + contractConfigMapper.updateById(config.setId(dbConfig.getId())); + // 记录操作日志上下文 + LogRecordContext.putVariable("isConfigUpdate", Boolean.TRUE); + LogRecordContext.putVariable("configId", config.getId()); + return; + } + + // 2. 不存在,则进行插入 + contractConfigMapper.insert(config); + // 记录操作日志上下文 + LogRecordContext.putVariable("isConfigUpdate", Boolean.FALSE); + LogRecordContext.putVariable("configId", config.getId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java new file mode 100644 index 0000000..f7a6867 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java @@ -0,0 +1,205 @@ +package cn.iocoder.yudao.module.crm.service.contract; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 合同 Service 接口 + * + * @author dhb52 + */ +public interface CrmContractService { + + /** + * 创建合同 + * + * @param createReqVO 创建信息 + * @param userId 用户编号 + * @return 编号 + */ + Long createContract(@Valid CrmContractSaveReqVO createReqVO, Long userId); + + /** + * 更新合同 + * + * @param updateReqVO 更新信息 + */ + void updateContract(@Valid CrmContractSaveReqVO updateReqVO); + + /** + * 删除合同 + * + * @param id 编号 + */ + void deleteContract(Long id); + + /** + * 合同转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferContract(CrmContractTransferReqVO reqVO, Long userId); + + /** + * 更新合同相关的更进信息 + * + * @param id 合同编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 + */ + void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); + + /** + * 发起合同审批流程 + * + * @param id 合同编号 + * @param userId 用户编号 + */ + void submitContract(Long id, Long userId); + + /** + * 更新合同流程审批结果 + * + * @param id 合同编号 + * @param bpmResult BPM 审批结果 + */ + void updateContractAuditStatus(Long id, Integer bpmResult); + + /** + * 获得合同 + * + * @param id 编号 + * @return 合同 + */ + CrmContractDO getContract(Long id); + + /** + * 校验合同是否合法 + * + * @param id 编号 + * @return 合同 + */ + CrmContractDO validateContract(Long id); + + /** + * 获得合同列表 + * + * @param ids 编号 + * @return 合同列表 + */ + List getContractList(Collection ids); + + /** + * 获得合同 Map + * + * @param ids 编号 + * @return 合同 Map + */ + default Map getContractMap(Collection ids) { + return convertMap(getContractList(ids), CrmContractDO::getId); + } + + /** + * 获得合同分页 + * + * 数据权限:基于 {@link CrmContractDO} 读取 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 合同分页 + */ + PageResult getContractPage(CrmContractPageReqVO pageReqVO, Long userId); + + /** + * 获得合同分页,基于指定客户 + * + * 数据权限:基于 {@link CrmCustomerDO} 读取 + * + * @param pageReqVO 分页查询 + * @return 合同分页 + */ + PageResult getContractPageByCustomerId(CrmContractPageReqVO pageReqVO); + + /** + * 获得合同分页,基于指定商机 + * + * 数据权限:基于 {@link CrmBusinessDO} 读取 + * + * @param pageReqVO 分页查询 + * @return 合同分页 + */ + PageResult getContractPageByBusinessId(CrmContractPageReqVO pageReqVO); + + /** + * 查询属于某个联系人的合同数量 + * + * @param contactId 联系人ID + * @return 合同 + */ + Long getContractCountByContactId(Long contactId); + + /** + * 获取关联客户的合同数量 + * + * @param customerId 客户编号 + * @return 数量 + */ + Long getContractCountByCustomerId(Long customerId); + + /** + * 根据商机编号,获取关联客户的合同数量 + * + * @param businessId 商机编号 + * @return 数量 + */ + Long getContractCountByBusinessId(Long businessId); + + /** + * 根据合同编号,获得合同的产品列表 + * + * @param contactId 合同编号 + * @return 产品列表 + */ + List getContractProductListByContractId(Long contactId); + + /** + * 获得待审核合同数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getAuditContractCount(Long userId); + + /** + * 获得即将到期(提醒)的合同数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getRemindContractCount(Long userId); + + /** + * 获得合同列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 合同列表 + */ + List getContractListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java new file mode 100644 index 0000000..4543f96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -0,0 +1,415 @@ +package cn.iocoder.yudao.module.crm.service.contract; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; +import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; +import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper; +import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmResultToAuditStatus; + +/** + * CRM 合同 Service 实现类 + * + * @author dhb52 + */ +@Service +@Validated +@Slf4j +public class CrmContractServiceImpl implements CrmContractService { + + /** + * BPM 合同审批流程标识 + */ + public static final String BPM_PROCESS_DEFINITION_KEY = "crm-contract-audit"; + + @Resource + private CrmContractMapper contractMapper; + @Resource + private CrmContractProductMapper contractProductMapper; + + @Resource + private CrmNoRedisDAO noRedisDAO; + + @Resource + private CrmPermissionService crmPermissionService; + @Resource + private CrmProductService productService; + @Resource + private CrmCustomerService customerService; + @Resource + private CrmBusinessService businessService; + @Resource + private CrmContactService contactService; + @Resource + private CrmContractConfigService contractConfigService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmReceivableService receivableService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private BpmProcessInstanceApi bpmProcessInstanceApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}", + success = CRM_CONTRACT_CREATE_SUCCESS) + public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) { + // 1.1 校验产品项的有效性 + List contractProducts = validateContractProducts(createReqVO.getProducts()); + // 1.2 校验关联字段 + validateRelationDataExists(createReqVO); + // 1.3 生成序号 + String no = noRedisDAO.generate(CrmNoRedisDAO.CONTRACT_NO_PREFIX); + if (contractMapper.selectByNo(no) != null) { + throw exception(CONTRACT_NO_EXISTS); + } + + // 2.1 插入合同 + CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setNo(no); + calculateTotalPrice(contract, contractProducts); + contractMapper.insert(contract); + // 2.2 插入合同关联商品 + if (CollUtil.isNotEmpty(contractProducts)) { + contractProducts.forEach(item -> item.setContractId(contract.getId())); + contractProductMapper.insertBatch(contractProducts); + } + + // 3. 创建数据权限 + crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(contract.getOwnerUserId()) + .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("contract", contract); + return contract.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CONTRACT_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateContract(CrmContractSaveReqVO updateReqVO) { + Assert.notNull(updateReqVO.getId(), "合同编号不能为空"); + updateReqVO.setOwnerUserId(null); // 不允许更新的字段 + // 1.1 校验存在 + CrmContractDO contract = validateContractExists(updateReqVO.getId()); + // 1.2 只有草稿、审批中,可以编辑; + if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), + CrmAuditStatusEnum.PROCESS.getStatus())) { + throw exception(CONTRACT_UPDATE_FAIL_NOT_DRAFT); + } + // 1.3 校验产品项的有效性 + List contractProducts = validateContractProducts(updateReqVO.getProducts()); + // 1.4 校验关联字段 + validateRelationDataExists(updateReqVO); + + // 2.1 更新合同 + CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class); + calculateTotalPrice(updateObj, contractProducts); + contractMapper.updateById(updateObj); + // 2.2 更新合同关联商品 + updateContractProduct(updateReqVO.getId(), contractProducts); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class)); + LogRecordContext.putVariable("contractName", contract.getName()); + } + + private void updateContractProduct(Long id, List newList) { + List oldList = contractProductMapper.selectListByContractId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setContractId(id)); + contractProductMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + contractProductMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + contractProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmContractProductDO::getId)); + } + } + + /** + * 校验关联数据是否存在 + * + * @param reqVO 请求 + */ + private void validateRelationDataExists(CrmContractSaveReqVO reqVO) { + // 1. 校验客户 + if (reqVO.getCustomerId() != null) { + customerService.validateCustomer(reqVO.getCustomerId()); + } + // 2. 校验负责人 + if (reqVO.getOwnerUserId() != null) { + adminUserApi.validateUser(reqVO.getOwnerUserId()); + } + // 3. 如果有关联商机,则需要校验存在 + if (reqVO.getBusinessId() != null) { + businessService.validateBusiness(reqVO.getBusinessId()); + } + // 4. 校验签约相关字段 + if (reqVO.getSignContactId() != null) { + contactService.validateContact(reqVO.getSignContactId()); + } + if (reqVO.getSignUserId() != null) { + adminUserApi.validateUser(reqVO.getSignUserId()); + } + } + + private List validateContractProducts(List list) { + // 1. 校验产品存在 + productService.validProductList(convertSet(list, CrmContractSaveReqVO.Product::getProductId)); + // 2. 转化为 CrmContractProductDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, CrmContractProductDO.class, + item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getContractPrice(), item.getCount())))); + } + + private void calculateTotalPrice(CrmContractDO contract, List contractProducts) { + contract.setTotalProductPrice(getSumValue(contractProducts, CrmContractProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(contract.getTotalProductPrice(), contract.getDiscountPercent()); + contract.setTotalPrice(contract.getTotalProductPrice().subtract(discountPrice)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CONTRACT_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteContract(Long id) { + // 1.1 校验存在 + CrmContractDO contract = validateContractExists(id); + // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除 + if (receivableService.getReceivableCountByContractId(contract.getId()) > 0) { + throw exception(CONTRACT_DELETE_FAIL); + } + + // 2.1 删除合同 + contractMapper.deleteById(id); + // 2.2 删除数据权限 + crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CONTRACT.getType(), id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("contractName", contract.getName()); + } + + private CrmContractDO validateContractExists(Long id) { + CrmContractDO contract = contractMapper.selectById(id); + if (contract == null) { + throw exception(CONTRACT_NOT_EXISTS); + } + return contract; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CONTRACT_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferContract(CrmContractTransferReqVO reqVO, Long userId) { + // 1. 校验合同是否存在 + CrmContractDO contract = validateContractExists(reqVO.getId()); + + // 2.1 数据权限转移 + crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + // 2.2 设置负责人 + contractMapper.updateById(new CrmContractDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + + // 3. 记录转移日志 + LogRecordContext.putVariable("contract", contract); + } + + @Override + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", + success = CRM_CONTRACT_FOLLOW_UP_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { + // 1. 校验存在 + CrmContractDO contract = validateContractExists(id); + + // 2. 更新联系人的跟进信息 + contractMapper.updateById(new CrmContractDO().setId(id).setContactLastTime(LocalDateTime.now())); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("contractName", contract.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CONTRACT_SUBMIT_SUCCESS) + public void submitContract(Long id, Long userId) { + // 1. 校验合同是否在审批 + CrmContractDO contract = validateContractExists(id); + if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) { + throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT); + } + + // 2. 创建合同审批流程实例 + String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() + .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id))); + + // 3. 更新合同工作流编号 + contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId) + .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); + + // 3. 记录日志 + LogRecordContext.putVariable("contractName", contract.getName()); + } + + @Override + public void updateContractAuditStatus(Long id, Integer bpmResult) { + // 1.1 校验合同是否存在 + CrmContractDO contract = validateContractExists(id); + // 1.2 只有审批中,可以更新审批结果 + if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { + log.error("[updateContractAuditStatus][contract({}) 不处于审批中,无法更新审批结果({})]", + contract.getId(), bpmResult); + throw exception(CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); + } + + // 2. 更新合同审批结果 + Integer auditStatus = convertBpmResultToAuditStatus(bpmResult); + contractMapper.updateById(new CrmContractDO().setId(id).setAuditStatus(auditStatus)); + } + + // ======================= 查询相关 ======================= + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmContractDO getContract(Long id) { + return contractMapper.selectById(id); + } + + @Override + public CrmContractDO validateContract(Long id) { + return validateContractExists(id); + } + + @Override + public List getContractList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return contractMapper.selectBatchIds(ids); + } + + @Override + public PageResult getContractPage(CrmContractPageReqVO pageReqVO, Long userId) { + // 1. 即将到期,需要查询合同配置 + CrmContractConfigDO config = null; + if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) { + config = contractConfigService.getContractConfig(); + if (config != null && Boolean.FALSE.equals(config.getNotifyEnabled())) { + config = null; + } + if (config == null) { + return PageResult.empty(); + } + } + // 2. 查询分页 + return contractMapper.selectPage(pageReqVO, userId, config); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) + public PageResult getContractPageByCustomerId(CrmContractPageReqVO pageReqVO) { + return contractMapper.selectPageByCustomerId(pageReqVO); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#pageReqVO.businessId", level = CrmPermissionLevelEnum.READ) + public PageResult getContractPageByBusinessId(CrmContractPageReqVO pageReqVO) { + return contractMapper.selectPageByBusinessId(pageReqVO); + } + + @Override + public Long getContractCountByContactId(Long contactId) { + return contractMapper.selectCountByContactId(contactId); + } + + @Override + public Long getContractCountByCustomerId(Long customerId) { + return contractMapper.selectCount(CrmContractDO::getCustomerId, customerId); + } + + @Override + public Long getContractCountByBusinessId(Long businessId) { + return contractMapper.selectCountByBusinessId(businessId); + } + + @Override + public List getContractProductListByContractId(Long contactId) { + return contractProductMapper.selectListByContractId(contactId); + } + + @Override + public Long getAuditContractCount(Long userId) { + return contractMapper.selectCountByAudit(userId); + } + + @Override + public Long getRemindContractCount(Long userId) { + CrmContractConfigDO config = contractConfigService.getContractConfig(); + if (config == null || Boolean.FALSE.equals(config.getNotifyEnabled())) { + return 0L; + } + return contractMapper.selectCountByRemind(userId, config); + } + + @Override + public List getContractListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return contractMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java new file mode 100644 index 0000000..b3c0735 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.crm.service.contract.listener; + +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 合同审批的结果的监听器实现类 + * + * @author HUIHUI + */ +@Component +public class CrmContractStatusListener extends BpmProcessInstanceStatusEventListener { + + @Resource + private CrmContractService contractService; + + @Override + public String getProcessDefinitionKey() { + return CrmContractServiceImpl.BPM_PROCESS_DEFINITION_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceStatusEvent event) { + contractService.updateContractAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java new file mode 100644 index 0000000..32d8856 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 客户限制配置 Service 接口 + * + * @author Wanwan + */ +public interface CrmCustomerLimitConfigService { + + /** + * 创建客户限制配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCustomerLimitConfig(@Valid CrmCustomerLimitConfigSaveReqVO createReqVO); + + /** + * 更新客户限制配置 + * + * @param updateReqVO 更新信息 + */ + void updateCustomerLimitConfig(@Valid CrmCustomerLimitConfigSaveReqVO updateReqVO); + + /** + * 删除客户限制配置 + * + * @param id 编号 + */ + void deleteCustomerLimitConfig(Long id); + + /** + * 获得客户限制配置 + * + * @param id 编号 + * @return 客户限制配置 + */ + CrmCustomerLimitConfigDO getCustomerLimitConfig(Long id); + + /** + * 获得客户限制配置分页 + * + * @param pageReqVO 分页查询 + * @return 客户限制配置分页 + */ + PageResult getCustomerLimitConfigPage(CrmCustomerLimitConfigPageReqVO pageReqVO); + + /** + * 查询用户对应的配置列表 + * + * @param type 类型 + * @param userId 用户类型 + */ + List getCustomerLimitConfigListByUserId(Integer type, Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java new file mode 100644 index 0000000..3add239 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java @@ -0,0 +1,124 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerLimitConfigMapper; +import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_LIMIT_CONFIG_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * 客户限制配置 Service 实现类 + * + * @author Wanwan + */ +@Service +@Validated +public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfigService { + + @Resource + private CrmCustomerLimitConfigMapper customerLimitConfigMapper; + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + @LogRecord(type = CRM_CUSTOMER_LIMIT_CONFIG_TYPE, subType = CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUB_TYPE, bizNo = "{{#limitId}}", + success = CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUCCESS) + public Long createCustomerLimitConfig(CrmCustomerLimitConfigSaveReqVO createReqVO) { + validateUserAndDept(createReqVO.getUserIds(), createReqVO.getDeptIds()); + // 插入 + CrmCustomerLimitConfigDO limitConfig = BeanUtils.toBean(createReqVO, CrmCustomerLimitConfigDO.class); + customerLimitConfigMapper.insert(limitConfig); + + // 记录操作日志上下文 + LogRecordContext.putVariable("limitType", CrmCustomerLimitConfigTypeEnum.getNameByType(limitConfig.getType())); + LogRecordContext.putVariable("limitId", limitConfig.getId()); + return limitConfig.getId(); + } + + @Override + @LogRecord(type = CRM_CUSTOMER_LIMIT_CONFIG_TYPE, subType = CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUCCESS) + public void updateCustomerLimitConfig(CrmCustomerLimitConfigSaveReqVO updateReqVO) { + // 校验存在 + CrmCustomerLimitConfigDO oldLimitConfig = validateCustomerLimitConfigExists(updateReqVO.getId()); + validateUserAndDept(updateReqVO.getUserIds(), updateReqVO.getDeptIds()); + // 更新 + CrmCustomerLimitConfigDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerLimitConfigDO.class); + customerLimitConfigMapper.updateById(updateObj); + + // 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldLimitConfig, CrmCustomerLimitConfigSaveReqVO.class)); + } + + @Override + @LogRecord(type = CRM_CUSTOMER_LIMIT_CONFIG_TYPE, subType = CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUCCESS) + public void deleteCustomerLimitConfig(Long id) { + // 校验存在 + CrmCustomerLimitConfigDO limitConfig = validateCustomerLimitConfigExists(id); + // 删除 + customerLimitConfigMapper.deleteById(id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("limitType", CrmCustomerLimitConfigTypeEnum.getNameByType(limitConfig.getType())); + } + + @Override + public CrmCustomerLimitConfigDO getCustomerLimitConfig(Long id) { + return customerLimitConfigMapper.selectById(id); + } + + @Override + public PageResult getCustomerLimitConfigPage(CrmCustomerLimitConfigPageReqVO pageReqVO) { + return customerLimitConfigMapper.selectPage(pageReqVO); + } + + private CrmCustomerLimitConfigDO validateCustomerLimitConfigExists(Long id) { + CrmCustomerLimitConfigDO limitConfigDO = customerLimitConfigMapper.selectById(id); + if (limitConfigDO == null) { + throw exception(CUSTOMER_LIMIT_CONFIG_NOT_EXISTS); + } + return limitConfigDO; + } + + /** + * 校验入参的用户和部门 + * + * @param userIds 用户 ids + * @param deptIds 部门 ids + */ + private void validateUserAndDept(Collection userIds, Collection deptIds) { + deptApi.validateDeptList(deptIds); + adminUserApi.validateUserList(userIds); + } + + @Override + public List getCustomerLimitConfigListByUserId(Integer type, Long userId) { + AdminUserRespDTO user = adminUserApi.getUser(userId); + Assert.notNull(user, "用户({})不存在", userId); + return customerLimitConfigMapper.selectListByTypeAndUserIdAndDeptId(type, userId, user.getDeptId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigService.java new file mode 100644 index 0000000..5a7c918 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigService.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; + +import javax.validation.Valid; + +/** + * 客户公海配置 Service 接口 + * + * @author Wanwan + */ +public interface CrmCustomerPoolConfigService { + + /** + * 获得客户公海配置 + * + * @return 客户公海配置 + */ + CrmCustomerPoolConfigDO getCustomerPoolConfig(); + + /** + * 保存客户公海配置 + * + * @param saveReqVO 更新信息 + */ + void saveCustomerPoolConfig(@Valid CrmCustomerPoolConfigSaveReqVO saveReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java new file mode 100644 index 0000000..b00315c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerPoolConfigMapper; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Objects; + +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * 客户公海配置 Service 实现类 + * + * @author Wanwan + */ +@Service +@Validated +public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigService { + + @Resource + private CrmCustomerPoolConfigMapper customerPoolConfigMapper; + + @Override + public CrmCustomerPoolConfigDO getCustomerPoolConfig() { + return customerPoolConfigMapper.selectOne(); + } + + @Override + @LogRecord(type = CRM_CUSTOMER_POOL_CONFIG_TYPE, subType = CRM_CUSTOMER_POOL_CONFIG_SUB_TYPE, bizNo = "{{#poolConfigId}}", + success = CRM_CUSTOMER_POOL_CONFIG_SUCCESS) + public void saveCustomerPoolConfig(CrmCustomerPoolConfigSaveReqVO saveReqVO) { + // 1. 存在,则进行更新 + CrmCustomerPoolConfigDO dbConfig = getCustomerPoolConfig(); + CrmCustomerPoolConfigDO poolConfig = BeanUtils.toBean(saveReqVO, CrmCustomerPoolConfigDO.class); + if (Objects.nonNull(dbConfig)) { + customerPoolConfigMapper.updateById(poolConfig.setId(dbConfig.getId())); + // 记录操作日志上下文 + LogRecordContext.putVariable("isPoolConfigUpdate", Boolean.TRUE); + LogRecordContext.putVariable("poolConfigId", poolConfig.getId()); + return; + } + + // 2. 不存在,则进行插入 + customerPoolConfigMapper.insert(poolConfig); + // 记录操作日志上下文 + LogRecordContext.putVariable("isPoolConfigUpdate", Boolean.FALSE); + LogRecordContext.putVariable("poolConfigId", poolConfig.getId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java new file mode 100644 index 0000000..3a133be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java @@ -0,0 +1,198 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 客户 Service 接口 + * + * @author Wanwan + */ +public interface CrmCustomerService { + + /** + * 创建客户 + * + * @param createReqVO 创建信息 + * @param userId 用户编号 + * @return 编号 + */ + Long createCustomer(@Valid CrmCustomerSaveReqVO createReqVO, Long userId); + + /** + * 更新客户 + * + * @param updateReqVO 更新信息 + */ + void updateCustomer(@Valid CrmCustomerSaveReqVO updateReqVO); + + /** + * 更新客户的跟进状态 + * + * @param id 编号 + * @param dealStatus 跟进状态 + */ + void updateCustomerDealStatus(Long id, Boolean dealStatus); + + /** + * 更新客户相关的跟进信息 + * + * @param id 编号 + * @param contactNextTime 下次联系时间 + * @param contactLastContent 最后联系内容 + */ + void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); + + /** + * 删除客户 + * + * @param id 编号 + */ + void deleteCustomer(Long id); + + /** + * 获得客户 + * + * @param id 编号 + * @return 客户 + */ + CrmCustomerDO getCustomer(Long id); + + /** + * 获得客户列表 + * + * @param ids 客户编号数组 + * @return 客户列表 + * @author ljlleo + */ + List getCustomerList(Collection ids); + + /** + * 获得客户 Map + * + * @param ids 客户编号数组 + * @return 客户 Map + */ + default Map getCustomerMap(Collection ids) { + return convertMap(getCustomerList(ids), CrmCustomerDO::getId); + } + + /** + * 获得客户分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 客户分页 + */ + PageResult getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId); + + /** + * 获得放入公海提醒的客户分页 + * + * @param pageVO 分页查询 + * @param userId 用户编号 + * @return 客户分页 + */ + PageResult getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId); + + /** + * 获得待进入公海的客户数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getPutPoolRemindCustomerCount(Long userId); + + /** + * 获得今日需联系客户数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getTodayContactCustomerCount(Long userId); + + /** + * 获得分配给我的客户数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getFollowCustomerCount(Long userId); + + /** + * 校验客户是否存在 + * + * @param id 编号 + */ + void validateCustomer(Long id); + + /** + * 客户转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId); + + /** + * 锁定/解锁客户 + * + * @param lockReqVO 更新信息 + * @param userId 用户编号 + */ + void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId); + + /** + * 创建客户 + * + * @param customerCreateReq 请求信息 + * @param userId 用户编号 + * @return 客户列表 + */ + Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId); + + /** + * 批量导入客户 + * + * @param importCustomers 导入客户列表 + * @param importReqVO 请求 + * @return 导入结果 + */ + CrmCustomerImportRespVO importCustomerList(List importCustomers, CrmCustomerImportReqVO importReqVO); + + // ==================== 公海相关操作 ==================== + + /** + * 客户放入公海 + * + * @param id 客户编号 + */ + void putCustomerPool(Long id); + + /** + * 领取公海客户 + * + * @param ids 要领取的客户编号数组 + * @param ownerUserId 负责人 + * @param isReceive 是/否领取;true - 领取;false - 分配 + */ + void receiveCustomer(List ids, Long ownerUserId, Boolean isReceive); + + /** + * 【系统】客户自动掉入公海 + * + * @return 掉入公海数量 + */ + int autoPutCustomerPool(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java new file mode 100644 index 0000000..66171c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -0,0 +1,663 @@ +package cn.iocoder.yudao.module.crm.service.customer; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT; +import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT; +import static java.util.Collections.singletonList; + +/** + * 客户 Service 实现类 + * + * @author Wanwan + */ +@Service +@Slf4j +@Validated +public class CrmCustomerServiceImpl implements CrmCustomerService { + + @Resource + private CrmCustomerMapper customerMapper; + + @Resource + private CrmPermissionService permissionService; + @Resource + private CrmCustomerLimitConfigService customerLimitConfigService; + @Resource + @Lazy + private CrmCustomerPoolConfigService customerPoolConfigService; + @Resource + @Lazy + private CrmContactService contactService; + @Resource + @Lazy + private CrmBusinessService businessService; + @Resource + @Lazy + private CrmContractService contractService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", + success = CRM_CUSTOMER_CREATE_SUCCESS) + public Long createCustomer(CrmCustomerSaveReqVO createReqVO, Long userId) { + createReqVO.setId(null); + // 1. 校验拥有客户是否到达上限 + validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1); + + // 2. 插入客户 + CrmCustomerDO customer = initCustomer(createReqVO, userId); + customerMapper.insert(customer); + + // 3. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("customer", customer); + return customer.getId(); + } + + /** + * 初始化客户的通用字段 + * + * @param customer 客户信息 + * @param ownerUserId 负责人编号 + * @return 客户信息 DO + */ + private static CrmCustomerDO initCustomer(Object customer, Long ownerUserId) { + return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(ownerUserId) + .setOwnerTime(LocalDateTime.now()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CUSTOMER_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) { + Assert.notNull(updateReqVO.getId(), "客户编号不能为空"); + updateReqVO.setOwnerUserId(null); // 更新的时候,要把 updateReqVO 负责人设置为空,避免修改 + // 1. 校验存在 + CrmCustomerDO oldCustomer = validateCustomerExists(updateReqVO.getId()); + + // 2. 更新客户 + CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class); + customerMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class)); + LogRecordContext.putVariable("customerName", oldCustomer.getName()); + } + + @Override + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateCustomerDealStatus(Long id, Boolean dealStatus) { + // 1.1 校验存在 + CrmCustomerDO customer = validateCustomerExists(id); + // 1.2 校验是否重复操作 + if (Objects.equals(customer.getDealStatus(), dealStatus)) { + throw exception(CUSTOMER_UPDATE_DEAL_STATUS_FAIL); + } + + // 2. 更新客户的成交状态 + customerMapper.updateById(new CrmCustomerDO().setId(id).setDealStatus(dealStatus)); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("customerName", customer.getName()); + LogRecordContext.putVariable("dealStatus", dealStatus); + } + + @Override + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", + success = CRM_CUSTOMER_FOLLOW_UP_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) + public void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { + // 1.1 校验存在 + CrmCustomerDO customer = validateCustomerExists(id); + + // 2. 更新客户的跟进信息 + customerMapper.updateById(new CrmCustomerDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) + .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("customerName", customer.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CUSTOMER_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteCustomer(Long id) { + // 1.1 校验存在 + CrmCustomerDO customer = validateCustomerExists(id); + // 1.2 检查引用 + validateCustomerReference(id); + + // 2. 删除客户 + customerMapper.deleteById(id); + // 3. 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("customerName", customer.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CUSTOMER_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { + // 1.1 校验客户是否存在 + CrmCustomerDO customer = validateCustomerExists(reqVO.getId()); + // 1.2 校验拥有客户是否到达上限 + validateCustomerExceedOwnerLimit(reqVO.getNewOwnerUserId(), 1); + // 2.1 数据权限转移 + permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + // 2.2 转移后重新设置负责人 + customerMapper.updateById(new CrmCustomerDO().setId(reqVO.getId()) + .setOwnerUserId(reqVO.getNewOwnerUserId()).setOwnerTime(LocalDateTime.now())); + + // 2.3 同时转移 + if (CollUtil.isNotEmpty(reqVO.getToBizTypes())) { + transfer(reqVO, userId); + } + + // 3. 记录转移日志 + LogRecordContext.putVariable("customer", customer); + } + + /** + * 转移客户时,需要额外有【联系人】【商机】【合同】 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + private void transfer(CrmCustomerTransferReqVO reqVO, Long userId) { + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTACT.getType())) { + List contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getId(), userId); + contactList.forEach(item -> { + contactService.transferContact(new CrmContactTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_BUSINESS.getType())) { + List businessList = businessService.getBusinessListByCustomerIdOwnerUserId(reqVO.getId(), userId); + businessList.forEach(item -> { + businessService.transferBusiness(new CrmBusinessTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTRACT.getType())) { + List contractList = contractService.getContractListByCustomerIdOwnerUserId(reqVO.getId(), userId); + contractList.forEach(item -> { + contractService.transferContract(new CrmContractTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + } + + @Override + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_LOCK_SUB_TYPE, bizNo = "{{#lockReqVO.id}}", + success = CRM_CUSTOMER_LOCK_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#lockReqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) { + // 1.1 校验当前客户是否存在 + CrmCustomerDO customer = validateCustomerExists(lockReqVO.getId()); + // 1.2 校验当前是否重复操作锁定/解锁状态 + if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) { + throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK); + } + // 1.3 校验锁定上限 + if (lockReqVO.getLockStatus()) { + validateCustomerExceedLockLimit(userId); + } + + // 2. 更新锁定状态 + customerMapper.updateById(BeanUtils.toBean(lockReqVO, CrmCustomerDO.class)); + + // 3. 记录操作日志上下文 + // tips: 因为这里使用的是老的状态所以记录时反着记录,也就是 lockStatus 为 true 那么就是解锁反之为锁定 + LogRecordContext.putVariable("customer", customer); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", + success = CRM_CUSTOMER_CREATE_SUCCESS) + public Long createCustomer(CrmCustomerCreateReqBO createReqBO, Long userId) { + // 1. 插入客户 + CrmCustomerDO customer = initCustomer(createReqBO, userId); + customerMapper.insert(customer); + + // 2. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("customer", customer); + return customer.getId(); + } + + @Override + public CrmCustomerImportRespVO importCustomerList(List importCustomers, + CrmCustomerImportReqVO importReqVO) { + // 校验非空 + importCustomers = filterList(importCustomers, item -> Objects.nonNull(item.getName())); + if (CollUtil.isEmpty(importCustomers)) { + throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY); + } + + // 逐条处理 + CrmCustomerImportRespVO respVO = CrmCustomerImportRespVO.builder().createCustomerNames(new ArrayList<>()) + .updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build(); + importCustomers.forEach(importCustomer -> { + // 校验,判断是否有不符合的原因 + try { + validateCustomerForCreate(importCustomer); + } catch (ServiceException ex) { + respVO.getFailureCustomerNames().put(importCustomer.getName(), ex.getMessage()); + return; + } + // 情况一:判断如果不存在,在进行插入 + CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName()); + if (existCustomer == null) { + // 1.1 插入客户信息 + CrmCustomerDO customer = initCustomer(importCustomer, importReqVO.getOwnerUserId()); + customerMapper.insert(customer); + respVO.getCreateCustomerNames().add(importCustomer.getName()); + // 1.2 创建数据权限 + if (importReqVO.getOwnerUserId() != null) { + permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setUserId(importReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + } + // 1.3 记录操作日志 + getSelf().importCustomerLog(customer, false); + return; + } + + // 情况二:如果存在,判断是否允许更新 + if (!importReqVO.getUpdateSupport()) { + respVO.getFailureCustomerNames().put(importCustomer.getName(), + StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName())); + return; + } + // 2.1 更新客户信息 + CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class) + .setId(existCustomer.getId()); + customerMapper.updateById(updateCustomer); + respVO.getUpdateCustomerNames().add(importCustomer.getName()); + // 2.2 记录操作日志 + getSelf().importCustomerLog(updateCustomer, true); + }); + return respVO; + } + + /** + * 记录导入客户时的操作日志 + * + * @param customer 客户信息 + * @param isUpdate 是否更新;true - 更新,false - 新增 + */ + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_IMPORT_SUB_TYPE, bizNo = "{{#customer.id}}", + success = CRM_CUSTOMER_IMPORT_SUCCESS) + public void importCustomerLog(CrmCustomerDO customer, boolean isUpdate) { + LogRecordContext.putVariable("customer", customer); + LogRecordContext.putVariable("isUpdate", isUpdate); + } + + // ==================== 公海相关操作 ==================== + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_POOL_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CUSTOMER_POOL_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void putCustomerPool(Long id) { + // 1. 校验存在 + CrmCustomerDO customer = customerMapper.selectById(id); + if (customer == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + // 1.2. 校验是否为公海数据 + validateCustomerOwnerExists(customer, true); + // 1.3. 校验客户是否锁定 + validateCustomerIsLocked(customer, true); + + // 2. 客户放入公海 + putCustomerPool(customer); + + // 记录操作日志上下文 + LogRecordContext.putVariable("customerName", customer.getName()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void receiveCustomer(List ids, Long ownerUserId, Boolean isReceive) { + // 1.1 校验存在 + List customers = customerMapper.selectBatchIds(ids); + if (customers.size() != ids.size()) { + throw exception(CUSTOMER_NOT_EXISTS); + } + // 1.2 校验负责人是否存在 + adminUserApi.validateUserList(singletonList(ownerUserId)); + // 1.3 校验状态 + customers.forEach(customer -> { + // 校验是否已有负责人 + validateCustomerOwnerExists(customer, false); + // 校验是否锁定 + validateCustomerIsLocked(customer, false); + // 校验成交状态 + validateCustomerDeal(customer); + }); + // 1.4 校验负责人是否到达上限 + validateCustomerExceedOwnerLimit(ownerUserId, customers.size()); + + // 2. 领取公海数据 + List updateCustomers = new ArrayList<>(); + List createPermissions = new ArrayList<>(); + customers.forEach(customer -> { + // 2.1. 设置负责人 + updateCustomers.add(new CrmCustomerDO().setId(customer.getId()) + .setOwnerUserId(ownerUserId).setOwnerTime(LocalDateTime.now())); + // 2.2. 创建负责人数据权限 + createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + }); + // 2.2 更新客户负责人 + customerMapper.updateBatch(updateCustomers); + // 2.3 创建负责人数据权限 + permissionService.createPermissionBatch(createPermissions); + // TODO @芋艿:要不要处理关联的联系人??? + + // 3. 记录操作日志 + AdminUserRespDTO user = null; + if (!isReceive) { + user = adminUserApi.getUser(ownerUserId); + } + for (CrmCustomerDO customer : customers) { + getSelf().receiveCustomerLog(customer, user == null ? null : user.getNickname()); + } + } + + @Override + public int autoPutCustomerPool() { + CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); + if (poolConfig == null || !poolConfig.getEnabled()) { + return 0; + } + // 1. 获得需要放到的客户列表 + List customerList = customerMapper.selectListByAutoPool(poolConfig); + // 2. 逐个放入公海 + int count = 0; + for (CrmCustomerDO customer : customerList) { + try { + getSelf().putCustomerPool(customer); + count++; + } catch (Throwable e) { + log.error("[autoPutCustomerPool][客户({}) 放入公海异常]", customer.getId(), e); + } + } + return count; + } + + @Transactional(rollbackFor = Exception.class) // 需要 protected 修饰,因为需要在事务中调用 + protected void putCustomerPool(CrmCustomerDO customer) { + // 1. 设置负责人为 NULL + int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null); + if (updateOwnerUserIncr == 0) { + throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL); + } + + // 2. 联系人的负责人,也要设置为 null。因为:因为领取后,负责人也要关联过来,这块和 receiveCustomer 是对应的 + contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); + + // 3. 删除负责人数据权限 + // 注意:需要放在 contactService 后面,不然【客户】数据权限已经被删除,无法操作! + permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), + CrmPermissionLevelEnum.OWNER.getLevel()); + } + + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_RECEIVE_SUB_TYPE, bizNo = "{{#customer.id}}", + success = CRM_CUSTOMER_RECEIVE_SUCCESS) + public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) { + // 记录操作日志上下文 + LogRecordContext.putVariable("customer", customer); + LogRecordContext.putVariable("ownerUserName", ownerUserName); + } + + //======================= 查询相关 ======================= + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmCustomerDO getCustomer(Long id) { + return customerMapper.selectById(id); + } + + @Override + public List getCustomerList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return customerMapper.selectBatchIds(ids); + } + + @Override + public PageResult getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) { + return customerMapper.selectPage(pageReqVO, userId); + } + + @Override + public PageResult getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId) { + CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); + if (ObjUtil.isNull(poolConfig) + || Boolean.FALSE.equals(poolConfig.getEnabled()) + || Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) { + return PageResult.empty(); + } + return customerMapper.selectPutPoolRemindCustomerPage(pageVO, poolConfig, userId); + } + + @Override + public Long getPutPoolRemindCustomerCount(Long userId) { + CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); + if (ObjUtil.isNull(poolConfig) + || Boolean.FALSE.equals(poolConfig.getEnabled()) + || Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) { + return 0L; + } + CrmCustomerPageReqVO pageVO = new CrmCustomerPageReqVO() + .setPool(null) + .setContactStatus(CrmCustomerPageReqVO.CONTACT_TODAY) + .setSceneType(CrmSceneTypeEnum.OWNER.getType()); + return customerMapper.selectPutPoolRemindCustomerCount(pageVO, poolConfig, userId); + } + + @Override + public Long getTodayContactCustomerCount(Long userId) { + return customerMapper.selectCountByTodayContact(userId); + } + + @Override + public Long getFollowCustomerCount(Long userId) { + return customerMapper.selectCountByFollow(userId); + } + + // ======================= 校验相关 ======================= + + private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) { + // 校验客户名称不能为空 + if (StrUtil.isEmptyIfStr(importCustomer.getName())) { + throw exception(CUSTOMER_CREATE_NAME_NOT_NULL); + } + } + + /** + * 校验客户是否被引用 + * + * @param id 客户编号 + */ + private void validateCustomerReference(Long id) { + if (contactService.getContactCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTACT.getName()); + } + if (businessService.getBusinessCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_BUSINESS.getName()); + } + if (contractService.getContractCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTRACT.getName()); + } + } + + /** + * 校验客户是否存在 + * + * @param id 客户 id + */ + @Override + public void validateCustomer(Long id) { + validateCustomerExists(id); + } + + private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) { + if (customer == null) { // 防御一下 + throw exception(CUSTOMER_NOT_EXISTS); + } + // 校验是否为公海数据 + if (pool && customer.getOwnerUserId() == null) { + throw exception(CUSTOMER_IN_POOL, customer.getName()); + } + // 负责人已存在 + if (!pool && customer.getOwnerUserId() != null) { + throw exception(CUSTOMER_OWNER_EXISTS, customer.getName()); + } + } + + private CrmCustomerDO validateCustomerExists(Long id) { + CrmCustomerDO customerDO = customerMapper.selectById(id); + if (customerDO == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + return customerDO; + } + + private void validateCustomerIsLocked(CrmCustomerDO customer, Boolean pool) { + if (customer.getLockStatus()) { + throw exception(pool ? CUSTOMER_LOCKED_PUT_POOL_FAIL : CUSTOMER_LOCKED, customer.getName()); + } + } + + private void validateCustomerDeal(CrmCustomerDO customer) { + if (customer.getDealStatus()) { + throw exception(CUSTOMER_ALREADY_DEAL); + } + } + + /** + * 校验用户拥有的客户数量,是否到达上限 + * + * @param userId 用户编号 + * @param newCount 附加数量 + */ + private void validateCustomerExceedOwnerLimit(Long userId, int newCount) { + List limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId( + CUSTOMER_OWNER_LIMIT.getType(), userId); + if (CollUtil.isEmpty(limitConfigs)) { + return; + } + Long ownerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(null, userId); + Long dealOwnerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(true, userId); + limitConfigs.forEach(limitConfig -> { + long nowCount = limitConfig.getDealCountEnabled() ? ownerCount : ownerCount - dealOwnerCount; + if (nowCount + newCount > limitConfig.getMaxCount()) { + throw exception(CUSTOMER_OWNER_EXCEED_LIMIT); + } + }); + } + + /** + * 校验用户锁定的客户数量,是否到达上限 + * + * @param userId 用户编号 + */ + private void validateCustomerExceedLockLimit(Long userId) { + List limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId( + CUSTOMER_LOCK_LIMIT.getType(), userId); + if (CollUtil.isEmpty(limitConfigs)) { + return; + } + Long lockCount = customerMapper.selectCountByLockStatusAndOwnerUserId(true, userId); + Integer maxCount = CollectionUtils.getMaxValue(limitConfigs, CrmCustomerLimitConfigDO::getMaxCount); + assert maxCount != null; + if (lockCount >= maxCount) { + throw exception(CUSTOMER_LOCK_EXCEED_LIMIT); + } + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private CrmCustomerServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java new file mode 100644 index 0000000..87a6b33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java @@ -0,0 +1,121 @@ +package cn.iocoder.yudao.module.crm.service.customer.bo; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 客户创建 Create Req BO + * + * @author HUIHUI + */ +@Data +public class CrmCustomerCreateReqBO { + + /** + * 客户名称 + */ + @NotEmpty(message = "客户名称不能为空") + private String name; + /** + * 跟进状态 + */ + private Boolean followUpStatus; + /** + * 锁定状态 + */ + private Boolean lockStatus; + /** + * 成交状态 + */ + private Boolean dealStatus; + /** + * 所属行业 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} + */ + private Integer industryId; + /** + * 客户等级 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} + */ + private Integer level; + /** + * 客户来源 + * + * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} + */ + private Integer source; + + /** + * 手机 + */ + @Mobile + private String mobile; + /** + * 电话 + */ + @Telephone + private String telephone; + /** + * QQ + */ + private String qq; + /** + * wechat + */ + private String wechat; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + private String email; + + /** + * 客户描述 + */ + @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") + private String description; + /** + * 备注 + */ + private String remark; + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + /** + * 所在地 + * + * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 + */ + private Integer areaId; + /** + * 详细地址 + */ + private String detailAddress; + + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 最后跟进内容 + */ + private String contactLastContent; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java new file mode 100644 index 0000000..ec6c9aa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.crm.service.followup; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 跟进记录 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmFollowUpRecordService { + + /** + * 创建跟进记录 (数据权限基于 bizType、 bizId) + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFollowUpRecord(@Valid CrmFollowUpRecordSaveReqVO createReqVO); + + /** + * 创建更进 + * + * @param list 请求 + */ + void createFollowUpRecordBatch(List list); + + /** + * 删除跟进记录 (数据权限基于 bizType、 bizId) + * + * @param id 编号 + * @param userId 用户编号 + */ + void deleteFollowUpRecord(Long id, Long userId); + + /** + * 删除跟进 + * + * @param bizType 模块类型 + * @param bizId 模块数据编号 + */ + void deleteFollowUpRecordByBiz(Integer bizType, Long bizId); + + /** + * 获得跟进记录 + * + * @param id 编号 + * @return 跟进记录 + */ + CrmFollowUpRecordDO getFollowUpRecord(Long id); + + /** + * 获得跟进记录分页 (数据权限基于 bizType、 bizId) + * + * @param pageReqVO 分页查询 + * @return 跟进记录分页 + */ + PageResult getFollowUpRecordPage(CrmFollowUpRecordPageReqVO pageReqVO); + + /** + * 获取跟进记录 + * + * @param bizType 模块类型 + * @param bizIds 模块数据编号 + * @return 跟进列表 + */ + List getFollowUpRecordByBiz(Integer bizType, Collection bizIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java new file mode 100644 index 0000000..0bc4480 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.crm.service.followup; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.dal.mysql.followup.CrmFollowUpRecordMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import javax.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS; + +/** + * 跟进记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { + + @Resource + private CrmFollowUpRecordMapper crmFollowUpRecordMapper; + + @Resource + @Lazy + private CrmPermissionService permissionService; + @Resource + @Lazy + private CrmBusinessService businessService; + @Resource + @Lazy + private CrmClueService clueService; + @Resource + @Lazy + private CrmContactService contactService; + @Resource + @Lazy + private CrmContractService contractService; + @Resource + @Lazy + private CrmCustomerService customerService; + + @Override + @CrmPermission(bizTypeValue = "#createReqVO.bizType", bizId = "#createReqVO.bizId", level = CrmPermissionLevelEnum.WRITE) + public Long createFollowUpRecord(CrmFollowUpRecordSaveReqVO createReqVO) { + // 1. 创建更进记录 + CrmFollowUpRecordDO record = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class); + crmFollowUpRecordMapper.insert(record); + + // 2. 更新 bizId 对应的记录 + if (ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), record.getBizType())) { // 更新客户跟进信息 + customerService.updateCustomerFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); + } + if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), record.getBizType())) { // 更新商机跟进信息 + businessService.updateBusinessFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); + } + if (ObjUtil.equal(CrmBizTypeEnum.CRM_CLUE.getType(), record.getBizType())) { // 更新线索跟进信息 + clueService.updateClueFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); + } + if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTACT.getType(), record.getBizType())) { // 更新联系人跟进信息 + contactService.updateContactFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); + } + if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTRACT.getType(), record.getBizType())) { // 更新合同跟进信息 + contractService.updateContractFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); + } + + // 3.1 更新 contactIds 对应的记录,只更新 nextTime + if (CollUtil.isNotEmpty(createReqVO.getContactIds())) { + contactService.updateContactContactNextTime(createReqVO.getContactIds(), createReqVO.getNextTime()); + } + // 3.2 需要更新 businessIds 对应的记录,只更新 nextTime + if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) { + businessService.updateBusinessContactNextTime(createReqVO.getBusinessIds(), createReqVO.getNextTime()); + } + return record.getId(); + } + + @Override + public void createFollowUpRecordBatch(List list) { + if (CollUtil.isEmpty(list)) { + return; + } + crmFollowUpRecordMapper.insertBatch(BeanUtils.toBean(list, CrmFollowUpRecordDO.class)); + } + + @Override + public void deleteFollowUpRecord(Long id, Long userId) { + // 校验存在 + CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id); + // 校验权限 + if (!permissionService.hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(), userId, CrmPermissionLevelEnum.OWNER)) { + throw exception(FOLLOW_UP_RECORD_DELETE_DENIED); + } + + // 删除 + crmFollowUpRecordMapper.deleteById(id); + } + + @Override + public void deleteFollowUpRecordByBiz(Integer bizType, Long bizId) { + crmFollowUpRecordMapper.deleteByBiz(bizType, bizId); + } + + private CrmFollowUpRecordDO validateFollowUpRecordExists(Long id) { + CrmFollowUpRecordDO followUpRecord = crmFollowUpRecordMapper.selectById(id); + if (followUpRecord == null) { + throw exception(FOLLOW_UP_RECORD_NOT_EXISTS); + } + return followUpRecord; + } + + @Override + public CrmFollowUpRecordDO getFollowUpRecord(Long id) { + return crmFollowUpRecordMapper.selectById(id); + } + + @Override + @CrmPermission(bizTypeValue = "#pageReqVO.bizType", bizId = "#pageReqVO.bizId", level = CrmPermissionLevelEnum.READ) + public PageResult getFollowUpRecordPage(CrmFollowUpRecordPageReqVO pageReqVO) { + return crmFollowUpRecordMapper.selectPage(pageReqVO); + } + + @Override + public List getFollowUpRecordByBiz(Integer bizType, Collection bizIds) { + return crmFollowUpRecordMapper.selectListByBiz(bizType, bizIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/bo/CrmFollowUpCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/bo/CrmFollowUpCreateReqBO.java new file mode 100644 index 0000000..280bcad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/bo/CrmFollowUpCreateReqBO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.crm.service.followup.bo; + +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 跟进信息 Create Req BO + * + * @author HUIHUI + */ +@Data +public class CrmFollowUpCreateReqBO { + + /** + * 数据类型 + * + * 枚举 {@link CrmBizTypeEnum} + */ + @NotNull(message = "数据类型不能为空") + private Integer bizType; + /** + * 数据编号 + * + * 关联 {@link CrmBizTypeEnum} 对应模块 DO 的 id 字段 + */ + @NotNull(message = "数据编号不能为空") + private Long bizId; + + /** + * 跟进类型 + * + * 关联 {@link DictTypeConstants#CRM_FOLLOW_UP_TYPE} 字典 + */ + @NotNull(message = "跟进类型不能为空") + private Integer type; + /** + * 跟进内容 + */ + @NotEmpty(message = "跟进内容不能为空") + private String content; + /** + * 下次联系时间 + */ + @NotNull(message = "下次联系时间不能为空") + private LocalDateTime nextTime; + + /** + * 图片 + */ + private List picUrls; + /** + * 附件 + */ + private List fileUrls; + + /** + * 关联的商机编号数组 + * + * 关联 {@link CrmBusinessDO#getId()} + */ + private List businessIds; + + /** + * 关联的联系人编号数组 + * + * 关联 {@link CrmContactDO#getId()} + */ + private List contactIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java new file mode 100644 index 0000000..e5b8444 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.module.crm.service.permission; + + +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * crm 数据权限 Service 接口 + * + * @author HUIHUI + */ +public interface CrmPermissionService { + + /** + * 创建数据权限 + * + * @param reqVO 创建信息 + * @param userId 用户编号 + */ + void createPermission(CrmPermissionSaveReqVO reqVO, Long userId); + + /** + * 创建数据权限 + * + * @param createReqBO 创建信息 + * @return 编号 + */ + Long createPermission(@Valid CrmPermissionCreateReqBO createReqBO); + + /** + * 创建数据权限 + * + * @param createReqBOs 创建信息 + */ + void createPermissionBatch(@Valid List createReqBOs); + + /** + * 更新数据权限 + * + * @param updateReqVO 更新信息 + */ + void updatePermission(CrmPermissionUpdateReqVO updateReqVO); + + /** + * 数据权限转移 + * + * @param crmPermissionTransferReqBO 数据权限转移请求 + */ + void transferPermission(@Valid CrmPermissionTransferReqBO crmPermissionTransferReqBO); + + /** + * 删除数据权限 + * + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} + * @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() + * @param level 数据权限级别,关联 {@link CrmPermissionLevelEnum} + */ + void deletePermission(Integer bizType, Long bizId, Integer level); + + /** + * 删除数据权限 + * + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} + * @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() + */ + void deletePermission(Integer bizType, Long bizId); + + /** + * 批量删除数据权限 + * + * @param ids 权限编号 + * @param userId 用户编号 + */ + void deletePermissionBatch(Collection ids, Long userId); + + /** + * 删除指定用户数据权限 + * + * @param id 权限编号 + * @param userId 用户编号 + */ + void deleteSelfPermission(Long id, Long userId); + + /** + * 获取数据权限列表,通过 数据类型 x 某个数据 + * + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} + * @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() + * @return Crm 数据权限列表 + */ + List getPermissionListByBiz(Integer bizType, Long bizId); + + /** + * 获取数据权限列表,通过 数据类型 x 某个数据 + * + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} + * @param bizIds 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() + * @return Crm 数据权限列表 + */ + List getPermissionListByBiz(Integer bizType, Collection bizIds); + + /** + * 获取用户参与的模块数据列表 + * + * @param bizType 模块类型 + * @param userId 用户编号 + * @return 模块数据列表 + */ + List getPermissionListByBizTypeAndUserId(Integer bizType, Long userId); + + /** + * 校验是否有指定数据的操作权限 + * + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum} + * @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId() + * @param userId 用户编号 + * @param level 权限级别 + * @return 是否有权限 + */ + boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java new file mode 100644 index 0000000..22773a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java @@ -0,0 +1,335 @@ +package cn.iocoder.yudao.module.crm.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.dal.mysql.permission.CrmPermissionMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isOwner; + +/** + * CRM 数据权限 Service 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class CrmPermissionServiceImpl implements CrmPermissionService { + + @Resource + private CrmPermissionMapper permissionMapper; + @Resource + @Lazy // 解决依赖循环 + private CrmContactService contactService; + @Resource + @Lazy // 解决依赖循环 + private CrmBusinessService businessService; + @Resource + @Lazy // 解决依赖循环 + private CrmContractService contractService; + @Resource + private AdminUserApi adminUserApi; + + + @Override + @Transactional(rollbackFor = Exception.class) + @CrmPermission(bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) + public void createPermission(CrmPermissionSaveReqVO reqVO, Long userId) { + // 1. 创建数据权限 + createPermission0(BeanUtils.toBean(reqVO, CrmPermissionCreateReqBO.class)); + + // 2. 处理【同时添加至】的权限 + if (CollUtil.isEmpty(reqVO.getToBizTypes())) { + return; + } + List createPermissions = new ArrayList<>(); + buildContactPermissions(reqVO, userId, createPermissions); + buildBusinessPermissions(reqVO, userId, createPermissions); + buildContractPermissions(reqVO, userId, createPermissions); + if (CollUtil.isEmpty(createPermissions)) { + return; + } + createPermissionBatch(createPermissions); + } + + /** + * 处理同时添加至联系人 + * + * @param reqVO 请求 + * @param userId 操作人 + * @param createPermissions 待添加权限列表 + */ + private void buildContactPermissions(CrmPermissionSaveReqVO reqVO, Long userId, List createPermissions) { + // 1. 校验是否被同时添加 + Integer type = CrmBizTypeEnum.CRM_CONTACT.getType(); + if (!reqVO.getToBizTypes().contains(type)) { + return; + } + // 2. 添加数据权限 + List contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + contactList.forEach(item -> createBizTypePermissions(reqVO, type, item.getId(), item.getName(), createPermissions)); + } + + /** + * 处理同时添加至商机 + * + * @param reqVO 请求 + * @param userId 操作人 + * @param createPermissions 待添加权限列表 + */ + private void buildBusinessPermissions(CrmPermissionSaveReqVO reqVO, Long userId, List createPermissions) { + // 1. 校验是否被同时添加 + Integer type = CrmBizTypeEnum.CRM_BUSINESS.getType(); + if (!reqVO.getToBizTypes().contains(type)) { + return; + } + // 2. 添加数据权限 + List businessList = businessService.getBusinessListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + businessList.forEach(item -> createBizTypePermissions(reqVO, type, item.getId(), item.getName(), createPermissions)); + } + + /** + * 处理同时添加至合同 + * + * @param reqVO 请求 + * @param userId 操作人 + * @param createPermissions 待添加权限列表 + */ + private void buildContractPermissions(CrmPermissionSaveReqVO reqVO, Long userId, List createPermissions) { + // 1. 校验是否被同时添加 + Integer type = CrmBizTypeEnum.CRM_CONTRACT.getType(); + if (!reqVO.getToBizTypes().contains(type)) { + return; + } + // 2. 添加数据权限 + List contractList = contractService.getContractListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + contractList.forEach(item -> createBizTypePermissions(reqVO, type, item.getId(), item.getName(), createPermissions)); + } + + private void createBizTypePermissions(CrmPermissionSaveReqVO reqVO, Integer type, Long bizId, String name, + List createPermissions) { + AdminUserRespDTO user = adminUserApi.getUser(reqVO.getUserId()); + // 1. 需要考虑,被添加人,是不是应该有对应的权限了; + CrmPermissionDO permission = hasAnyPermission(type, bizId, reqVO.getUserId()); + if (ObjUtil.isNotNull(permission)) { + throw exception(CRM_PERMISSION_CREATE_FAIL_EXISTS, user.getNickname(), CrmBizTypeEnum.getNameByType(type), + name, CrmPermissionLevelEnum.getNameByLevel(permission.getLevel())); + } + // 2. 添加数据权限 + createPermissions.add(new CrmPermissionCreateReqBO().setBizType(type) + .setBizId(bizId).setUserId(reqVO.getUserId()).setLevel(reqVO.getLevel())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createPermission(CrmPermissionCreateReqBO createReqBO) { + return createPermission0(createReqBO); + } + + private Long createPermission0(CrmPermissionCreateReqBO createReqBO) { + validatePermissionNotExists(Collections.singletonList(createReqBO)); + // 1. 校验用户是否存在 + adminUserApi.validateUserList(Collections.singletonList(createReqBO.getUserId())); + // 2. 插入权限 + CrmPermissionDO permission = BeanUtils.toBean(createReqBO, CrmPermissionDO.class); + permissionMapper.insert(permission); + return permission.getId(); + } + + @Override + public void createPermissionBatch(List createReqBOs) { + validatePermissionNotExists(createReqBOs); + // 1. 校验用户是否存在 + adminUserApi.validateUserList(convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId)); + + // 2. 创建 + List permissions = BeanUtils.toBean(createReqBOs, CrmPermissionDO.class); + permissionMapper.insertBatch(permissions); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePermission(CrmPermissionUpdateReqVO updateReqVO) { + // 1. 校验存在 + validatePermissionExists(updateReqVO.getIds()); + // 2. 更新 + List updateList = CollectionUtils.convertList(updateReqVO.getIds(), + id -> new CrmPermissionDO().setId(id).setLevel(updateReqVO.getLevel())); + permissionMapper.updateBatch(updateList); + } + + private void validatePermissionExists(Collection ids) { + List permissionList = permissionMapper.selectBatchIds(ids); + if (ObjUtil.notEqual(permissionList.size(), ids.size())) { + throw exception(CRM_PERMISSION_NOT_EXISTS); + } + } + + private void validatePermissionNotExists(Collection createReqBOs) { + Set bizTypes = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizType); + Set bizIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizId); + Set userIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId); + Long count = permissionMapper.selectListByBiz(bizTypes, bizIds, userIds); + if (count > 0) { + throw exception(CRM_PERMISSION_CREATE_FAIL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void transferPermission(CrmPermissionTransferReqBO transferReqBO) { + // 1. 校验数据权限:是否是负责人,只有负责人才可以转移 + CrmPermissionDO oldPermission = permissionMapper.selectByBizTypeAndBizIdByUserId( + transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId()); + String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType()); + if (oldPermission == null // 不是拥有者,并且不是超管 + || (!isOwner(oldPermission.getLevel()) && !CrmPermissionUtils.isCrmAdmin())) { + throw exception(CRM_PERMISSION_DENIED, bizTypeName); + } + // 1.1 校验转移对象是否已经是该负责人 + if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) { + throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, bizTypeName); + } + // 1.2 校验新负责人是否存在 + adminUserApi.validateUserList(Collections.singletonList(transferReqBO.getNewOwnerUserId())); + + // 2. 修改新负责人的权限 + List permissions = permissionMapper.selectByBizTypeAndBizId( + transferReqBO.getBizType(), transferReqBO.getBizId()); // 获得所有数据权限 + CrmPermissionDO permission = CollUtil.findOne(permissions, + item -> ObjUtil.equal(item.getUserId(), transferReqBO.getNewOwnerUserId())); + if (permission == null) { + permissionMapper.insert(new CrmPermissionDO().setBizType(transferReqBO.getBizType()) + .setBizId(transferReqBO.getBizId()).setUserId(transferReqBO.getNewOwnerUserId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + } else { + permissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + } + + // 3. 修改老负责人的权限 + if (transferReqBO.getOldOwnerPermissionLevel() != null) { + permissionMapper.updateById(new CrmPermissionDO().setId(oldPermission.getId()) + .setLevel(transferReqBO.getOldOwnerPermissionLevel())); + } else { + permissionMapper.deleteById(oldPermission.getId()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deletePermission(Integer bizType, Long bizId, Integer level) { + // 校验存在 + List permissions = permissionMapper.selectListByBizTypeAndBizIdAndLevel( + bizType, bizId, level); + if (CollUtil.isEmpty(permissions)) { + throw exception(CRM_PERMISSION_NOT_EXISTS); + } + + // 删除数据权限 + permissionMapper.deleteBatchIds(convertSet(permissions, CrmPermissionDO::getId)); + } + + @Override + public void deletePermission(Integer bizType, Long bizId) { + int deletedCount = permissionMapper.deletePermission(bizType, bizId); + if (deletedCount == 0) { + throw exception(CRM_PERMISSION_NOT_EXISTS); + } + } + + @Override + public void deletePermissionBatch(Collection ids, Long userId) { + List permissions = permissionMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(permissions)) { + throw exception(CRM_PERMISSION_NOT_EXISTS); + } + // 校验:数据权限的模块数据编号是一致的不可能存在两个 + if (convertSet(permissions, CrmPermissionDO::getBizId).size() > 1) { + throw exception(CRM_PERMISSION_DELETE_FAIL); + } + // 校验操作人是否为负责人 + CrmPermissionDO permission = permissionMapper.selectByBizAndUserId(permissions.get(0).getBizType(), permissions.get(0).getBizId(), userId); + if (permission == null) { + throw exception(CRM_PERMISSION_DELETE_DENIED); + } + if (!CrmPermissionLevelEnum.isOwner(permission.getLevel())) { + throw exception(CRM_PERMISSION_DELETE_DENIED); + } + + // 删除数据权限 + permissionMapper.deleteBatchIds(ids); + } + + @Override + public void deleteSelfPermission(Long id, Long userId) { + // 校验数据存在且是自己 + CrmPermissionDO permission = permissionMapper.selectByIdAndUserId(id, userId); + if (permission == null) { + throw exception(CRM_PERMISSION_NOT_EXISTS); + } + // 校验是否是负责人 + if (CrmPermissionLevelEnum.isOwner(permission.getLevel())) { + throw exception(CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER); + } + + // 删除 + permissionMapper.deleteById(id); + } + + @Override + public List getPermissionListByBiz(Integer bizType, Long bizId) { + return permissionMapper.selectByBizTypeAndBizId(bizType, bizId); + } + + @Override + public List getPermissionListByBiz(Integer bizType, Collection bizIds) { + return permissionMapper.selectByBizTypeAndBizIds(bizType, bizIds); + } + + @Override + public List getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) { + return permissionMapper.selectListByBizTypeAndUserId(bizType, userId); + } + + @Override + public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level) { + List permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId); + return anyMatch(permissionList, permission -> + ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), level.getLevel())); + } + + public CrmPermissionDO hasAnyPermission(Integer bizType, Long bizId, Long userId) { + List permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId); + return findFirst(permissionList, permission -> ObjUtil.equal(permission.getUserId(), userId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java new file mode 100644 index 0000000..ce13a2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.crm.service.permission.bo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * crm 数据权限 Create Req BO + * + * @author HUIHUI + */ +@Data +public class CrmPermissionCreateReqBO { + + /** + * 当前登录用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + + /** + * Crm 类型 + */ + @NotNull(message = "Crm 类型不能为空") + @InEnum(CrmBizTypeEnum.class) + private Integer bizType; + /** + * 数据编号 + */ + @NotNull(message = "Crm 数据编号不能为空") + private Long bizId; + + /** + * 权限级别 + */ + @NotNull(message = "权限级别不能为空") + @InEnum(CrmPermissionLevelEnum.class) + private Integer level; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java new file mode 100644 index 0000000..fb7813a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.crm.service.permission.bo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +/** + * 数据权限转移 Request BO + * + * @author HUIHUI + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CrmPermissionTransferReqBO { + + /** + * 当前登录用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + + /** + * CRM 类型 + */ + @NotNull(message = "Crm 类型不能为空") + @InEnum(CrmBizTypeEnum.class) + private Integer bizType; + /** + * 数据编号 + */ + @NotNull(message = "CRM 数据编号不能为空") + private Long bizId; + + /** + * 新负责人的用户编号 + */ + @NotNull(message = "新负责人的用户编号不能为空") + private Long newOwnerUserId; + + /** + * 老负责人加入团队后的权限级别。如果 null 说明移除 + * + * 关联 {@link CrmPermissionLevelEnum} + */ + private Integer oldOwnerPermissionLevel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java new file mode 100644 index 0000000..c82f97c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.crm.service.product; + +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 产品分类 Service 接口 + * + * @author ZanGe丶 + */ +public interface CrmProductCategoryService { + + /** + * 创建产品分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductCategory(@Valid CrmProductCategoryCreateReqVO createReqVO); + + /** + * 更新产品分类 + * + * @param updateReqVO 更新信息 + */ + void updateProductCategory(@Valid CrmProductCategoryCreateReqVO updateReqVO); + + /** + * 删除产品分类 + * + * @param id 编号 + */ + void deleteProductCategory(Long id); + + /** + * 获得产品分类 + * + * @param id 编号 + * @return 产品分类 + */ + CrmProductCategoryDO getProductCategory(Long id); + + /** + * 获得产品分类列表 + * + * @param listReqVO 列表请求 + * @return 产品分类列表 + */ + List getProductCategoryList(CrmProductCategoryListReqVO listReqVO); + + /** + * 获得产品分类列表 + * + * @param ids 编号数组 + * @return 产品分类列表 + */ + List getProductCategoryList(Collection ids); + + /** + * 获得产品分类 Map + * + * @param ids 编号数组 + * @return 产品分类 Map + */ + default Map getProductCategoryMap(Collection ids) { + return convertMap(getProductCategoryList(ids), CrmProductCategoryDO::getId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java new file mode 100644 index 0000000..873d996 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.crm.service.product; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductCategoryMapper; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO.PARENT_ID_NULL; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * CRM 产品分类 Service 实现类 + * + * @author ZanGe丶 + */ +@Service +@Validated +public class CrmProductCategoryServiceImpl implements CrmProductCategoryService { + + @Resource(name = "crmProductCategoryMapper") + private CrmProductCategoryMapper productCategoryMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖问题 + private CrmProductService crmProductService; + + @Override + @LogRecord(type = CRM_PRODUCT_CATEGORY_TYPE, subType = CRM_PRODUCT_CATEGORY_CREATE_SUB_TYPE, bizNo = "{{#productCategoryId}}", + success = CRM_PRODUCT_CATEGORY_CREATE_SUCCESS) + public Long createProductCategory(CrmProductCategoryCreateReqVO createReqVO) { + // 1.1 校验父分类存在 + validateParentProductCategory(createReqVO.getParentId()); + // 1.2 分类名称是否存在 + validateProductNameExists(null, createReqVO.getParentId(), createReqVO.getName()); + + // 2. 插入分类 + CrmProductCategoryDO category = BeanUtils.toBean(createReqVO, CrmProductCategoryDO.class); + productCategoryMapper.insert(category); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("productCategoryId", category.getId()); + return category.getId(); + } + + @Override + @LogRecord(type = CRM_PRODUCT_CATEGORY_TYPE, subType = CRM_PRODUCT_CATEGORY_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_PRODUCT_CATEGORY_UPDATE_SUCCESS) + public void updateProductCategory(CrmProductCategoryCreateReqVO updateReqVO) { + // 1.1 校验存在 + validateProductCategoryExists(updateReqVO.getId()); + // 1.2 校验父分类存在 + validateParentProductCategory(updateReqVO.getParentId()); + // 1.3 分类名称是否存在 + validateProductNameExists(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 2. 更新分类 + CrmProductCategoryDO updateObj = BeanUtils.toBean(updateReqVO, CrmProductCategoryDO.class); + productCategoryMapper.updateById(updateObj); + } + + private void validateProductCategoryExists(Long id) { + if (productCategoryMapper.selectById(id) == null) { + throw exception(PRODUCT_CATEGORY_NOT_EXISTS); + } + } + + private void validateParentProductCategory(Long id) { + // 如果是根分类,无需验证 + if (Objects.equals(id, PARENT_ID_NULL)) { + return; + } + // 父分类不存在 + CrmProductCategoryDO category = productCategoryMapper.selectById(id); + if (category == null) { + throw exception(PRODUCT_CATEGORY_PARENT_NOT_EXISTS); + } + // 父分类不能是二级分类 + if (!Objects.equals(category.getParentId(), PARENT_ID_NULL)) { + throw exception(PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL); + } + } + + private void validateProductNameExists(Long id, Long parentId, String name) { + CrmProductCategoryDO category = productCategoryMapper.selectByParentIdAndName(parentId, name); + if (category == null + || category.getId().equals(id)) { + return; + } + throw exception(PRODUCT_CATEGORY_EXISTS); + } + + @Override + @LogRecord(type = CRM_PRODUCT_CATEGORY_TYPE, subType = CRM_PRODUCT_CATEGORY_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_PRODUCT_CATEGORY_DELETE_SUCCESS) + public void deleteProductCategory(Long id) { + // 1.1 校验存在 + validateProductCategoryExists(id); + // 1.2 校验是否还有子分类 + if (productCategoryMapper.selectCountByParentId(id) > 0) { + throw exception(PRODUCT_CATEGORY_EXISTS_CHILDREN); + } + // 1.3 校验是否被产品使用 + if (crmProductService.getProductByCategoryId(id) > 0) { + throw exception(PRODUCT_CATEGORY_USED); + } + // 2. 删除 + productCategoryMapper.deleteById(id); + } + + @Override + public CrmProductCategoryDO getProductCategory(Long id) { + return productCategoryMapper.selectById(id); + } + + @Override + public List getProductCategoryList(CrmProductCategoryListReqVO listReqVO) { + return productCategoryMapper.selectList(listReqVO); + } + + @Override + public List getProductCategoryList(Collection ids) { + return productCategoryMapper.selectBatchIds(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java new file mode 100644 index 0000000..d2f6aa5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.crm.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 产品 Service 接口 + * + * @author ZanGe丶 + */ +public interface CrmProductService { + + /** + * 创建产品 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProduct(@Valid CrmProductSaveReqVO createReqVO); + + /** + * 更新产品 + * + * @param updateReqVO 更新信息 + */ + void updateProduct(@Valid CrmProductSaveReqVO updateReqVO); + + /** + * 删除产品 + * + * @param id 编号 + */ + void deleteProduct(Long id); + + /** + * 获得产品 + * + * @param id 编号 + * @return 产品 + */ + CrmProductDO getProduct(Long id); + + /** + * 获得产品列表 + * + * @param ids 编号 + * @return 产品列表 + */ + List getProductList(Collection ids); + + /** + * 获得产品 Map + * + * @param ids 编号 + * @return 产品 Map + */ + default Map getProductMap(Collection ids) { + return convertMap(getProductList(ids), CrmProductDO::getId); + } + + /** + * 获得产品分页 + * + * @param pageReqVO 分页查询 + * @return 产品分页 + */ + PageResult getProductPage(CrmProductPageReqVO pageReqVO); + + /** + * 获得产品数量 + * + * @param categoryId 分类编号 + * @return 产品 + */ + Long getProductByCategoryId(Long categoryId); + + /** + * 获得指定状态的产品列表 + * + * @param status 状态 + * @return 产品列表 + */ + List getProductListByStatus(Integer status); + + /** + * 校验产品们的有效性 + * + * @param ids 编号数组 + * @return 产品列表 + */ + List validProductList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java new file mode 100644 index 0000000..61b39c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.module.crm.service.product; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; +import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + + +/** + * CRM 产品 Service 实现类 + * + * @author ZanGe丶 + */ +@Service +@Validated +public class CrmProductServiceImpl implements CrmProductService { + + @Resource(name = "crmProductMapper") + private CrmProductMapper productMapper; + + @Resource + private CrmProductCategoryService productCategoryService; + @Resource + private CrmPermissionService permissionService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_CREATE_SUB_TYPE, bizNo = "{{#productId}}", + success = CRM_PRODUCT_CREATE_SUCCESS) + public Long createProduct(CrmProductSaveReqVO createReqVO) { + // 1. 校验产品 + adminUserApi.validateUserList(Collections.singleton(createReqVO.getOwnerUserId())); + validateProductNoDuplicate(null, createReqVO.getNo()); + validateProductCategoryExists(createReqVO.getCategoryId()); + + // 2. 插入产品 + CrmProductDO product = BeanUtils.toBean(createReqVO, CrmProductDO.class); + productMapper.insert(product); + + // 3. 插入数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(product.getOwnerUserId()) + .setBizType(CrmBizTypeEnum.CRM_PRODUCT.getType()).setBizId(product.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("productId", product.getId()); + return product.getId(); + } + + @Override + @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_PRODUCT_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateProduct(CrmProductSaveReqVO updateReqVO) { + // 1. 校验产品 + updateReqVO.setOwnerUserId(null); // 不修改负责人 + CrmProductDO crmProductDO = validateProductExists(updateReqVO.getId()); + validateProductNoDuplicate(updateReqVO.getId(), updateReqVO.getNo()); + validateProductCategoryExists(updateReqVO.getCategoryId()); + + // 2. 更新产品 + CrmProductDO updateObj = BeanUtils.toBean(updateReqVO, CrmProductDO.class); + productMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(crmProductDO, CrmProductSaveReqVO.class)); + } + + private CrmProductDO validateProductExists(Long id) { + CrmProductDO product = productMapper.selectById(id); + if (product == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + return product; + } + + private void validateProductNoDuplicate(Long id, String no) { + CrmProductDO product = productMapper.selectByNo(no); + if (product == null + || product.getId().equals(id)) { + return; + } + throw exception(PRODUCT_NO_EXISTS); + } + + private void validateProductCategoryExists(Long categoryId) { + CrmProductCategoryDO category = productCategoryService.getProductCategory(categoryId); + if (category == null) { + throw exception(PRODUCT_CATEGORY_NOT_EXISTS); + } + } + + @Override + @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_PRODUCT_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteProduct(Long id) { + // 校验存在 + validateProductExists(id); + // 删除 + productMapper.deleteById(id); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmProductDO getProduct(Long id) { + return productMapper.selectById(id); + } + + @Override + public PageResult getProductPage(CrmProductPageReqVO pageReqVO) { + return productMapper.selectPage(pageReqVO); + } + + @Override + public Long getProductByCategoryId(Long categoryId) { + return productMapper.selectCountByCategoryId(categoryId); + } + + @Override + public List getProductListByStatus(Integer status) { + return productMapper.selectListByStatus(status); + } + + @Override + public List validProductList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = productMapper.selectBatchIds(ids); + Map productMap = convertMap(list, CrmProductDO::getId); + for (Long id : ids) { + CrmProductDO product = productMap.get(id); + if (productMap.get(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + if (CrmProductStatusEnum.isDisable(product.getStatus())) { + throw exception(PRODUCT_NOT_ENABLE, product.getName()); + } + } + return list; + } + + @Override + public List getProductList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return productMapper.selectBatchIds(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java new file mode 100644 index 0000000..e81f1e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.crm.service.receivable; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * CRM 回款计划 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmReceivablePlanService { + + /** + * 创建回款计划 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createReceivablePlan(@Valid CrmReceivablePlanSaveReqVO createReqVO); + + /** + * 更新回款计划 + * + * @param updateReqVO 更新信息 + */ + void updateReceivablePlan(@Valid CrmReceivablePlanSaveReqVO updateReqVO); + + /** + * 更新回款计划关联的回款编号 + * + * @param id 编号 + * @param receivableId 回款编号 + */ + void updateReceivablePlanReceivableId(Long id, Long receivableId); + + /** + * 删除回款计划 + * + * @param id 编号 + */ + void deleteReceivablePlan(Long id); + + /** + * 获得回款计划 + * + * @param id 编号 + * @return 回款计划 + */ + CrmReceivablePlanDO getReceivablePlan(Long id); + + /** + * 获得回款计划列表 + * + * @param ids 编号 + * @return 回款计划列表 + */ + List getReceivablePlanList(Collection ids); + + /** + * 获得回款计划分页 + * + * 数据权限:基于 {@link CrmReceivablePlanDO} 读取 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 回款计划分页 + */ + PageResult getReceivablePlanPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId); + + /** + * 获得回款计划分页,基于指定客户 + * + * 数据权限:基于 {@link CrmCustomerDO} 读取 + * + * @param pageReqVO 分页查询 + * @return 回款计划分页 + */ + PageResult getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO); + + /** + * 获得待回款提醒数量 + * + * @param userId 用户编号 + * @return 提醒数量 + */ + Long getReceivablePlanRemindCount(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java new file mode 100644 index 0000000..127ef72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -0,0 +1,187 @@ +package cn.iocoder.yudao.module.crm.service.receivable; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; +import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.RECEIVABLE_PLAN_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.RECEIVABLE_PLAN_UPDATE_FAIL; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; + +/** + * 回款计划 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { + + @Resource + private CrmReceivablePlanMapper receivablePlanMapper; + + @Resource + private CrmContractService contractService; + @Resource + private CrmPermissionService permissionService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE, bizNo = "{{#receivablePlan.id}}", + success = CRM_RECEIVABLE_PLAN_CREATE_SUCCESS) + public Long createReceivablePlan(CrmReceivablePlanSaveReqVO createReqVO) { + // 1. 校验关联数据是否存在 + validateRelationDataExists(createReqVO); + + // 2. 插入回款计划 + CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId()); + int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1; + CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period); + if (createReqVO.getReturnTime() != null && createReqVO.getRemindDays() != null) { + receivablePlan.setRemindTime(createReqVO.getReturnTime().minusDays(createReqVO.getRemindDays())); + } + receivablePlanMapper.insert(receivablePlan); + + // 3. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(createReqVO.getOwnerUserId()) + .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("receivablePlan", receivablePlan); + return receivablePlan.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateReceivablePlan(CrmReceivablePlanSaveReqVO updateReqVO) { + updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null); // 防止修改这些字段 + // 1.1 校验存在 + validateRelationDataExists(updateReqVO); + // 1.2 校验关联数据是否存在 + CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); + // 1.3 如果已经有对应的回款,则不允许编辑 + if (Objects.nonNull(oldReceivablePlan.getReceivableId())) { + throw exception(RECEIVABLE_PLAN_UPDATE_FAIL); + } + + // 2. 更新回款计划 + CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class); + if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) { + updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays())); + } + receivablePlanMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivablePlan, CrmReceivablePlanSaveReqVO.class)); + LogRecordContext.putVariable("receivablePlan", oldReceivablePlan); + } + + private void validateRelationDataExists(CrmReceivablePlanSaveReqVO reqVO) { + // 校验负责人存在 + if (reqVO.getOwnerUserId() != null) { + adminUserApi.validateUser(reqVO.getOwnerUserId()); + } + // 校验合同存在 + if (reqVO.getContractId() != null) { + CrmContractDO contract = contractService.getContract(reqVO.getContractId()); + reqVO.setCustomerId(contract.getCustomerId()); + } + } + + @Override + public void updateReceivablePlanReceivableId(Long id, Long receivableId) { + // 校验存在 + validateReceivablePlanExists(id); + // 更新回款计划 + receivablePlanMapper.updateById(new CrmReceivablePlanDO().setId(id).setReceivableId(receivableId)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_RECEIVABLE_PLAN_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteReceivablePlan(Long id) { + // 1. 校验存在 + CrmReceivablePlanDO receivablePlan = validateReceivablePlanExists(id); + + // 2. 删除 + receivablePlanMapper.deleteById(id); + // 3. 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), id); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("receivablePlan", receivablePlan); + } + + private CrmReceivablePlanDO validateReceivablePlanExists(Long id) { + CrmReceivablePlanDO receivablePlan = receivablePlanMapper.selectById(id); + if (receivablePlan == null) { + throw exception(RECEIVABLE_PLAN_NOT_EXISTS); + } + return receivablePlan; + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmReceivablePlanDO getReceivablePlan(Long id) { + return receivablePlanMapper.selectById(id); + } + + @Override + public List getReceivablePlanList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return receivablePlanMapper.selectBatchIds(ids); + } + + @Override + public PageResult getReceivablePlanPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId) { + return receivablePlanMapper.selectPage(pageReqVO, userId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) + public PageResult getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO) { + return receivablePlanMapper.selectPageByCustomerId(pageReqVO); + } + + @Override + public Long getReceivablePlanRemindCount(Long userId) { + return receivablePlanMapper.selectReceivablePlanCountByRemind(userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java new file mode 100644 index 0000000..287927f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.module.crm.service.receivable; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 回款 Service 接口 + * + * @author 赤焰 + */ +public interface CrmReceivableService { + + /** + * 创建回款 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createReceivable(@Valid CrmReceivableSaveReqVO createReqVO); + + /** + * 更新回款 + * + * @param updateReqVO 更新信息 + */ + void updateReceivable(@Valid CrmReceivableSaveReqVO updateReqVO); + + /** + * 更新回款流程审批结果 + * + * @param id 回款编号 + * @param bpmResult BPM 审批结果 + */ + void updateReceivableAuditStatus(Long id, Integer bpmResult); + + /** + * 删除回款 + * + * @param id 编号 + */ + void deleteReceivable(Long id); + + /** + * 发起回款审批流程 + * + * @param id 回款编号 + * @param userId 用户编号 + */ + void submitReceivable(Long id, Long userId); + + /** + * 获得回款 + * + * @param id 编号 + * @return 回款 + */ + CrmReceivableDO getReceivable(Long id); + + /** + * 获得回款列表 + * + * @param ids 编号 + * @return 回款列表 + */ + List getReceivableList(Collection ids); + + /** + * 获得回款 Map + * + * @param ids 编号 + * @return 回款 Map + */ + default Map getReceivableMap(Collection ids) { + return convertMap(getReceivableList(ids), CrmReceivableDO::getId); + } + + /** + * 获得回款分页 + * + * 数据权限:基于 {@link CrmReceivableDO} 读取 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 回款分页 + */ + PageResult getReceivablePage(CrmReceivablePageReqVO pageReqVO, Long userId); + + /** + * 获得回款分页,基于指定客户 + * + * 数据权限:基于 {@link CrmCustomerDO} 读取 + * + * @param pageReqVO 分页查询 + * @return 回款分页 + */ + PageResult getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO); + + /** + * 获得待审核回款数量 + * + * @param userId 用户编号 + * @return 待审批数量 + */ + Long getAuditReceivableCount(Long userId); + + /** + * 获得合同已回款金额 Map + * + * @param contractIds 合同编号 + * @return 回款金额 Map + */ + Map getReceivablePriceMapByContractId(Collection contractIds); + + /** + * 根据合同编号查询回款数量 + * + * @param contractId 合同编号 + * @return 回款数量 + */ + Long getReceivableCountByContractId(Long contractId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java new file mode 100644 index 0000000..449915c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -0,0 +1,309 @@ +package cn.iocoder.yudao.module.crm.service.receivable; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; +import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; +import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; +import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmResultToAuditStatus; + +/** + * CRM 回款 Service 实现类 + * + * @author 赤焰 + */ +@Service +@Validated +@Slf4j +public class CrmReceivableServiceImpl implements CrmReceivableService { + + /** + * BPM 合同审批流程标识 + */ + public static final String BPM_PROCESS_DEFINITION_KEY = "crm-receivable-audit"; + + @Resource + private CrmReceivableMapper receivableMapper; + + @Resource + private CrmNoRedisDAO noRedisDAO; + + @Resource + private CrmContractService contractService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmReceivablePlanService receivablePlanService; + @Resource + private CrmPermissionService permissionService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private BpmProcessInstanceApi bpmProcessInstanceApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", + success = CRM_RECEIVABLE_CREATE_SUCCESS) + public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { + // 1.1 校验可回款金额超过上限 + validateReceivablePriceExceedsLimit(createReqVO); + // 1.2 校验关联数据存在 + validateRelationDataExists(createReqVO); + // 1.3 生成回款编号 + String no = noRedisDAO.generate(CrmNoRedisDAO.RECEIVABLE_PREFIX); + if (receivableMapper.selectByNo(no) != null) { + throw exception(RECEIVABLE_NO_EXISTS); + } + + // 2.1 插入回款 + CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class) + .setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); + receivableMapper.insert(receivable); + // 2.2 + + // 3. 创建数据权限 + permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) + .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId()) + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + + // 4. 更新关联的回款计划 + if (createReqVO.getPlanId() != null) { + receivablePlanService.updateReceivablePlanReceivableId(receivable.getPlanId(), receivable.getId()); + } + + // 5. 记录操作日志上下文 + LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); + return receivable.getId(); + } + + private void validateReceivablePriceExceedsLimit(CrmReceivableSaveReqVO reqVO) { + // 1. 计算剩余可退款金额,不包括 reqVO 自身 + CrmContractDO contract = contractService.validateContract(reqVO.getContractId()); + List receivables = receivableMapper.selectListByContractIdAndStatus(reqVO.getContractId(), + Arrays.asList(CrmAuditStatusEnum.APPROVE.getStatus(), CrmAuditStatusEnum.PROCESS.getStatus())); + if (reqVO.getId() != null) { + receivables.removeIf(receivable -> ObjectUtil.equal(receivable.getId(), reqVO.getId())); + } + BigDecimal notReceivablePrice = contract.getTotalPrice().subtract( + CollectionUtils.getSumValue(receivables, CrmReceivableDO::getPrice, BigDecimal::add, BigDecimal.ZERO)); + // 2. 校验金额是否超过 + if (reqVO.getPrice().compareTo(notReceivablePrice) > 0) { + throw exception(RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT, notReceivablePrice); + } + } + + private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { + if (reqVO.getOwnerUserId() != null) { + adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 + } + if (reqVO.getContractId() != null) { + CrmContractDO contract = contractService.validateContract(reqVO.getContractId()); + if (ObjectUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { + throw exception(RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE); + } + reqVO.setCustomerId(contract.getCustomerId()); // 设置客户编号 + } + if (reqVO.getPlanId() != null) { + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId()); + if (receivablePlan == null) { + throw exception(RECEIVABLE_PLAN_NOT_EXISTS); + } + if (receivablePlan.getReceivableId() != null) { + throw exception(RECEIVABLE_PLAN_EXISTS_RECEIVABLE); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_RECEIVABLE_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) + public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { + Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); + updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段 + // 1.1 校验存在 + CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); + updateReqVO.setOwnerUserId(receivable.getOwnerUserId()).setCustomerId(receivable.getCustomerId()) + .setContractId(receivable.getContractId()).setPlanId(receivable.getPlanId()); // 设置已存在的值 + // 1.2 校验可回款金额超过上限 + validateReceivablePriceExceedsLimit(updateReqVO); + + // 1.3 只有草稿、审批中,可以编辑; + if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), + CrmAuditStatusEnum.PROCESS.getStatus())) { + throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); + } + + // 2. 更新回款 + CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); + receivableMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class)); + } + + private Integer getReceivablePeriod(Long planId) { + if (Objects.isNull(planId)) { + return null; + } + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(planId); + return receivablePlan.getPeriod(); + } + + @Override + public void updateReceivableAuditStatus(Long id, Integer bpmResult) { + // 1.1 校验存在 + CrmReceivableDO receivable = validateReceivableExists(id); + // 1.2 只有审批中,可以更新审批结果 + if (ObjUtil.notEqual(receivable.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { + log.error("[updateReceivableAuditStatus][receivable({}) 不处于审批中,无法更新审批结果({})]", + receivable.getId(), bpmResult); + throw exception(RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); + } + + // 2. 更新回款审批状态 + Integer auditStatus = convertBpmResultToAuditStatus(bpmResult); + receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_RECEIVABLE_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void deleteReceivable(Long id) { + // 1.1 校验存在 + CrmReceivableDO receivable = validateReceivableExists(id); + // 1.2 如果被 CrmReceivablePlanDO 所使用,则不允许删除 + if (receivable.getPlanId() != null && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { + throw exception(RECEIVABLE_DELETE_FAIL); + } + // 1.3 审批通过时,不允许删除 + if (ObjUtil.equal(receivable.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { + throw exception(RECEIVABLE_DELETE_FAIL_IS_APPROVE); + } + + // 2.1 删除回款 + receivableMapper.deleteById(id); + // 2.2 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_RECEIVABLE_SUBMIT_SUCCESS) + public void submitReceivable(Long id, Long userId) { + // 1. 校验回款是否在审批 + CrmReceivableDO receivable = validateReceivableExists(id); + if (ObjUtil.notEqual(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) { + throw exception(RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT); + } + + // 2. 创建回款审批流程实例 + String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() + .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id))); + + // 3. 更新回款工作流编号 + receivableMapper.updateById(new CrmReceivableDO().setId(id).setProcessInstanceId(processInstanceId) + .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); + + // 4. 记录日志 + LogRecordContext.putVariable("receivableNo", receivable.getNo()); + } + + private CrmReceivableDO validateReceivableExists(Long id) { + CrmReceivableDO receivable = receivableMapper.selectById(id); + if (receivable == null) { + throw exception(RECEIVABLE_NOT_EXISTS); + } + return receivable; + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.READ) + public CrmReceivableDO getReceivable(Long id) { + return receivableMapper.selectById(id); + } + + @Override + public List getReceivableList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return receivableMapper.selectBatchIds(ids); + } + + @Override + public PageResult getReceivablePage(CrmReceivablePageReqVO pageReqVO, Long userId) { + return receivableMapper.selectPage(pageReqVO, userId); + } + + @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) + public PageResult getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO) { + return receivableMapper.selectPageByCustomerId(pageReqVO); + } + + @Override + public Long getAuditReceivableCount(Long userId) { + return receivableMapper.selectCountByAudit(userId); + } + + @Override + public Map getReceivablePriceMapByContractId(Collection contractIds) { + return receivableMapper.selectReceivablePriceMapByContractId(contractIds); + } + + @Override + public Long getReceivableCountByContractId(Long contractId) { + return receivableMapper.selectCountByContractId(contractId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java new file mode 100644 index 0000000..bd76b01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.crm.service.receivable.listener; + +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 回款审批的结果的监听器实现类 + * + * @author HUIHUI + */ +@Component +public class CrmReceivableStatusListener extends BpmProcessInstanceStatusEventListener { + + @Resource + private CrmReceivableService receivableService; + + @Override + public String getProcessDefinitionKey() { + return CrmReceivableServiceImpl.BPM_PROCESS_DEFINITION_KEY; + } + + @Override + public void onEvent(BpmProcessInstanceStatusEvent event) { + receivableService.updateReceivableAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java new file mode 100644 index 0000000..70c720b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; + +import java.util.List; + +/** + * CRM 客户分析 Service 接口 + * + * @author dhb52 + */ +public interface CrmStatisticsCustomerService { + + /** + * 总量分析(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 总量分析(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进次数分析(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getFollowUpSummaryByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 跟进次数分析(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getFollowUpSummaryByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户跟进次数分析(按类型) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getFollowUpSummaryByType(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户的首次合同、回款信息列表,用于【客户转化率】页面 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getContractSummary(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海客户分析(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolSummaryByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海客户分析(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolSummaryByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按日期) + * + * 成交周期的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按区域) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按产品) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java new file mode 100644 index 0000000..4c818ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -0,0 +1,368 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; + +/** + * CRM 客户分析 Service 实现类 + * + * @author dhb52 + */ +@Service +@Validated +public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerService { + + @Resource + private CrmStatisticsCustomerMapper customerMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List customerCreateCountList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByDate(reqVO); + + // 3. 按照日期间隔,合并数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Integer customerCreateCount = customerCreateCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount).sum(); + Integer customerDealCount = customerDealCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount).sum(); + return new CrmStatisticsCustomerSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setCustomerCreateCount(customerCreateCount).setCustomerDealCount(customerDealCount); + }); + } + + @Override + public List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按用户统计,获取分项统计数据 + List customerCreateCountList = customerMapper.selectCustomerCreateCountGroupByUser(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByUser(reqVO); + List contractPriceList = customerMapper.selectContractPriceGroupByUser(reqVO); + List receivablePriceList = customerMapper.selectReceivablePriceGroupByUser(reqVO); + + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Integer customerCreateCount = customerCreateCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount).sum(); + Integer customerDealCount = customerDealCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount).sum(); + BigDecimal contractPrice = contractPriceList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .reduce(BigDecimal.ZERO, (sum, vo) -> sum.add(vo.getContractPrice()), BigDecimal::add); + BigDecimal receivablePrice = receivablePriceList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .reduce(BigDecimal.ZERO, (sum, vo) -> sum.add(vo.getReceivablePrice()), BigDecimal::add); + return (CrmStatisticsCustomerSummaryByUserRespVO) new CrmStatisticsCustomerSummaryByUserRespVO() + .setCustomerCreateCount(customerCreateCount).setCustomerDealCount(customerDealCount) + .setContractPrice(contractPrice).setReceivablePrice(receivablePrice).setOwnerUserId(userId); + }); + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; + } + + @Override + public List getFollowUpSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List followUpRecordCountList = customerMapper.selectFollowUpRecordCountGroupByDate(reqVO); + List followUpCustomerCountList = customerMapper.selectFollowUpCustomerCountGroupByDate(reqVO); + + // 3. 按照时间间隔,合并统计数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Integer followUpRecordCount = followUpRecordCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsFollowUpSummaryByDateRespVO::getFollowUpRecordCount).sum(); + Integer followUpCustomerCount = followUpCustomerCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsFollowUpSummaryByDateRespVO::getFollowUpCustomerCount).sum(); + return new CrmStatisticsFollowUpSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setFollowUpCustomerCount(followUpRecordCount).setFollowUpRecordCount(followUpCustomerCount); + }); + } + + @Override + public List getFollowUpSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按用户统计,获取分项统计数据 + List followUpRecordCountList = customerMapper.selectFollowUpRecordCountGroupByUser(reqVO); + List followUpCustomerCountList = customerMapper.selectFollowUpCustomerCountGroupByUser(reqVO); + + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Integer followUpRecordCount = followUpRecordCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsFollowUpSummaryByUserRespVO::getFollowUpRecordCount).sum(); + Integer followUpCustomerCount = followUpCustomerCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsFollowUpSummaryByUserRespVO::getFollowUpCustomerCount).sum(); + return (CrmStatisticsFollowUpSummaryByUserRespVO) new CrmStatisticsFollowUpSummaryByUserRespVO() + .setFollowUpCustomerCount(followUpRecordCount).setFollowUpRecordCount(followUpCustomerCount).setOwnerUserId(userId); + }); + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; + } + + @Override + public List getFollowUpSummaryByType(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 获得跟进数据 + return customerMapper.selectFollowUpRecordCountGroupByType(reqVO); + } + + @Override + public List getContractSummary(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按用户统计,获取统计数据 + List summaryList = customerMapper.selectContractSummary(reqVO); + + // 3. 拼接信息 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(summaryList, vo -> Stream.of(NumberUtils.parseLong(vo.getCreator()), vo.getOwnerUserId()))); + summaryList.forEach(vo -> { + findAndThen(userMap, NumberUtils.parseLong(vo.getCreator()), user -> vo.setCreatorUserName(user.getNickname())); + findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); + }); + return summaryList; + } + + @Override + public List getPoolSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List customerPutCountList = customerMapper.selectPoolCustomerPutCountByDate(reqVO); + List customerTakeCountList = customerMapper.selectPoolCustomerTakeCountByDate(reqVO); + + // 3. 按照日期间隔,合并数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Integer customerPutCount = customerPutCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsPoolSummaryByDateRespVO::getCustomerPutCount).sum(); + Integer customerTakeCount = customerTakeCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsPoolSummaryByDateRespVO::getCustomerTakeCount).sum(); + return new CrmStatisticsPoolSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setCustomerPutCount(customerPutCount).setCustomerTakeCount(customerTakeCount); + }); + } + + @Override + public List getPoolSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按用户统计,获取分项统计数据 + List customerPutCountList = customerMapper.selectPoolCustomerPutCountByUser(reqVO); + List customerTakeCountList = customerMapper.selectPoolCustomerTakeCountByUser(reqVO); + + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Integer customerPutCount = customerPutCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsPoolSummaryByUserRespVO::getCustomerPutCount).sum(); + Integer customerTakeCount = customerTakeCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsPoolSummaryByUserRespVO::getCustomerTakeCount).sum(); + return (CrmStatisticsPoolSummaryByUserRespVO) new CrmStatisticsPoolSummaryByUserRespVO() + .setCustomerPutCount(customerPutCount).setCustomerTakeCount(customerTakeCount) + .setOwnerUserId(userId); + }); + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; + } + + @Override + public List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List customerDealCycleList = customerMapper.selectCustomerDealCycleGroupByDate(reqVO); + + // 3. 按照日期间隔,合并统计数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Double customerDealCycle = customerDealCycleList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToDouble(CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle).sum(); + return new CrmStatisticsCustomerDealCycleByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setCustomerDealCycle(customerDealCycle); + }); + } + + @Override + public List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按用户统计,获取分项统计数据 + List customerDealCycleList = customerMapper.selectCustomerDealCycleGroupByUser(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByUser(reqVO); + + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Double customerDealCycle = customerDealCycleList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToDouble(CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle).sum(); + Integer customerDealCount = customerDealCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount).sum(); + return (CrmStatisticsCustomerDealCycleByUserRespVO) new CrmStatisticsCustomerDealCycleByUserRespVO() + .setCustomerDealCycle(customerDealCycle).setCustomerDealCount(customerDealCount).setOwnerUserId(userId); + }); + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; + } + + @Override + public List getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户地区统计数据 + List dealCycleByAreaList = customerMapper.selectCustomerDealCycleGroupByAreaId(reqVO); + if (CollUtil.isEmpty(dealCycleByAreaList)) { + return Collections.emptyList(); + } + + // 3. 拼接数据 + Map areaMap = convertMap(AreaUtils.getByType(AreaTypeEnum.PROVINCE, Function.identity()), Area::getId); + return convertList(dealCycleByAreaList, vo -> { + if (vo.getAreaId() != null) { + Integer parentId = AreaUtils.getParentIdByType(vo.getAreaId(), AreaTypeEnum.PROVINCE); + findAndThen(areaMap, parentId, area -> vo.setAreaId(parentId).setAreaName(area.getName())); + } + return vo; + }); + } + + @Override + public List getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户产品统计数据 + // TODO @dhb52:未读取产品名 + return customerMapper.selectCustomerDealCycleGroupByProductId(reqVO); + } + + /** + * 拼接用户信息(昵称) + * + * @param voList 统计数据 + */ + private void appendUserInfo(List voList) { + Map userMap = adminUserApi.getUserMap( + convertSet(voList, CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); + voList.forEach(vo -> findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsCustomerReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java new file mode 100644 index 0000000..10458da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; + +import java.util.List; + +/** + * CRM 销售漏斗分析 Service + * + * @author HUIHUI + */ +public interface CrmStatisticsFunnelService { + + /** + * 获得销售漏斗数据 + * + * @param reqVO 请求 + * @return 销售漏斗数据 + */ + CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO); + + /** + * 获得商机结束状态统计 + * + * @param reqVO 请求 + * @return 商机结束状态统计 + */ + List getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO); + + /** + * 获取新增商机分析(按日期) + * + * @param reqVO 请求 + * @return 新增商机分析 + */ + List getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO); + + /** + * 获得商机转化率分析(按日期) + * + * @param reqVO 请求 + * @return 商机转化率分析 + */ + List getBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO); + + /** + * 获得商机分页(按日期) + * + * @param pageVO 请求 + * @return 商机分页 + */ + PageResult getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java new file mode 100644 index 0000000..fa12817 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper; +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * CRM 销售漏斗分析 Service 实现类 + * + * @author HUIHUI + */ +@Service +public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelService { + + @Resource + private CrmStatisticsFunnelMapper funnelMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private CrmBusinessService businessService; + @Resource + private DeptApi deptApi; + + @Override + public CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return null; + } + reqVO.setUserIds(userIds); + + // 2. 获得漏斗数据 + Long customerCount = funnelMapper.selectCustomerCountByDate(reqVO); + Long businessCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, null); + Long businessWinCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, CrmBusinessEndStatusEnum.WIN.getStatus()); + return new CrmStatisticFunnelSummaryRespVO(customerCount, businessCount, businessWinCount); + } + + @Override + public List getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 获得统计数据 + return funnelMapper.selectBusinessSummaryListGroupByEndStatus(reqVO); + } + + @Override + public List getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List businessSummaryList = funnelMapper.selectBusinessSummaryGroupByDate(reqVO); + // 3. 按照日期间隔,合并数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Long businessCreateCount = businessSummaryList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToLong(CrmStatisticsBusinessSummaryByDateRespVO::getBusinessCreateCount).sum(); + BigDecimal businessDealCount = businessSummaryList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .map(CrmStatisticsBusinessSummaryByDateRespVO::getTotalPrice) + .reduce(BigDecimal.ZERO, BigDecimal::add); + return new CrmStatisticsBusinessSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setBusinessCreateCount(businessCreateCount).setTotalPrice(businessDealCount); + }); + } + + @Override + public List getBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 按天统计,获取分项统计数据 + List businessSummaryList = funnelMapper.selectBusinessInversionRateSummaryByDate(reqVO); + // 3. 按照日期间隔,合并数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Long businessCount = businessSummaryList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToLong(CrmStatisticsBusinessInversionRateSummaryByDateRespVO::getBusinessCount).sum(); + Long businessWinCount = businessSummaryList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToLong(CrmStatisticsBusinessInversionRateSummaryByDateRespVO::getBusinessWinCount).sum(); + return new CrmStatisticsBusinessInversionRateSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setBusinessCount(businessCount).setBusinessWinCount(businessWinCount); + }); + } + + @Override + public PageResult getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) { + // 1. 获得用户编号数组 + pageVO.setUserIds(getUserIds(pageVO)); + if (CollUtil.isEmpty(pageVO.getUserIds())) { + return PageResult.empty(); + } + // 2. 执行查询 + return businessService.getBusinessPageByDate(pageVO); + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsFunnelReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java new file mode 100644 index 0000000..15423af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + + + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; + +import java.util.List; + +/** + * CRM 员工绩效统计 Service 接口 + * + * @author scholar + */ +public interface CrmStatisticsPerformanceService { + + /** + * 员工签约合同数量分析 + * + * @param performanceReqVO 排行参数 + * @return 员工签约合同数量排行分析 + */ + List getContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工签约合同金额分析 + * + * @param performanceReqVO 排行参数 + * @return 员工签约合同金额分析 + */ + List getContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工获得回款金额分析 + * + * @param performanceReqVO 排行参数 + * @return 员工获得回款金额分析 + */ + List getReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java new file mode 100644 index 0000000..14c2099 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPerformanceMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * CRM 员工业绩分析 Service 实现类 + * + * @author scholar + */ +@Service +@Validated +public class CrmStatisticsPerformanceServiceImpl implements CrmStatisticsPerformanceService { + + @Resource + private CrmStatisticsPerformanceMapper performanceMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + // TODO @scholar:可以把下面这个注释,你理解后,重新整理下,写到 getPerformance 里; + // 比如说,2024 年的合同数据,是不是 2022-12 到 2024-12-31,每个月的统计呢? + // 理解之后,我们可以数据 group by 年-月,20222-12 到 2024-12-31 的,然后内存在聚合出 CrmStatisticsPerformanceRespVO 这样 + // 这样,我们就可以减少数据库的计算量,提升性能;同时 SQL 也会很简单,开发者理解起来也简单哈; + return getPerformance(performanceReqVO, performanceMapper::selectContractCountPerformance); + } + + @Override + public List getContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + return getPerformance(performanceReqVO, performanceMapper::selectContractPricePerformance); + } + + @Override + public List getReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + return getPerformance(performanceReqVO, performanceMapper::selectReceivablePricePerformance); + } + + // TODO @scholar:代码注释,应该有 3 个变量哈; + /** + * 获得员工业绩数据 + * + * @param performanceReqVO 参数 + * @param performanceFunction 员工业绩统计方法 + * @return 员工业绩数据 + */ + // TODO @scholar:下面一行的变量,超过一行了,阅读不美观;可以考虑每一行一个变量; + private List getPerformance(CrmStatisticsPerformanceReqVO performanceReqVO, Function> performanceFunction) { + + // TODO @scholar:没使用到的变量,建议删除; + List performanceRespVOList; + + // 1. 获得用户编号数组 + final List userIds = getUserIds(performanceReqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + performanceReqVO.setUserIds(userIds); + // TODO @scholar:1. 和 2. 之间,可以考虑换一行;保证每一块逻辑的间隔; + // 2. 获得业绩数据 + // TODO @scholar:复数变量,建议使用 s 或者 list 结果;这里用 performanceList 好列; + List performance = performanceFunction.apply(performanceReqVO); + + // 获取查询的年份 + // TODO @scholar:逻辑可以简化一下; + // TODO 1)把 performance 转换成 map;key 是 time,value 是 count + // TODO 2)当前年,遍历 1-12 月份,去 map 拿到 count;接着月份 -1,去 map 拿 count;再年份 -1,拿 count + String currentYear = LocalDateTimeUtil.format(performanceReqVO.getTimes()[0],"yyyy"); + + // 构造查询当年和前一年,每年12个月的年月组合 + List allMonths = new ArrayList<>(); + for (int year = Integer.parseInt(currentYear)-1; year <= Integer.parseInt(currentYear); year++) { + for (int month = 1; month <= 12; month++) { + allMonths.add(String.format("%d%02d", year, month)); + } + } + + List computedList = new ArrayList<>(); + List respVOList = new ArrayList<>(); + + // 生成computedList基础数据 + // 构造完整的2*12个月的数据,如果某月数据缺失,需要补上0,一年12个月不能有缺失 + for (String month : allMonths) { + CrmStatisticsPerformanceRespVO foundData = performance.stream() + .filter(data -> data.getTime().equals(month)) + .findFirst() + .orElse(null); + + if (foundData != null) { + computedList.add(foundData); + } else { + CrmStatisticsPerformanceRespVO missingData = new CrmStatisticsPerformanceRespVO(); + missingData.setTime(month); + missingData.setCurrentMonthCount(BigDecimal.ZERO); + missingData.setLastMonthCount(BigDecimal.ZERO); + missingData.setLastYearCount(BigDecimal.ZERO); + computedList.add(missingData); + } + } + //根据查询年份和前一年的数据,计算查询年份的同比环比数据 + for (CrmStatisticsPerformanceRespVO currentData : computedList) { + String currentMonth = currentData.getTime(); + + // 根据当年和前一年的月销售数据,计算currentYear的完整数据 + if (currentMonth.startsWith(currentYear)) { + // 计算 LastMonthCount + int currentIndex = computedList.indexOf(currentData); + if (currentIndex > 0) { + CrmStatisticsPerformanceRespVO lastMonthData = computedList.get(currentIndex - 1); + currentData.setLastMonthCount(lastMonthData.getCurrentMonthCount()); + } else { + currentData.setLastMonthCount(BigDecimal.ZERO); // 第一个月的 LastMonthCount 设为0 + } + + // 计算 LastYearCount + String lastYearMonth = String.valueOf(Integer.parseInt(currentMonth) - 100); + CrmStatisticsPerformanceRespVO lastYearData = computedList.stream() + .filter(data -> data.getTime().equals(lastYearMonth)) + .findFirst() + .orElse(null); + + if (lastYearData != null) { + currentData.setLastYearCount(lastYearData.getCurrentMonthCount()); + } else { + currentData.setLastYearCount(BigDecimal.ZERO); // 如果去年同月数据不存在,设为0 + } + respVOList.add(currentData);//给前端只需要返回查询当年的数据,不需要前一年数据 + } + } + return respVOList; + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsPerformanceReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + final Long deptId = reqVO.getDeptId(); + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java new file mode 100644 index 0000000..c568d3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; + +import java.util.List; + +/** + * CRM 客户画像 Service 接口 + * + * @author HUIHUI + */ +public interface CrmStatisticsPortraitService { + + /** + * 获取客户地区统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO); + + /** + * 获取客户行业统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO); + + /** + * 获取客户级别统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO); + + /** + * 获取客户来源统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java new file mode 100644 index 0000000..fe5a24b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 客户画像 Service 实现类 + * + * @author HUIHUI + */ +@Service +public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitService { + + @Resource + private CrmStatisticsPortraitMapper portraitMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户地区统计数据 + List list = portraitMapper.selectSummaryListGroupByAreaId(reqVO); + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + + // 3. 拼接数据 + List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); + Map areaMap = convertMap(areaList, Area::getId); + return convertList(list, item -> { + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); + if (parentId != null) { + Area area = areaMap.get(parentId); + if (area != null) { + item.setAreaId(parentId).setAreaName(area.getName()); + return item; + } + } + // 找不到,归到未知 + return item.setAreaId(null).setAreaName("未知"); + }); + } + + @Override + public List getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户行业统计数据 + return portraitMapper.selectCustomerIndustryListGroupByIndustryId(reqVO); + } + + @Override + public List getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户行业统计数据 + return portraitMapper.selectCustomerSourceListGroupBySource(reqVO); + } + + @Override + public List getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取客户级别统计数据 + return portraitMapper.selectCustomerLevelListGroupByLevel(reqVO); + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsPortraitReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java new file mode 100644 index 0000000..2fc8a5b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; + +import java.util.List; + +/** + * CRM 排行榜统计 Service 接口 + * + * @author anhaohao + */ +public interface CrmStatisticsRankService { + + /** + * 获得合同金额排行榜 + * + * @param rankReqVO 排行参数 + * @return 合同金额排行榜 + */ + List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得回款金额排行榜 + * + * @param rankReqVO 排行参数 + * @return 回款金额排行榜 + */ + List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得签约合同数量排行榜 + * + * @param rankReqVO 排行参数 + * @return 签约合同数量排行榜 + */ + List getContractCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得产品销量排行榜 + * + * @param rankReqVO 排行参数 + * @return 产品销量排行榜 + */ + List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得新增客户数排行榜 + * + * @param rankReqVO 排行参数 + * @return 新增客户数排行榜 + */ + List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得联系人数量排行榜 + * + * @param rankReqVO 排行参数 + * @return 联系人数量排行榜 + */ + List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得跟进次数排行榜 + * + * @param rankReqVO 排行参数 + * @return 跟进次数排行榜 + */ + List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO); + + /** + * 获得跟进客户数排行榜 + * + * @param rankReqVO 排行参数 + * @return 跟进客户数排行榜 + */ + List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java new file mode 100644 index 0000000..715bfd4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsRankMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * CRM 排行榜统计 Service 实现类 + * + * @author anhaohao + */ +@Service +@Validated +public class CrmStatisticsRankServiceImpl implements CrmStatisticsRankService { + + @Resource + private CrmStatisticsRankMapper rankMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectContractPriceRank); + } + + @Override + public List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectReceivablePriceRank); + } + + @Override + public List getContractCountRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectContractCountRank); + } + + @Override + public List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectProductSalesRank); + } + + @Override + public List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectCustomerCountRank); + } + + @Override + public List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectContactsCountRank); + } + + @Override + public List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectFollowCountRank); + } + + @Override + public List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { + return getRank(rankReqVO, rankMapper::selectFollowCustomerCountRank); + } + + /** + * 获得排行版数据 + * + * @param rankReqVO 参数 + * @param rankFunction 排行榜方法 + * @return 排行版数据 + */ + private List getRank(CrmStatisticsRankReqVO rankReqVO, Function> rankFunction) { + // 1. 获得用户编号数组 + rankReqVO.setUserIds(getUserIds(rankReqVO.getDeptId())); + if (CollUtil.isEmpty(rankReqVO.getUserIds())) { + return Collections.emptyList(); + } + // 2. 获得排行数据 + List ranks = rankFunction.apply(rankReqVO); + if (CollUtil.isEmpty(ranks)) { + return Collections.emptyList(); + } + ranks.sort(Comparator.comparing(CrmStatisticsRankRespVO::getCount).reversed()); + // 3. 拼接用户信息 + appendUserInfo(ranks); + return ranks; + } + + /** + * 拼接用户信息(昵称、部门) + * + * @param ranks 排行榜数据 + */ + private void appendUserInfo(List ranks) { + Map userMap = adminUserApi.getUserMap(convertSet(ranks, CrmStatisticsRankRespVO::getOwnerUserId)); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + ranks.forEach(rank -> MapUtils.findAndThen(userMap, rank.getOwnerUserId(), user -> { + rank.setNickname(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> rank.setDeptName(dept.getName())); + })); + } + + /** + * 获得部门下的用户编号数组,包括子部门的 + * + * @param deptId 部门编号 + * @return 用户编号数组 + */ + public List getUserIds(Long deptId) { + // 1. 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2. 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java new file mode 100644 index 0000000..c1d4eaa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.util; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; + +/** + * CRM 流程工具类 + * + * @author HUIHUI + */ +public class CrmAuditStatusUtils { + + /** + * BPM 审批结果转换 + * + * @param bpmResult BPM 审批结果 + */ + public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { + Integer auditStatus = BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() + : BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() + : BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult) ? BpmTaskStatusEnum.CANCEL.getStatus() : null; + Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); + return auditStatus; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java new file mode 100644 index 0000000..c42db3e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.crm.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.github.yulichang.autoconfigure.MybatisPlusJoinProperties; +import com.github.yulichang.wrapper.MPJLambdaWrapper; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * 数据权限工具类 + * + * @author HUIHUI + */ +public class CrmPermissionUtils { + + /** + * 校验用户是否是 CRM 管理员 + * + * @return 是/否 + */ + public static boolean isCrmAdmin() { + PermissionApi permissionApi = SpringUtil.getBean(PermissionApi.class); + return permissionApi.hasAnyRoles(getLoginUserId(), RoleCodeEnum.CRM_ADMIN.getCode()); + } + + /** + * 构造 CRM 数据类型数据分页查询条件 + * + * @param query 连表查询对象 + * @param bizType 数据类型 {@link CrmBizTypeEnum} + * @param bizId 数据编号 + * @param userId 用户编号 + * @param sceneType 场景类型 + * @param pool 公海 + */ + public static , S> void appendPermissionCondition(T query, Integer bizType, SFunction bizId, + Long userId, Integer sceneType, Boolean pool) { + MybatisPlusJoinProperties mybatisPlusJoinProperties = SpringUtil.getBean(MybatisPlusJoinProperties.class); + final String ownerUserIdField = mybatisPlusJoinProperties.getTableAlias() + ".owner_user_id"; + // 1. 构建数据权限连表条件 + if (!CrmPermissionUtils.isCrmAdmin() && ObjUtil.notEqual(pool, Boolean.TRUE)) { // 管理员,公海不需要数据权限 + query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId) // 只能使用 SFunction 如果传 id 解析出来的 sql 不对 + .eq(CrmPermissionDO::getUserId, userId)); + } + // 2.1 场景一:我负责的数据 + if (CrmSceneTypeEnum.isOwner(sceneType)) { + query.eq(ownerUserIdField, userId); + } + // 2.2 场景二:我参与的数据 + if (CrmSceneTypeEnum.isInvolved(sceneType)) { + query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) + .eq(CrmPermissionDO::getBizId, bizId) + .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())); + query.ne(ownerUserIdField, userId); + } + // 2.3 场景三:下属负责的数据 + if (CrmSceneTypeEnum.isSubordinate(sceneType)) { + AdminUserApi adminUserApi = SpringUtil.getBean(AdminUserApi.class); + List subordinateUsers = adminUserApi.getUserListBySubordinate(userId); + if (CollUtil.isEmpty(subordinateUsers)) { + query.eq(ownerUserIdField, -1); // 不返回任何结果 + } else { + query.in(ownerUserIdField, convertSet(subordinateUsers, AdminUserRespDTO::getId)); + } + } + + // 3. 拼接公海的查询条件 + if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海 + query.isNull(ownerUserIdField); + } else { // 情况二:不是公海 + query.isNotNull(ownerUserIdField); + } + } + + /** + * 构造 CRM 数据类型批量数据查询条件 + * + * @param query 连表查询对象 + * @param bizType 数据类型 {@link CrmBizTypeEnum} + * @param bizIds 数据编号 + * @param userId 用户编号 + */ + public static > void appendPermissionCondition(T query, Integer bizType, Collection bizIds, Long userId) { + if (isCrmAdmin()) {// 管理员不需要数据权限 + return; + } + query.innerJoin(CrmPermissionDO.class, on -> + on.eq(CrmPermissionDO::getBizType, bizType).in(CrmPermissionDO::getBizId, bizIds) + .eq(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml new file mode 100644 index 0000000..dc10f12 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml new file mode 100644 index 0000000..a074062 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml new file mode 100644 index 0000000..79ff454 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml new file mode 100644 index 0000000..42056a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml new file mode 100644 index 0000000..abd63f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..0fc9151 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,48 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis-plus: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao diff --git a/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..1d071e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-crm/yudao-module-crm-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-erp/pom.xml b/ruoyi-vue-pro-master/yudao-module-erp/pom.xml new file mode 100644 index 0000000..22fe0ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/pom.xml @@ -0,0 +1,24 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + + yudao-module-erp-api + yudao-module-erp-biz + + 4.0.0 + yudao-module-erp + pom + + ${project.artifactId} + + erp 包下,企业资源管理(Enterprise Resource Planning)。 + 例如说:采购、销售、库存、财务、产品等等 + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/pom.xml new file mode 100644 index 0000000..961845c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-erp + ${revision} + + 4.0.0 + yudao-module-erp-api + jar + + ${project.artifactId} + + erp 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/api/package-info.java new file mode 100644 index 0000000..540f18f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/api/package-info.java @@ -0,0 +1,4 @@ +/** + * erp API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.erp.api; diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java new file mode 100644 index 0000000..36d4df8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/DictTypeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.erp.enums; + +/** + * ERP 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String AUDIT_STATUS = "erp_audit_status"; // 审核状态 + String STOCK_RECORD_BIZ_TYPE = "erp_stock_record_biz_type"; // 库存明细的业务类型 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java new file mode 100644 index 0000000..a10147a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.erp.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * ERP 审核状态枚举 + * + * TODO 芋艿:目前只有待审批、已审批两个状态,未来接入工作流后,会丰富下:待提交(草稿)=》已提交(待审核)=》审核通过、审核不通过;另外,工作流需要支持“反审核”,把工作流退回到原点; + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum ErpAuditStatus implements IntArrayValuable { + + PROCESS(10, "未审核"), // 审核中 + APPROVE(20, "已审核"); // 审核通过 + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpAuditStatus::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..65f64c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -0,0 +1,168 @@ +package cn.iocoder.yudao.module.erp.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * ERP 错误码枚举类 + *

+ * erp 系统,使用 1-030-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== ERP 供应商(1-030-100-000) ========== + ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在"); + ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用"); + + // ========== ERP 采购订单(1-030-101-000) ========== + ErrorCode PURCHASE_ORDER_NOT_EXISTS = new ErrorCode(1_030_101_000, "采购订单不存在"); + ErrorCode PURCHASE_ORDER_DELETE_FAIL_APPROVE = new ErrorCode(1_030_101_001, "采购订单({})已审核,无法删除"); + ErrorCode PURCHASE_ORDER_PROCESS_FAIL = new ErrorCode(1_030_101_002, "反审核失败,只有已审核的采购订单才能反审核"); + ErrorCode PURCHASE_ORDER_APPROVE_FAIL = new ErrorCode(1_030_101_003, "审核失败,只有未审核的采购订单才能审核"); + ErrorCode PURCHASE_ORDER_NO_EXISTS = new ErrorCode(1_030_101_004, "生成采购单号失败,请重新提交"); + ErrorCode PURCHASE_ORDER_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_101_005, "采购订单({})已审核,无法修改"); + ErrorCode PURCHASE_ORDER_NOT_APPROVE = new ErrorCode(1_030_101_006, "采购订单未审核,无法操作"); + ErrorCode PURCHASE_ORDER_ITEM_IN_FAIL_PRODUCT_EXCEED = new ErrorCode(1_030_101_007, "采购订单项({})超过最大允许入库数量({})"); + ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_IN = new ErrorCode(1_030_101_008, "反审核失败,已存在对应的采购入库单"); +ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_009, "采购订单项({})超过最大允许退货数量({})"); + ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_030_101_010, "反审核失败,已存在对应的采购退货单"); + + // ========== ERP 采购入库(1-030-102-000) ========== + ErrorCode PURCHASE_IN_NOT_EXISTS = new ErrorCode(1_030_102_000, "采购入库单不存在"); + ErrorCode PURCHASE_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_102_001, "采购入库单({})已审核,无法删除"); + ErrorCode PURCHASE_IN_PROCESS_FAIL = new ErrorCode(1_030_102_002, "反审核失败,只有已审核的入库单才能反审核"); + ErrorCode PURCHASE_IN_APPROVE_FAIL = new ErrorCode(1_030_102_003, "审核失败,只有未审核的入库单才能审核"); + ErrorCode PURCHASE_IN_NO_EXISTS = new ErrorCode(1_030_102_004, "生成入库单失败,请重新提交"); + ErrorCode PURCHASE_IN_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_102_005, "采购入库单({})已审核,无法修改"); + ErrorCode PURCHASE_IN_NOT_APPROVE = new ErrorCode(1_030_102_006, "采购入库单未审核,无法操作"); + ErrorCode PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED = new ErrorCode(1_030_102_007, "付款金额({})超过采购入库单总金额({})"); + ErrorCode PURCHASE_IN_PROCESS_FAIL_EXISTS_PAYMENT = new ErrorCode(1_030_102_008, "反审核失败,已存在对应的付款单"); + + // ========== ERP 采购退货(1-030-103-000) ========== + ErrorCode PURCHASE_RETURN_NOT_EXISTS = new ErrorCode(1_030_103_000, "采购退货单不存在"); + ErrorCode PURCHASE_RETURN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_103_001, "采购退货单({})已审核,无法删除"); + ErrorCode PURCHASE_RETURN_PROCESS_FAIL = new ErrorCode(1_030_103_002, "反审核失败,只有已审核的退货单才能反审核"); + ErrorCode PURCHASE_RETURN_APPROVE_FAIL = new ErrorCode(1_030_103_003, "审核失败,只有未审核的退货单才能审核"); + ErrorCode PURCHASE_RETURN_NO_EXISTS = new ErrorCode(1_030_103_004, "生成退货单失败,请重新提交"); + ErrorCode PURCHASE_RETURN_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_103_005, "采购退货单({})已审核,无法修改"); + ErrorCode PURCHASE_RETURN_NOT_APPROVE = new ErrorCode(1_030_103_006, "采购退货单未审核,无法操作"); + ErrorCode PURCHASE_RETURN_FAIL_REFUND_PRICE_EXCEED = new ErrorCode(1_030_103_007, "退款金额({})超过采购退货单总金额({})"); + ErrorCode PURCHASE_RETURN_PROCESS_FAIL_EXISTS_REFUND = new ErrorCode(1_030_103_008, "反审核失败,已存在对应的退款单"); + + // ========== ERP 客户(1-030-200-000)========== + ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_200_000, "客户不存在"); + ErrorCode CUSTOMER_NOT_ENABLE = new ErrorCode(1_020_200_001, "客户({})未启用"); + + // ========== ERP 销售订单(1-030-201-000) ========== + ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_201_000, "销售订单不存在"); + ErrorCode SALE_ORDER_DELETE_FAIL_APPROVE = new ErrorCode(1_020_201_001, "销售订单({})已审核,无法删除"); + ErrorCode SALE_ORDER_PROCESS_FAIL = new ErrorCode(1_020_201_002, "反审核失败,只有已审核的销售订单才能反审核"); + ErrorCode SALE_ORDER_APPROVE_FAIL = new ErrorCode(1_020_201_003, "审核失败,只有未审核的销售订单才能审核"); + ErrorCode SALE_ORDER_NO_EXISTS = new ErrorCode(1_020_201_004, "生成销售单号失败,请重新提交"); + ErrorCode SALE_ORDER_UPDATE_FAIL_APPROVE = new ErrorCode(1_020_201_005, "销售订单({})已审核,无法修改"); + ErrorCode SALE_ORDER_NOT_APPROVE = new ErrorCode(1_020_201_006, "销售订单未审核,无法操作"); + ErrorCode SALE_ORDER_ITEM_OUT_FAIL_PRODUCT_EXCEED = new ErrorCode(1_020_201_007, "销售订单项({})超过最大允许出库数量({})"); + ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_OUT = new ErrorCode(1_020_201_008, "反审核失败,已存在对应的销售出库单"); + ErrorCode SALE_ORDER_ITEM_RETURN_FAIL_OUT_EXCEED = new ErrorCode(1_020_201_009, "销售订单项({})超过最大允许退货数量({})"); + ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_020_201_010, "反审核失败,已存在对应的销售退货单"); + + // ========== ERP 销售出库(1-030-202-000) ========== + ErrorCode SALE_OUT_NOT_EXISTS = new ErrorCode(1_020_202_000, "销售出库单不存在"); + ErrorCode SALE_OUT_DELETE_FAIL_APPROVE = new ErrorCode(1_020_202_001, "销售出库单({})已审核,无法删除"); + ErrorCode SALE_OUT_PROCESS_FAIL = new ErrorCode(1_020_202_002, "反审核失败,只有已审核的出库单才能反审核"); + ErrorCode SALE_OUT_APPROVE_FAIL = new ErrorCode(1_020_202_003, "审核失败,只有未审核的出库单才能审核"); + ErrorCode SALE_OUT_NO_EXISTS = new ErrorCode(1_020_202_004, "生成出库单失败,请重新提交"); + ErrorCode SALE_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_020_202_005, "销售出库单({})已审核,无法修改"); + ErrorCode SALE_OUT_NOT_APPROVE = new ErrorCode(1_020_202_006, "销售出库单未审核,无法操作"); + ErrorCode SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED = new ErrorCode(1_020_202_007, "收款金额({})超过销售出库单总金额({})"); + ErrorCode SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT = new ErrorCode(1_020_202_008, "反审核失败,已存在对应的收款单"); + + // ========== ERP 销售退货(1-030-203-000) ========== + ErrorCode SALE_RETURN_NOT_EXISTS = new ErrorCode(1_020_203_000, "销售退货单不存在"); + ErrorCode SALE_RETURN_DELETE_FAIL_APPROVE = new ErrorCode(1_020_203_001, "销售退货单({})已审核,无法删除"); + ErrorCode SALE_RETURN_PROCESS_FAIL = new ErrorCode(1_020_203_002, "反审核失败,只有已审核的退货单才能反审核"); + ErrorCode SALE_RETURN_APPROVE_FAIL = new ErrorCode(1_020_203_003, "审核失败,只有未审核的退货单才能审核"); + ErrorCode SALE_RETURN_NO_EXISTS = new ErrorCode(1_020_203_004, "生成退货单失败,请重新提交"); + ErrorCode SALE_RETURN_UPDATE_FAIL_APPROVE = new ErrorCode(1_020_203_005, "销售退货单({})已审核,无法修改"); + ErrorCode SALE_RETURN_NOT_APPROVE = new ErrorCode(1_020_203_006, "销售退货单未审核,无法操作"); + ErrorCode SALE_RETURN_FAIL_REFUND_PRICE_EXCEED = new ErrorCode(1_020_203_007, "退款金额({})超过销售退货单总金额({})"); + ErrorCode SALE_RETURN_PROCESS_FAIL_EXISTS_REFUND = new ErrorCode(1_020_203_008, "反审核失败,已存在对应的退款单"); + + // ========== ERP 仓库 1-030-400-000 ========== + ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_030_400_000, "仓库不存在"); + ErrorCode WAREHOUSE_NOT_ENABLE = new ErrorCode(1_030_400_001, "仓库({})未启用"); + + // ========== ERP 其它入库单 1-030-401-000 ========== + ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); + ErrorCode STOCK_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_401_001, "其它入库单({})已审核,无法删除"); + ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核"); + ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核"); + ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交"); + ErrorCode STOCK_IN_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_401_005, "其它入库单({})已审核,无法修改"); + + // ========== ERP 其它出库单 1-030-402-000 ========== + ErrorCode STOCK_OUT_NOT_EXISTS = new ErrorCode(1_030_402_000, "其它出库单不存在"); + ErrorCode STOCK_OUT_DELETE_FAIL_APPROVE = new ErrorCode(1_030_402_001, "其它出库单({})已审核,无法删除"); + ErrorCode STOCK_OUT_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的出库单才能反审核"); + ErrorCode STOCK_OUT_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的出库单才能审核"); + ErrorCode STOCK_OUT_NO_EXISTS = new ErrorCode(1_030_402_004, "生成出库单失败,请重新提交"); + ErrorCode STOCK_OUT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "其它出库单({})已审核,无法修改"); + + // ========== ERP 库存调拨单 1-030-403-000 ========== + ErrorCode STOCK_MOVE_NOT_EXISTS = new ErrorCode(1_030_402_000, "库存调拨单不存在"); + ErrorCode STOCK_MOVE_DELETE_FAIL_APPROVE = new ErrorCode(1_030_402_001, "库存调拨单({})已审核,无法删除"); + ErrorCode STOCK_MOVE_PROCESS_FAIL = new ErrorCode(1_030_402_002, "反审核失败,只有已审核的调拨单才能反审核"); + ErrorCode STOCK_MOVE_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的调拨单才能审核"); + ErrorCode STOCK_MOVE_NO_EXISTS = new ErrorCode(1_030_402_004, "生成调拨号失败,请重新提交"); + ErrorCode STOCK_MOVE_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "库存调拨单({})已审核,无法修改"); + + // ========== ERP 库存盘点单 1-030-403-000 ========== + ErrorCode STOCK_CHECK_NOT_EXISTS = new ErrorCode(1_030_403_000, "库存盘点单不存在"); + ErrorCode STOCK_CHECK_DELETE_FAIL_APPROVE = new ErrorCode(1_030_403_001, "库存盘点单({})已审核,无法删除"); + ErrorCode STOCK_CHECK_PROCESS_FAIL = new ErrorCode(1_030_403_002, "反审核失败,只有已审核的盘点单才能反审核"); + ErrorCode STOCK_CHECK_APPROVE_FAIL = new ErrorCode(1_030_403_003, "审核失败,只有未审核的盘点单才能审核"); + ErrorCode STOCK_CHECK_NO_EXISTS = new ErrorCode(1_030_403_004, "生成盘点号失败,请重新提交"); + ErrorCode STOCK_CHECK_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_403_005, "库存盘点单({})已审核,无法修改"); + + // ========== ERP 产品库存 1-030-404-000 ========== + ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); + ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_404_001, "操作失败,产品({})所在仓库({})的库存不足"); + + // ========== ERP 产品 1-030-500-000 ========== + ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); + ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用"); + + // ========== ERP 产品分类 1-030-501-000 ========== + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); + ErrorCode PRODUCT_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_030_501_001, "存在存在子产品分类,无法删除"); + ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_030_501_002,"父级产品分类不存在"); + ErrorCode PRODUCT_CATEGORY_PARENT_ERROR = new ErrorCode(1_030_501_003, "不能设置自己为父产品分类"); + ErrorCode PRODUCT_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_030_501_004, "已经存在该分类名称的产品分类"); + ErrorCode PRODUCT_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_030_501_005, "不能设置自己的子分类为父分类"); + ErrorCode PRODUCT_CATEGORY_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该分类,无法删除"); + + // ========== ERP 产品单位 1-030-502-000 ========== + ErrorCode PRODUCT_UNIT_NOT_EXISTS = new ErrorCode(1_030_502_000, "产品单位不存在"); + ErrorCode PRODUCT_UNIT_NAME_DUPLICATE = new ErrorCode(1_030_502_001, "已存在该名字的产品单位"); + ErrorCode PRODUCT_UNIT_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该单位,无法删除"); + + // ========== ERP 结算账户 1-030-600-000 ========== + ErrorCode ACCOUNT_NOT_EXISTS = new ErrorCode(1_030_600_000, "结算账户不存在"); + ErrorCode ACCOUNT_NOT_ENABLE = new ErrorCode(1_030_600_001, "结算账户({})未启用"); + + // ========== ERP 付款单 1-030-601-000 ========== + ErrorCode FINANCE_PAYMENT_NOT_EXISTS = new ErrorCode(1_030_601_000, "付款单不存在"); + ErrorCode FINANCE_PAYMENT_DELETE_FAIL_APPROVE = new ErrorCode(1_030_601_001, "付款单({})已审核,无法删除"); + ErrorCode FINANCE_PAYMENT_PROCESS_FAIL = new ErrorCode(1_030_601_002, "反审核失败,只有已审核的付款单才能反审核"); + ErrorCode FINANCE_PAYMENT_APPROVE_FAIL = new ErrorCode(1_030_601_003, "审核失败,只有未审核的付款单才能审核"); + ErrorCode FINANCE_PAYMENT_NO_EXISTS = new ErrorCode(1_030_601_004, "生成付款单号失败,请重新提交"); + ErrorCode FINANCE_PAYMENT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_601_005, "付款单({})已审核,无法修改"); + + // ========== ERP 收款单 1-030-602-000 ========== + ErrorCode FINANCE_RECEIPT_NOT_EXISTS = new ErrorCode(1_030_602_000, "收款单不存在"); + ErrorCode FINANCE_RECEIPT_DELETE_FAIL_APPROVE = new ErrorCode(1_030_602_001, "收款单({})已审核,无法删除"); + ErrorCode FINANCE_RECEIPT_PROCESS_FAIL = new ErrorCode(1_030_602_002, "反审核失败,只有已审核的收款单才能反审核"); + ErrorCode FINANCE_RECEIPT_APPROVE_FAIL = new ErrorCode(1_030_602_003, "审核失败,只有未审核的收款单才能审核"); + ErrorCode FINANCE_RECEIPT_NO_EXISTS = new ErrorCode(1_030_602_004, "生成收款单号失败,请重新提交"); + ErrorCode FINANCE_RECEIPT_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_602_005, "收款单({})已审核,无法修改"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/LogRecordConstants.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/LogRecordConstants.java new file mode 100644 index 0000000..73b72c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/LogRecordConstants.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.erp.enums; + +/** + * ERP 操作日志枚举 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串 + * + * @author 芋道源码 + */ +public interface LogRecordConstants { + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/common/ErpBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/common/ErpBizTypeEnum.java new file mode 100644 index 0000000..a277059 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/common/ErpBizTypeEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.erp.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * ERP 业务类型枚举 + * + * @author HUIHUI + */ +@RequiredArgsConstructor +@Getter +public enum ErpBizTypeEnum implements IntArrayValuable { + + PURCHASE_ORDER(10, "采购订单"), + PURCHASE_IN(11, "采购入库"), + PURCHASE_RETURN(12, "采购退货"), + + SALE_ORDER(20, "销售订单"), + SALE_OUT(21, "销售出库"), + SALE_RETURN(22, "销售退货"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpBizTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java new file mode 100644 index 0000000..559bf4c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockRecordBizTypeEnum.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.erp.enums.stock; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * ERP 库存明细 - 业务类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum ErpStockRecordBizTypeEnum implements IntArrayValuable { + + OTHER_IN(10, "其它入库"), + OTHER_IN_CANCEL(11, "其它入库(作废)"), + + OTHER_OUT(20, "其它出库"), + OTHER_OUT_CANCEL(21, "其它出库(作废)"), + + MOVE_IN(30, "调拨入库"), + MOVE_IN_CANCEL(31, "调拨入库(作废)"), + MOVE_OUT(32, "调拨出库"), + MOVE_OUT_CANCEL(33, "调拨出库(作废)"), + + CHECK_MORE_IN(40, "盘盈入库"), + CHECK_MORE_IN_CANCEL(41, "盘盈入库(作废)"), + CHECK_LESS_OUT(42, "盘亏出库"), + CHECK_LESS_OUT_CANCEL(43, "盘亏出库(作废)"), + + SALE_OUT(50, "销售出库"), + SALE_OUT_CANCEL(51, "销售出库(作废)"), + + SALE_RETURN(60, "销售退货入库"), + SALE_RETURN_CANCEL(61, "销售退货入库(作废)"), + + PURCHASE_IN(70, "采购入库"), + PURCHASE_IN_CANCEL(71, "采购入库(作废)"), + + PURCHASE_RETURN(80, "采购退货出库"), + PURCHASE_RETURN_CANCEL(81, "采购退货出库(作废)"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockRecordBizTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/pom.xml new file mode 100644 index 0000000..f1a3f7a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/pom.xml @@ -0,0 +1,69 @@ + + + + cn.iocoder.boot + yudao-module-erp + ${revision} + + 4.0.0 + yudao-module-erp-biz + + ${project.artifactId} + + erp 包下,企业资源管理(Enterprise Resource Planning)。 + 例如说:采购、销售、库存、财务、产品等等 + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-erp-api + ${revision} + + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java new file mode 100644 index 0000000..fcc43ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 结算账户") +@RestController +@RequestMapping("/erp/account") +@Validated +public class ErpAccountController { + + @Resource + private ErpAccountService accountService; + + @PostMapping("/create") + @Operation(summary = "创建结算账户") + @PreAuthorize("@ss.hasPermission('erp:account:create')") + public CommonResult createAccount(@Valid @RequestBody ErpAccountSaveReqVO createReqVO) { + return success(accountService.createAccount(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新结算账户") + @PreAuthorize("@ss.hasPermission('erp:account:update')") + public CommonResult updateAccount(@Valid @RequestBody ErpAccountSaveReqVO updateReqVO) { + accountService.updateAccount(updateReqVO); + return success(true); + } + + @PutMapping("/update-default-status") + @Operation(summary = "更新结算账户默认状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true), + @Parameter(name = "status", description = "状态", required = true) + }) + public CommonResult updateAccountDefaultStatus(@RequestParam("id") Long id, + @RequestParam("defaultStatus") Boolean defaultStatus) { + accountService.updateAccountDefaultStatus(id, defaultStatus); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除结算账户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:account:delete')") + public CommonResult deleteAccount(@RequestParam("id") Long id) { + accountService.deleteAccount(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得结算账户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:account:query')") + public CommonResult getAccount(@RequestParam("id") Long id) { + ErpAccountDO account = accountService.getAccount(id); + return success(BeanUtils.toBean(account, ErpAccountRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得结算账户精简列表", description = "只包含被开启的结算账户,主要用于前端的下拉选项") + public CommonResult> getWarehouseSimpleList() { + List list = accountService.getAccountListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, account -> new ErpAccountRespVO().setId(account.getId()) + .setName(account.getName()).setDefaultStatus(account.getDefaultStatus()))); + } + + @GetMapping("/page") + @Operation(summary = "获得结算账户分页") + @PreAuthorize("@ss.hasPermission('erp:account:query')") + public CommonResult> getAccountPage(@Valid ErpAccountPageReqVO pageReqVO) { + PageResult pageResult = accountService.getAccountPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpAccountRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出结算账户 Excel") + @PreAuthorize("@ss.hasPermission('erp:account:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportAccountExcel(@Valid ErpAccountPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = accountService.getAccountPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "结算账户.xls", "数据", ErpAccountRespVO.class, + BeanUtils.toBean(list, ErpAccountRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java new file mode 100644 index 0000000..58ec2fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java @@ -0,0 +1,153 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.finance.ErpFinancePaymentService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +@Tag(name = "管理后台 - ERP 付款单") +@RestController +@RequestMapping("/erp/finance-payment") +@Validated +public class ErpFinancePaymentController { + + @Resource + private ErpFinancePaymentService financePaymentService; + @Resource + private ErpSupplierService supplierService; + @Resource + private ErpAccountService accountService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建付款单") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:create')") + public CommonResult createFinancePayment(@Valid @RequestBody ErpFinancePaymentSaveReqVO createReqVO) { + return success(financePaymentService.createFinancePayment(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新付款单") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:update')") + public CommonResult updateFinancePayment(@Valid @RequestBody ErpFinancePaymentSaveReqVO updateReqVO) { + financePaymentService.updateFinancePayment(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新付款单的状态") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:update-status')") + public CommonResult updateFinancePaymentStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + financePaymentService.updateFinancePaymentStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除付款单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:finance-payment:delete')") + public CommonResult deleteFinancePayment(@RequestParam("ids") List ids) { + financePaymentService.deleteFinancePayment(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得付款单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:query')") + public CommonResult getFinancePayment(@RequestParam("id") Long id) { + ErpFinancePaymentDO payment = financePaymentService.getFinancePayment(id); + if (payment == null) { + return success(null); + } + List paymentItemList = financePaymentService.getFinancePaymentItemListByPaymentId(id); + return success(BeanUtils.toBean(payment, ErpFinancePaymentRespVO.class, financePaymentVO -> + financePaymentVO.setItems(BeanUtils.toBean(paymentItemList, ErpFinancePaymentRespVO.Item.class)))); + } + + @GetMapping("/page") + @Operation(summary = "获得付款单分页") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:query')") + public CommonResult> getFinancePaymentPage(@Valid ErpFinancePaymentPageReqVO pageReqVO) { + PageResult pageResult = financePaymentService.getFinancePaymentPage(pageReqVO); + return success(buildFinancePaymentVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出付款单 Excel") + @PreAuthorize("@ss.hasPermission('erp:finance-payment:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportFinancePaymentExcel(@Valid ErpFinancePaymentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildFinancePaymentVOPageResult(financePaymentService.getFinancePaymentPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "付款单.xls", "数据", ErpFinancePaymentRespVO.class, list); + } + + private PageResult buildFinancePaymentVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 付款项 + List paymentItemList = financePaymentService.getFinancePaymentItemListByPaymentIds( + convertSet(pageResult.getList(), ErpFinancePaymentDO::getId)); + Map> financePaymentItemMap = convertMultiMap(paymentItemList, ErpFinancePaymentItemDO::getPaymentId); + // 1.2 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpFinancePaymentDO::getSupplierId)); + // 1.3 结算账户信息 + Map accountMap = accountService.getAccountMap( + convertSet(pageResult.getList(), ErpFinancePaymentDO::getAccountId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getFinanceUserId()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpFinancePaymentRespVO.class, payment -> { + payment.setItems(BeanUtils.toBean(financePaymentItemMap.get(payment.getId()), ErpFinancePaymentRespVO.Item.class)); + MapUtils.findAndThen(supplierMap, payment.getSupplierId(), supplier -> payment.setSupplierName(supplier.getName())); + MapUtils.findAndThen(accountMap, payment.getAccountId(), account -> payment.setAccountName(account.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(payment.getCreator()), user -> payment.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, payment.getFinanceUserId(), user -> payment.setFinanceUserName(user.getNickname())); + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java new file mode 100644 index 0000000..173f40a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java @@ -0,0 +1,153 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.finance.ErpFinanceReceiptService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +@Tag(name = "管理后台 - ERP 收款单") +@RestController +@RequestMapping("/erp/finance-receipt") +@Validated +public class ErpFinanceReceiptController { + + @Resource + private ErpFinanceReceiptService financeReceiptService; + @Resource + private ErpCustomerService customerService; + @Resource + private ErpAccountService accountService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建收款单") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:create')") + public CommonResult createFinanceReceipt(@Valid @RequestBody ErpFinanceReceiptSaveReqVO createReqVO) { + return success(financeReceiptService.createFinanceReceipt(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新收款单") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:update')") + public CommonResult updateFinanceReceipt(@Valid @RequestBody ErpFinanceReceiptSaveReqVO updateReqVO) { + financeReceiptService.updateFinanceReceipt(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新收款单的状态") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:update-status')") + public CommonResult updateFinanceReceiptStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + financeReceiptService.updateFinanceReceiptStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除收款单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:delete')") + public CommonResult deleteFinanceReceipt(@RequestParam("ids") List ids) { + financeReceiptService.deleteFinanceReceipt(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得收款单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:query')") + public CommonResult getFinanceReceipt(@RequestParam("id") Long id) { + ErpFinanceReceiptDO receipt = financeReceiptService.getFinanceReceipt(id); + if (receipt == null) { + return success(null); + } + List receiptItemList = financeReceiptService.getFinanceReceiptItemListByReceiptId(id); + return success(BeanUtils.toBean(receipt, ErpFinanceReceiptRespVO.class, financeReceiptVO -> + financeReceiptVO.setItems(BeanUtils.toBean(receiptItemList, ErpFinanceReceiptRespVO.Item.class)))); + } + + @GetMapping("/page") + @Operation(summary = "获得收款单分页") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:query')") + public CommonResult> getFinanceReceiptPage(@Valid ErpFinanceReceiptPageReqVO pageReqVO) { + PageResult pageResult = financeReceiptService.getFinanceReceiptPage(pageReqVO); + return success(buildFinanceReceiptVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出收款单 Excel") + @PreAuthorize("@ss.hasPermission('erp:finance-receipt:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportFinanceReceiptExcel(@Valid ErpFinanceReceiptPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildFinanceReceiptVOPageResult(financeReceiptService.getFinanceReceiptPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "收款单.xls", "数据", ErpFinanceReceiptRespVO.class, list); + } + + private PageResult buildFinanceReceiptVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 收款项 + List receiptItemList = financeReceiptService.getFinanceReceiptItemListByReceiptIds( + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getId)); + Map> financeReceiptItemMap = convertMultiMap(receiptItemList, ErpFinanceReceiptItemDO::getReceiptId); + // 1.2 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getCustomerId)); + // 1.3 结算账户信息 + Map accountMap = accountService.getAccountMap( + convertSet(pageResult.getList(), ErpFinanceReceiptDO::getAccountId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getFinanceUserId()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpFinanceReceiptRespVO.class, receipt -> { + receipt.setItems(BeanUtils.toBean(financeReceiptItemMap.get(receipt.getId()), ErpFinanceReceiptRespVO.Item.class)); + MapUtils.findAndThen(customerMap, receipt.getCustomerId(), customer -> receipt.setCustomerName(customer.getName())); + MapUtils.findAndThen(accountMap, receipt.getAccountId(), account -> receipt.setAccountName(account.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(receipt.getCreator()), user -> receipt.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, receipt.getFinanceUserId(), user -> receipt.setFinanceUserName(user.getNickname())); + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountPageReqVO.java new file mode 100644 index 0000000..3e1fa72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 结算账户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpAccountPageReqVO extends PageParam { + + @Schema(description = "账户编码", example = "A88") + private String no; + + @Schema(description = "账户名称", example = "张三") + private String name; + + @Schema(description = "备注", example = "随便") + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountRespVO.java new file mode 100644 index 0000000..a1c2e95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountRespVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 结算账户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpAccountRespVO { + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28684") + @ExcelProperty("结算账户编号") + private Long id; + + @Schema(description = "账户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("账户名称") + private String name; + + @Schema(description = "账户编码", example = "A88") + @ExcelProperty("账户编码") + private String no; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("开启状态") + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "是否默认", example = "1") + @ExcelProperty("是否默认") + private Boolean defaultStatus; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountSaveReqVO.java new file mode 100644 index 0000000..5b698be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/account/ErpAccountSaveReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - ERP 结算账户新增/修改 Request VO") +@Data +public class ErpAccountSaveReqVO { + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28684") + private Long id; + + @Schema(description = "账户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "账户名称不能为空") + private String name; + + @Schema(description = "账户编码", example = "A88") + private String no; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + @InEnum(value = CommonStatusEnum.class) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "排序不能为空") + private Integer sort; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentPageReqVO.java new file mode 100644 index 0000000..b5618ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 付款单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpFinancePaymentPageReqVO extends PageParam { + + @Schema(description = "付款单编号", example = "XS001") + private String no; + + @Schema(description = "付款时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] paymentTime; + + @Schema(description = "供应商编号", example = "1724") + private Long supplierId; + + @Schema(description = "创建者", example = "666") + private String creator; + + @Schema(description = "财务人员编号", example = "888") + private String financeUserId; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "付款状态", example = "2") + private Integer status; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "业务编号", example = "123") + private String bizNo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java new file mode 100644 index 0000000..2eeac53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 付款单 Response VO") +@Data +public class ErpFinancePaymentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752") + private Long id; + + @Schema(description = "付款单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "FKD888") + private String no; + + @Schema(description = "付款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "付款时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime paymentTime; + + @Schema(description = "财务人员编号", example = "19690") + private Long financeUserId; + @Schema(description = "财务人员名称", example = "张三") + private String financeUserName; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399") + private Long supplierId; + @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小番茄公司") + private String supplierName; + + @Schema(description = "付款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989") + private Long accountId; + @Schema(description = "付款账户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String accountName; + + @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "13832") + private BigDecimal totalPrice; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600") + private BigDecimal discountPrice; + + @Schema(description = "实际价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal paymentPrice; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "付款项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Data + public static class Item { + + @Schema(description = "付款项编号", example = "11756") + private Long id; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long bizId; + + @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private String bizNo; + + @Schema(description = "应付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal totalPrice; + + @Schema(description = "已付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal paidPrice; + + @Schema(description = "本次付款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "本次付款不能为空") + private BigDecimal paymentPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentSaveReqVO.java new file mode 100644 index 0000000..c13e54f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentSaveReqVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 付款单新增/修改 Request VO") +@Data +public class ErpFinancePaymentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752") + private Long id; + + @Schema(description = "付款时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "付款时间不能为空") + private LocalDateTime paymentTime; + + @Schema(description = "财务人员编号", example = "19690") + private Long financeUserId; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399") + @NotNull(message = "供应商编号不能为空") + private Long supplierId; + + @Schema(description = "付款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989") + @NotNull(message = "付款账户编号不能为空") + private Long accountId; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600") + @NotNull(message = "优惠金额不能为空") + private BigDecimal discountPrice; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "付款项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "付款项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "付款项编号", example = "11756") + private Long id; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "业务类型不能为空") + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "业务编号不能为空") + private Long bizId; + + @Schema(description = "已付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "已付金额不能为空") + private BigDecimal paidPrice; + + @Schema(description = "本次付款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "本次付款不能为空") + private BigDecimal paymentPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptPageReqVO.java new file mode 100644 index 0000000..d3e938c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 收款单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpFinanceReceiptPageReqVO extends PageParam { + + @Schema(description = "收款单编号", example = "XS001") + private String no; + + @Schema(description = "收款时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] receiptTime; + + @Schema(description = "客户编号", example = "1724") + private Long customerId; + + @Schema(description = "创建者", example = "666") + private String creator; + + @Schema(description = "财务人员编号", example = "888") + private String financeUserId; + + @Schema(description = "收款账户编号", example = "31189") + private Long accountId; + + @Schema(description = "收款状态", example = "2") + private Integer status; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "业务编号", example = "123") + private String bizNo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java new file mode 100644 index 0000000..cb2b95d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 收款单 Response VO") +@Data +public class ErpFinanceReceiptRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752") + private Long id; + + @Schema(description = "收款单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "FKD888") + private String no; + + @Schema(description = "收款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "收款时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime receiptTime; + + @Schema(description = "财务人员编号", example = "19690") + private Long financeUserId; + @Schema(description = "财务人员名称", example = "张三") + private String financeUserName; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399") + private Long customerId; + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小番茄公司") + private String customerName; + + @Schema(description = "收款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989") + private Long accountId; + @Schema(description = "收款账户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String accountName; + + @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "13832") + private BigDecimal totalPrice; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600") + private BigDecimal discountPrice; + + @Schema(description = "实际价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal receiptPrice; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "收款项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Data + public static class Item { + + @Schema(description = "收款项编号", example = "11756") + private Long id; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long bizId; + + @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private String bizNo; + + @Schema(description = "应收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal totalPrice; + + @Schema(description = "已收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + private BigDecimal receiptedPrice; + + @Schema(description = "本次收款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "本次收款不能为空") + private BigDecimal receiptPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptSaveReqVO.java new file mode 100644 index 0000000..e85912b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptSaveReqVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 收款单新增/修改 Request VO") +@Data +public class ErpFinanceReceiptSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752") + private Long id; + + @Schema(description = "收款时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款时间不能为空") + private LocalDateTime receiptTime; + + @Schema(description = "财务人员编号", example = "19690") + private Long financeUserId; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29399") + @NotNull(message = "客户编号不能为空") + private Long customerId; + + @Schema(description = "收款账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28989") + @NotNull(message = "收款账户编号不能为空") + private Long accountId; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "11600") + @NotNull(message = "优惠金额不能为空") + private BigDecimal discountPrice; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "收款项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "收款项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "收款项编号", example = "11756") + private Long id; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "业务类型不能为空") + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "业务编号不能为空") + private Long bizId; + + @Schema(description = "已收金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "已收金额不能为空") + private BigDecimal receiptedPrice; + + @Schema(description = "本次收款,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @NotNull(message = "本次收款不能为空") + private BigDecimal receiptPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java new file mode 100644 index 0000000..918ccad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategorySaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 产品分类") +@RestController +@RequestMapping("/erp/product-category") +@Validated +public class ErpProductCategoryController { + + @Resource + private ErpProductCategoryService productCategoryService; + + @PostMapping("/create") + @Operation(summary = "创建产品分类") + @PreAuthorize("@ss.hasPermission('erp:product-category:create')") + public CommonResult createProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO createReqVO) { + return success(productCategoryService.createProductCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品分类") + @PreAuthorize("@ss.hasPermission('erp:product-category:update')") + public CommonResult updateProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO updateReqVO) { + productCategoryService.updateProductCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:product-category:delete')") + public CommonResult deleteProductCategory(@RequestParam("id") Long id) { + productCategoryService.deleteProductCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:product-category:query')") + public CommonResult getProductCategory(@RequestParam("id") Long id) { + ErpProductCategoryDO category = productCategoryService.getProductCategory(id); + return success(BeanUtils.toBean(category, ErpProductCategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得产品分类列表") + @PreAuthorize("@ss.hasPermission('erp:product-category:query')") + public CommonResult> getProductCategoryList(@Valid ErpProductCategoryListReqVO listReqVO) { + List list = productCategoryService.getProductCategoryList(listReqVO); + return success(BeanUtils.toBean(list, ErpProductCategoryRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品分类精简列表", description = "只包含被开启的分类,主要用于前端的下拉选项") + public CommonResult> getProductCategorySimpleList() { + List list = productCategoryService.getProductCategoryList( + new ErpProductCategoryListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + return success(convertList(list, category -> new ErpProductCategoryRespVO() + .setId(category.getId()).setName(category.getName()).setParentId(category.getParentId()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品分类 Excel") + @PreAuthorize("@ss.hasPermission('erp:product-category:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductCategoryExcel(@Valid ErpProductCategoryListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = productCategoryService.getProductCategoryList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "产品分类.xls", "数据", ErpProductCategoryRespVO.class, + BeanUtils.toBean(list, ErpProductCategoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java new file mode 100644 index 0000000..aba64d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 产品") +@RestController +@RequestMapping("/erp/product") +@Validated +public class ErpProductController { + + @Resource + private ErpProductService productService; + + @PostMapping("/create") + @Operation(summary = "创建产品") + @PreAuthorize("@ss.hasPermission('erp:product:create')") + public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { + return success(productService.createProduct(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品") + @PreAuthorize("@ss.hasPermission('erp:product:update')") + public CommonResult updateProduct(@Valid @RequestBody ProductSaveReqVO updateReqVO) { + productService.updateProduct(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:product:delete')") + public CommonResult deleteProduct(@RequestParam("id") Long id) { + productService.deleteProduct(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:product:query')") + public CommonResult getProduct(@RequestParam("id") Long id) { + ErpProductDO product = productService.getProduct(id); + return success(BeanUtils.toBean(product, ErpProductRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品分页") + @PreAuthorize("@ss.hasPermission('erp:product:query')") + public CommonResult> getProductPage(@Valid ErpProductPageReqVO pageReqVO) { + return success(productService.getProductVOPage(pageReqVO)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") + public CommonResult> getProductSimpleList() { + List list = productService.getProductVOListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, product -> new ErpProductRespVO().setId(product.getId()) + .setName(product.getName()).setBarCode(product.getBarCode()) + .setCategoryId(product.getCategoryId()).setCategoryName(product.getCategoryName()) + .setUnitId(product.getUnitId()).setUnitName(product.getUnitName()) + .setPurchasePrice(product.getPurchasePrice()).setSalePrice(product.getSalePrice()).setMinPrice(product.getMinPrice()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品 Excel") + @PreAuthorize("@ss.hasPermission('erp:product:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductExcel(@Valid ErpProductPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult pageResult = productService.getProductVOPage(pageReqVO); + // 导出 Excel + ExcelUtils.write(response, "产品.xls", "数据", ErpProductRespVO.class, + pageResult.getList()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java new file mode 100644 index 0000000..ae66baa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 产品单位") +@RestController +@RequestMapping("/erp/product-unit") +@Validated +public class ErpProductUnitController { + + @Resource + private ErpProductUnitService productUnitService; + + @PostMapping("/create") + @Operation(summary = "创建产品单位") + @PreAuthorize("@ss.hasPermission('erp:product-unit:create')") + public CommonResult createProductUnit(@Valid @RequestBody ErpProductUnitSaveReqVO createReqVO) { + return success(productUnitService.createProductUnit(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品单位") + @PreAuthorize("@ss.hasPermission('erp:product-unit:update')") + public CommonResult updateProductUnit(@Valid @RequestBody ErpProductUnitSaveReqVO updateReqVO) { + productUnitService.updateProductUnit(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品单位") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:product-unit:delete')") + public CommonResult deleteProductUnit(@RequestParam("id") Long id) { + productUnitService.deleteProductUnit(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品单位") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:product-unit:query')") + public CommonResult getProductUnit(@RequestParam("id") Long id) { + ErpProductUnitDO productUnit = productUnitService.getProductUnit(id); + return success(BeanUtils.toBean(productUnit, ErpProductUnitRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品单位分页") + @PreAuthorize("@ss.hasPermission('erp:product-unit:query')") + public CommonResult> getProductUnitPage(@Valid ErpProductUnitPageReqVO pageReqVO) { + PageResult pageResult = productUnitService.getProductUnitPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpProductUnitRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品单位精简列表", description = "只包含被开启的单位,主要用于前端的下拉选项") + public CommonResult> getProductUnitSimpleList() { + List list = productUnitService.getProductUnitListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, unit -> new ErpProductUnitRespVO().setId(unit.getId()).setName(unit.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品单位 Excel") + @PreAuthorize("@ss.hasPermission('erp:product-unit:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductUnitExcel(@Valid ErpProductUnitPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = productUnitService.getProductUnitPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品单位.xls", "数据", ErpProductUnitRespVO.class, + BeanUtils.toBean(list, ErpProductUnitRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryListReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryListReqVO.java new file mode 100644 index 0000000..b9b530e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryListReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - ERP 产品分类列表 Request VO") +@Data +public class ErpProductCategoryListReqVO { + + @Schema(description = "分类名称", example = "芋艿") + private String name; + + @Schema(description = "开启状态", example = "1") + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryRespVO.java new file mode 100644 index 0000000..23d7d9e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategoryRespVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.category; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 产品分类 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpProductCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5860") + @ExcelProperty("分类编号") + private Long id; + + @Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21829") + @ExcelProperty("父分类编号") + private Long parentId; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("分类名称") + private String name; + + @Schema(description = "分类编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "S110") + @ExcelProperty("分类编码") + private String code; + + @Schema(description = "分类排序", example = "10") + @ExcelProperty("分类排序") + private Integer sort; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategorySaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategorySaveReqVO.java new file mode 100644 index 0000000..1a5ba4e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/category/ErpProductCategorySaveReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - ERP 产品分类新增/修改 Request VO") +@Data +public class ErpProductCategorySaveReqVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5860") + private Long id; + + @Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21829") + @NotNull(message = "父分类编号不能为空") + private Long parentId; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "分类名称不能为空") + private String name; + + @Schema(description = "分类编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "S110") + @NotEmpty(message = "分类编码不能为空") + private String code; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "分类排序不能为空") + private Integer sort; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java new file mode 100644 index 0000000..de4f814 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 产品分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpProductPageReqVO extends PageParam { + + @Schema(description = "产品名称", example = "李四") + private String name; + + @Schema(description = "产品分类编号", example = "11161") + private Long categoryId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java new file mode 100644 index 0000000..9be9bc2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 产品 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpProductRespVO { + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15672") + @ExcelProperty("产品编号") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("产品名称") + private String name; + + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110") + @ExcelProperty("产品条码") + private String barCode; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") + private Long categoryId; + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869") + private Long unitId; + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; + + @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("产品状态") + private Integer status; + + @Schema(description = "产品规格", example = "红色") + @ExcelProperty("产品规格") + private String standard; + + @Schema(description = "产品备注", example = "你猜") + @ExcelProperty("产品备注") + private String remark; + + @Schema(description = "保质期天数", example = "10") + @ExcelProperty("保质期天数") + private Integer expiryDay; + + @Schema(description = "基础重量(kg)", example = "1.00") + @ExcelProperty("基础重量(kg)") + private BigDecimal weight; + + @Schema(description = "采购价格,单位:元", example = "10.30") + @ExcelProperty("采购价格,单位:元") + private BigDecimal purchasePrice; + + @Schema(description = "销售价格,单位:元", example = "74.32") + @ExcelProperty("销售价格,单位:元") + private BigDecimal salePrice; + + @Schema(description = "最低价格,单位:元", example = "161.87") + @ExcelProperty("最低价格,单位:元") + private BigDecimal minPrice; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java new file mode 100644 index 0000000..cd34e88 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 产品新增/修改 Request VO") +@Data +public class ProductSaveReqVO { + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15672") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "产品名称不能为空") + private String name; + + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110") + @NotEmpty(message = "产品条码不能为空") + private String barCode; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") + @NotNull(message = "产品分类编号不能为空") + private Long categoryId; + + @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869") + @NotNull(message = "单位编号不能为空") + private Long unitId; + + @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "产品状态不能为空") + private Integer status; + + @Schema(description = "产品规格", example = "红色") + private String standard; + + @Schema(description = "产品备注", example = "你猜") + private String remark; + + @Schema(description = "保质期天数", example = "10") + private Integer expiryDay; + + @Schema(description = "基础重量(kg)", example = "1.00") + private BigDecimal weight; + + @Schema(description = "采购价格,单位:元", example = "10.30") + private BigDecimal purchasePrice; + + @Schema(description = "销售价格,单位:元", example = "74.32") + private BigDecimal salePrice; + + @Schema(description = "最低价格,单位:元", example = "161.87") + private BigDecimal minPrice; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java new file mode 100644 index 0000000..87119c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 产品单位分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpProductUnitPageReqVO extends PageParam { + + @Schema(description = "单位名字", example = "芋艿") + private String name; + + @Schema(description = "单位状态", example = "1") + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java new file mode 100644 index 0000000..06f6049 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 产品单位 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpProductUnitRespVO { + + @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31254") + @ExcelProperty("单位编号") + private Long id; + + @Schema(description = "单位名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("单位名字") + private String name; + + @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("单位状态") + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java new file mode 100644 index 0000000..dd45478 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - ERP 产品单位新增/修改 Request VO") +@Data +public class ErpProductUnitSaveReqVO { + + @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31254") + private Long id; + + @Schema(description = "单位名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "单位名字不能为空") + private String name; + + @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "单位状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java new file mode 100644 index 0000000..4aa485a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 采购入库") +@RestController +@RequestMapping("/erp/purchase-in") +@Validated +public class ErpPurchaseInController { + + @Resource + private ErpPurchaseInService purchaseInService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建采购入库") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:create')") + public CommonResult createPurchaseIn(@Valid @RequestBody ErpPurchaseInSaveReqVO createReqVO) { + return success(purchaseInService.createPurchaseIn(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新采购入库") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:update')") + public CommonResult updatePurchaseIn(@Valid @RequestBody ErpPurchaseInSaveReqVO updateReqVO) { + purchaseInService.updatePurchaseIn(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新采购入库的状态") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:update-status')") + public CommonResult updatePurchaseInStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + purchaseInService.updatePurchaseInStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除采购入库") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:purchase-in:delete')") + public CommonResult deletePurchaseIn(@RequestParam("ids") List ids) { + purchaseInService.deletePurchaseIn(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得采购入库") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:query')") + public CommonResult getPurchaseIn(@RequestParam("id") Long id) { + ErpPurchaseInDO purchaseIn = purchaseInService.getPurchaseIn(id); + if (purchaseIn == null) { + return success(null); + } + List purchaseInItemList = purchaseInService.getPurchaseInItemListByInId(id); + Map productMap = productService.getProductVOMap( + convertSet(purchaseInItemList, ErpPurchaseInItemDO::getProductId)); + return success(BeanUtils.toBean(purchaseIn, ErpPurchaseInRespVO.class, purchaseInVO -> + purchaseInVO.setItems(BeanUtils.toBean(purchaseInItemList, ErpPurchaseInRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得采购入库分页") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:query')") + public CommonResult> getPurchaseInPage(@Valid ErpPurchaseInPageReqVO pageReqVO) { + PageResult pageResult = purchaseInService.getPurchaseInPage(pageReqVO); + return success(buildPurchaseInVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出采购入库 Excel") + @PreAuthorize("@ss.hasPermission('erp:purchase-in:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPurchaseInExcel(@Valid ErpPurchaseInPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildPurchaseInVOPageResult(purchaseInService.getPurchaseInPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "采购入库.xls", "数据", ErpPurchaseInRespVO.class, list); + } + + private PageResult buildPurchaseInVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 入库项 + List purchaseInItemList = purchaseInService.getPurchaseInItemListByInIds( + convertSet(pageResult.getList(), ErpPurchaseInDO::getId)); + Map> purchaseInItemMap = convertMultiMap(purchaseInItemList, ErpPurchaseInItemDO::getInId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(purchaseInItemList, ErpPurchaseInItemDO::getProductId)); + // 1.3 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpPurchaseInDO::getSupplierId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), purchaseIn -> Long.parseLong(purchaseIn.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpPurchaseInRespVO.class, purchaseIn -> { + purchaseIn.setItems(BeanUtils.toBean(purchaseInItemMap.get(purchaseIn.getId()), ErpPurchaseInRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + purchaseIn.setProductNames(CollUtil.join(purchaseIn.getItems(), ",", ErpPurchaseInRespVO.Item::getProductName)); + MapUtils.findAndThen(supplierMap, purchaseIn.getSupplierId(), supplier -> purchaseIn.setSupplierName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(purchaseIn.getCreator()), user -> purchaseIn.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java new file mode 100644 index 0000000..c3d36e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 采购订单") +@RestController +@RequestMapping("/erp/purchase-order") +@Validated +public class ErpPurchaseOrderController { + + @Resource + private ErpPurchaseOrderService purchaseOrderService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建采购订单") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:create')") + public CommonResult createPurchaseOrder(@Valid @RequestBody ErpPurchaseOrderSaveReqVO createReqVO) { + return success(purchaseOrderService.createPurchaseOrder(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新采购订单") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:update')") + public CommonResult updatePurchaseOrder(@Valid @RequestBody ErpPurchaseOrderSaveReqVO updateReqVO) { + purchaseOrderService.updatePurchaseOrder(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新采购订单的状态") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:update-status')") + public CommonResult updatePurchaseOrderStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + purchaseOrderService.updatePurchaseOrderStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除采购订单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:purchase-order:delete')") + public CommonResult deletePurchaseOrder(@RequestParam("ids") List ids) { + purchaseOrderService.deletePurchaseOrder(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得采购订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')") + public CommonResult getPurchaseOrder(@RequestParam("id") Long id) { + ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(id); + if (purchaseOrder == null) { + return success(null); + } + List purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderId(id); + Map productMap = productService.getProductVOMap( + convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId)); + return success(BeanUtils.toBean(purchaseOrder, ErpPurchaseOrderRespVO.class, purchaseOrderVO -> + purchaseOrderVO.setItems(BeanUtils.toBean(purchaseOrderItemList, ErpPurchaseOrderRespVO.Item.class, item -> { + BigDecimal purchaseCount = stockService.getStockCount(item.getProductId()); + item.setStockCount(purchaseCount != null ? purchaseCount : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得采购订单分页") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')") + public CommonResult> getPurchaseOrderPage(@Valid ErpPurchaseOrderPageReqVO pageReqVO) { + PageResult pageResult = purchaseOrderService.getPurchaseOrderPage(pageReqVO); + return success(buildPurchaseOrderVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出采购订单 Excel") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPurchaseOrderExcel(@Valid ErpPurchaseOrderPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildPurchaseOrderVOPageResult(purchaseOrderService.getPurchaseOrderPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "采购订单.xls", "数据", ErpPurchaseOrderRespVO.class, list); + } + + private PageResult buildPurchaseOrderVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 订单项 + List purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderIds( + convertSet(pageResult.getList(), ErpPurchaseOrderDO::getId)); + Map> purchaseOrderItemMap = convertMultiMap(purchaseOrderItemList, ErpPurchaseOrderItemDO::getOrderId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId)); + // 1.3 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpPurchaseOrderDO::getSupplierId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), purchaseOrder -> Long.parseLong(purchaseOrder.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpPurchaseOrderRespVO.class, purchaseOrder -> { + purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + purchaseOrder.setProductNames(CollUtil.join(purchaseOrder.getItems(), ",", ErpPurchaseOrderRespVO.Item::getProductName)); + MapUtils.findAndThen(supplierMap, purchaseOrder.getSupplierId(), supplier -> purchaseOrder.setSupplierName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java new file mode 100644 index 0000000..e72b175 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseReturnService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 采购退货") +@RestController +@RequestMapping("/erp/purchase-return") +@Validated +public class ErpPurchaseReturnController { + + @Resource + private ErpPurchaseReturnService purchaseReturnService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建采购退货") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:create')") + public CommonResult createPurchaseReturn(@Valid @RequestBody ErpPurchaseReturnSaveReqVO createReqVO) { + return success(purchaseReturnService.createPurchaseReturn(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新采购退货") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:update')") + public CommonResult updatePurchaseReturn(@Valid @RequestBody ErpPurchaseReturnSaveReqVO updateReqVO) { + purchaseReturnService.updatePurchaseReturn(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新采购退货的状态") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:update-status')") + public CommonResult updatePurchaseReturnStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + purchaseReturnService.updatePurchaseReturnStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除采购退货") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:purchase-return:delete')") + public CommonResult deletePurchaseReturn(@RequestParam("ids") List ids) { + purchaseReturnService.deletePurchaseReturn(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得采购退货") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:query')") + public CommonResult getPurchaseReturn(@RequestParam("id") Long id) { + ErpPurchaseReturnDO purchaseReturn = purchaseReturnService.getPurchaseReturn(id); + if (purchaseReturn == null) { + return success(null); + } + List purchaseReturnItemList = purchaseReturnService.getPurchaseReturnItemListByReturnId(id); + Map productMap = productService.getProductVOMap( + convertSet(purchaseReturnItemList, ErpPurchaseReturnItemDO::getProductId)); + return success(BeanUtils.toBean(purchaseReturn, ErpPurchaseReturnRespVO.class, purchaseReturnVO -> + purchaseReturnVO.setItems(BeanUtils.toBean(purchaseReturnItemList, ErpPurchaseReturnRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得采购退货分页") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:query')") + public CommonResult> getPurchaseReturnPage(@Valid ErpPurchaseReturnPageReqVO pageReqVO) { + PageResult pageResult = purchaseReturnService.getPurchaseReturnPage(pageReqVO); + return success(buildPurchaseReturnVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出采购退货 Excel") + @PreAuthorize("@ss.hasPermission('erp:purchase-return:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPurchaseReturnExcel(@Valid ErpPurchaseReturnPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildPurchaseReturnVOPageResult(purchaseReturnService.getPurchaseReturnPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "采购退货.xls", "数据", ErpPurchaseReturnRespVO.class, list); + } + + private PageResult buildPurchaseReturnVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 退货项 + List purchaseReturnItemList = purchaseReturnService.getPurchaseReturnItemListByReturnIds( + convertSet(pageResult.getList(), ErpPurchaseReturnDO::getId)); + Map> purchaseReturnItemMap = convertMultiMap(purchaseReturnItemList, ErpPurchaseReturnItemDO::getReturnId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(purchaseReturnItemList, ErpPurchaseReturnItemDO::getProductId)); + // 1.3 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpPurchaseReturnDO::getSupplierId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), purchaseReturn -> Long.parseLong(purchaseReturn.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpPurchaseReturnRespVO.class, purchaseReturn -> { + purchaseReturn.setItems(BeanUtils.toBean(purchaseReturnItemMap.get(purchaseReturn.getId()), ErpPurchaseReturnRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + purchaseReturn.setProductNames(CollUtil.join(purchaseReturn.getItems(), ",", ErpPurchaseReturnRespVO.Item::getProductName)); + MapUtils.findAndThen(supplierMap, purchaseReturn.getSupplierId(), supplier -> purchaseReturn.setSupplierName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(purchaseReturn.getCreator()), user -> purchaseReturn.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java new file mode 100644 index 0000000..affc0ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 供应商") +@RestController +@RequestMapping("/erp/supplier") +@Validated +public class ErpSupplierController { + + @Resource + private ErpSupplierService supplierService; + + @PostMapping("/create") + @Operation(summary = "创建供应商") + @PreAuthorize("@ss.hasPermission('erp:supplier:create')") + public CommonResult createSupplier(@Valid @RequestBody ErpSupplierSaveReqVO createReqVO) { + return success(supplierService.createSupplier(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新供应商") + @PreAuthorize("@ss.hasPermission('erp:supplier:update')") + public CommonResult updateSupplier(@Valid @RequestBody ErpSupplierSaveReqVO updateReqVO) { + supplierService.updateSupplier(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除供应商") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:supplier:delete')") + public CommonResult deleteSupplier(@RequestParam("id") Long id) { + supplierService.deleteSupplier(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得供应商") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:supplier:query')") + public CommonResult getSupplier(@RequestParam("id") Long id) { + ErpSupplierDO supplier = supplierService.getSupplier(id); + return success(BeanUtils.toBean(supplier, ErpSupplierRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得供应商分页") + @PreAuthorize("@ss.hasPermission('erp:supplier:query')") + public CommonResult> getSupplierPage(@Valid ErpSupplierPageReqVO pageReqVO) { + PageResult pageResult = supplierService.getSupplierPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpSupplierRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得供应商精简列表", description = "只包含被开启的供应商,主要用于前端的下拉选项") + public CommonResult> getSupplierSimpleList() { + List list = supplierService.getSupplierListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, supplier -> new ErpSupplierRespVO().setId(supplier.getId()).setName(supplier.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出供应商 Excel") + @PreAuthorize("@ss.hasPermission('erp:supplier:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSupplierExcel(@Valid ErpSupplierPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = supplierService.getSupplierPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "供应商.xls", "数据", ErpSupplierRespVO.class, + BeanUtils.toBean(list, ErpSupplierRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInPageReqVO.java new file mode 100644 index 0000000..e84607c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInPageReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 采购入库分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpPurchaseInPageReqVO extends PageParam { + + public static final Integer PAYMENT_STATUS_NONE = 0; + public static final Integer PAYMENT_STATUS_PART = 1; + public static final Integer PAYMENT_STATUS_ALL = 2; + + @Schema(description = "采购单编号", example = "XS001") + private String no; + + @Schema(description = "供应商编号", example = "1724") + private Long supplierId; + + @Schema(description = "入库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] inTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "入库状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "结算账号编号", example = "1") + private Long accountId; + + @Schema(description = "付款状态", example = "1") + private Integer paymentStatus; + + @Schema(description = "是否可付款", example = "true") + private Boolean paymentEnable; // 对应 paymentStatus = [0, 1] + + @Schema(description = "采购单号", example = "1") + private String orderNo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInRespVO.java new file mode 100644 index 0000000..530269d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInRespVO.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购入库 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpPurchaseInRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "入库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("入库单编号") + private String no; + + @Schema(description = "入库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("入库状态") + private Integer status; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long supplierId; + @Schema(description = "供应商名称", example = "芋道") + @ExcelProperty("供应商名称") + private String supplierName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("入库时间") + private LocalDateTime inTime; + + @Schema(description = "采购订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long orderId; + @Schema(description = "采购订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + private String orderNo; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + @Schema(description = "已付款金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal paymentPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "入库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "采购订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInSaveReqVO.java new file mode 100644 index 0000000..b4aa630 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/in/ErpPurchaseInSaveReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购入库新增/修改 Request VO") +@Data +public class ErpPurchaseInSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "入库时间不能为空") + private LocalDateTime inTime; + + @Schema(description = "采购订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @NotNull(message = "采购订单编号不能为空") + private Long orderId; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "其它金额,单位:元", example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "入库清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "采购订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "采购订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderPageReqVO.java new file mode 100644 index 0000000..8bf70d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderPageReqVO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 采购订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpPurchaseOrderPageReqVO extends PageParam { + + /** + * 入库状态 - 无 + */ + public static final Integer IN_STATUS_NONE = 0; + /** + * 入库状态 - 部分 + */ + public static final Integer IN_STATUS_PART = 1; + /** + * 入库状态 - 全部 + */ + public static final Integer IN_STATUS_ALL = 2; + + /** + * 退货状态 - 无 + */ + public static final Integer RETURN_STATUS_NONE = 0; + /** + * 退货状态 - 部分 + */ + public static final Integer RETURN_STATUS_PART = 1; + /** + * 退货状态 - 全部 + */ + public static final Integer RETURN_STATUS_ALL = 2; + + @Schema(description = "采购单编号", example = "XS001") + private String no; + + @Schema(description = "供应商编号", example = "1724") + private Long supplierId; + + @Schema(description = "采购时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] orderTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "采购状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "入库状态", example = "2") + private Integer inStatus; + + @Schema(description = "退货状态", example = "2") + private Integer returnStatus; + + @Schema(description = "是否可入库", example = "true") + private Boolean inEnable; + + @Schema(description = "是否可退货", example = "true") + private Boolean returnEnable; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java new file mode 100644 index 0000000..2e57516 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java @@ -0,0 +1,152 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购订单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpPurchaseOrderRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "采购单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("采购单编号") + private String no; + + @Schema(description = "采购状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("采购状态") + private Integer status; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long supplierId; + @Schema(description = "供应商名称", example = "芋道") + @ExcelProperty("供应商名称") + private String supplierName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "采购时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("采购时间") + private LocalDateTime orderTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal depositPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + // ========== 采购入库 ========== + + @Schema(description = "采购入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal inCount; + + // ========== 采购退货(出库)) ========== + + @Schema(description = "采购退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal returnCount; + + @Data + public static class Item { + + @Schema(description = "订单项编号", example = "11756") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 采购入库 ========== + + @Schema(description = "采购入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal inCount; + + // ========== 采购退货(入库)) ========== + + @Schema(description = "采购退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal returnCount; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderSaveReqVO.java new file mode 100644 index 0000000..78b4d2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderSaveReqVO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购订单新增/修改 Request VO") +@Data +public class ErpPurchaseOrderSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + @NotNull(message = "供应商编号不能为空") + private Long supplierId; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "采购时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "采购时间不能为空") + private LocalDateTime orderTime; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "定金金额,单位:元", example = "7127") + private BigDecimal depositPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "订单清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "订单项编号", example = "11756") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnPageReqVO.java new file mode 100644 index 0000000..a534d2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnPageReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 采购退货分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpPurchaseReturnPageReqVO extends PageParam { + + public static final Integer REFUND_STATUS_NONE = 0; + public static final Integer REFUND_STATUS_PART = 1; + public static final Integer REFUND_STATUS_ALL = 2; + + @Schema(description = "采购单编号", example = "XS001") + private String no; + + @Schema(description = "供应商编号", example = "1724") + private Long supplierId; + + @Schema(description = "退货时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] returnTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "退货状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "结算账号编号", example = "1") + private Long accountId; + + @Schema(description = "采购单号", example = "1") + private String orderNo; + + @Schema(description = "退款状态", example = "1") + private Integer refundStatus; + + @Schema(description = "是否可退款", example = "true") + private Boolean refundEnable; // 对应 refundStatus = [0, 1] + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnRespVO.java new file mode 100644 index 0000000..1d20e43 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnRespVO.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购退货 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpPurchaseReturnRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "退货单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("退货单编号") + private String no; + + @Schema(description = "退货状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("退货状态") + private Integer status; + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long supplierId; + @Schema(description = "供应商名称", example = "芋道") + @ExcelProperty("供应商名称") + private String supplierName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "退货时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("退货时间") + private LocalDateTime returnTime; + + @Schema(description = "采购订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long orderId; + @Schema(description = "采购订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + private String orderNo; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + @Schema(description = "已退款金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal refundPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "退货项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "退货项编号", example = "11756") + private Long id; + + @Schema(description = "采购订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnSaveReqVO.java new file mode 100644 index 0000000..0d6e554 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/returns/ErpPurchaseReturnSaveReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 采购退货新增/修改 Request VO") +@Data +public class ErpPurchaseReturnSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "退货时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "退货时间不能为空") + private LocalDateTime returnTime; + + @Schema(description = "采购订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @NotNull(message = "采购订单编号不能为空") + private Long orderId; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "其它金额,单位:元", example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "退货清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "退货项编号", example = "11756") + private Long id; + + @Schema(description = "采购订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "采购订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java new file mode 100644 index 0000000..229ab63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 供应商分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpSupplierPageReqVO extends PageParam { + + @Schema(description = "供应商名称", example = "芋道源码") + private String name; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + private String telephone; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java new file mode 100644 index 0000000..5ba5892 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 供应商 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpSupplierRespVO { + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17791") + @ExcelProperty("供应商编号") + private Long id; + + @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @ExcelProperty("供应商名称") + private String name; + + @Schema(description = "联系人", example = "芋艿") + @ExcelProperty("联系人") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + @ExcelProperty("联系电话") + private String telephone; + + @Schema(description = "电子邮箱", example = "76853@qq.com") + @ExcelProperty("电子邮箱") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + @ExcelProperty("传真") + private String fax; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + @ExcelProperty("纳税人识别号") + private String taxNo; + + @Schema(description = "税率", example = "10") + @ExcelProperty("税率") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "张三") + @ExcelProperty("开户行") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + @ExcelProperty("开户账号") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + @ExcelProperty("开户地址") + private String bankAddress; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java new file mode 100644 index 0000000..3c26ba9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/supplier/ErpSupplierSaveReqVO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 供应商新增/修改 Request VO") +@Data +public class ErpSupplierSaveReqVO { + + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17791") + private Long id; + + @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotEmpty(message = "供应商名称不能为空") + private String name; + + @Schema(description = "联系人", example = "芋艿") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @Mobile + private String mobile; + + @Schema(description = "联系电话", example = "18818288888") + @Telephone + private String telephone; + + @Schema(description = "电子邮箱", example = "76853@qq.com") + @Email + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + private String fax; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + @InEnum(value = CommonStatusEnum.class) + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + private String taxNo; + + @Schema(description = "税率", example = "10") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "张三") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + private String bankAddress; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java new file mode 100644 index 0000000..5a1c4a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 客户") +@RestController +@RequestMapping("/erp/customer") +@Validated +public class ErpCustomerController { + + @Resource + private ErpCustomerService customerService; + + @PostMapping("/create") + @Operation(summary = "创建客户") + @PreAuthorize("@ss.hasPermission('erp:customer:create')") + public CommonResult createCustomer(@Valid @RequestBody ErpCustomerSaveReqVO createReqVO) { + return success(customerService.createCustomer(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新客户") + @PreAuthorize("@ss.hasPermission('erp:customer:update')") + public CommonResult updateCustomer(@Valid @RequestBody ErpCustomerSaveReqVO updateReqVO) { + customerService.updateCustomer(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除客户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:customer:delete')") + public CommonResult deleteCustomer(@RequestParam("id") Long id) { + customerService.deleteCustomer(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得客户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:customer:query')") + public CommonResult getCustomer(@RequestParam("id") Long id) { + ErpCustomerDO customer = customerService.getCustomer(id); + return success(BeanUtils.toBean(customer, ErpCustomerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得客户分页") + @PreAuthorize("@ss.hasPermission('erp:customer:query')") + public CommonResult> getCustomerPage(@Valid ErpCustomerPageReqVO pageReqVO) { + PageResult pageResult = customerService.getCustomerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpCustomerRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得客户精简列表", description = "只包含被开启的客户,主要用于前端的下拉选项") + public CommonResult> getCustomerSimpleList() { + List list = customerService.getCustomerListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, customer -> new ErpCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出客户 Excel") + @PreAuthorize("@ss.hasPermission('erp:customer:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportCustomerExcel(@Valid ErpCustomerPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = customerService.getCustomerPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "客户.xls", "数据", ErpCustomerRespVO.class, + BeanUtils.toBean(list, ErpCustomerRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java new file mode 100644 index 0000000..12fb1c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 销售订单") +@RestController +@RequestMapping("/erp/sale-order") +@Validated +public class ErpSaleOrderController { + + @Resource + private ErpSaleOrderService saleOrderService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建销售订单") + @PreAuthorize("@ss.hasPermission('erp:sale-out:create')") + public CommonResult createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) { + return success(saleOrderService.createSaleOrder(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新销售订单") + @PreAuthorize("@ss.hasPermission('erp:sale-out:update')") + public CommonResult updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) { + saleOrderService.updateSaleOrder(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新销售订单的状态") + @PreAuthorize("@ss.hasPermission('erp:sale-out:update-status')") + public CommonResult updateSaleOrderStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + saleOrderService.updateSaleOrderStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售订单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:sale-out:delete')") + public CommonResult deleteSaleOrder(@RequestParam("ids") List ids) { + saleOrderService.deleteSaleOrder(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:sale-out:query')") + public CommonResult getSaleOrder(@RequestParam("id") Long id) { + ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id); + if (saleOrder == null) { + return success(null); + } + List saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderId(id); + Map productMap = productService.getProductVOMap( + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); + return success(BeanUtils.toBean(saleOrder, ErpSaleOrderRespVO.class, saleOrderVO -> + saleOrderVO.setItems(BeanUtils.toBean(saleOrderItemList, ErpSaleOrderRespVO.Item.class, item -> { + BigDecimal stockCount = stockService.getStockCount(item.getProductId()); + item.setStockCount(stockCount != null ? stockCount : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得销售订单分页") + @PreAuthorize("@ss.hasPermission('erp:sale-out:query')") + public CommonResult> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) { + PageResult pageResult = saleOrderService.getSaleOrderPage(pageReqVO); + return success(buildSaleOrderVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出销售订单 Excel") + @PreAuthorize("@ss.hasPermission('erp:sale-out:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildSaleOrderVOPageResult(saleOrderService.getSaleOrderPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "销售订单.xls", "数据", ErpSaleOrderRespVO.class, list); + } + + private PageResult buildSaleOrderVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 订单项 + List saleOrderItemList = saleOrderService.getSaleOrderItemListByOrderIds( + convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); + Map> saleOrderItemMap = convertMultiMap(saleOrderItemList, ErpSaleOrderItemDO::getOrderId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(saleOrderItemList, ErpSaleOrderItemDO::getProductId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpSaleOrderDO::getCustomerId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), saleOrder -> Long.parseLong(saleOrder.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { + saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + saleOrder.setProductNames(CollUtil.join(saleOrder.getItems(), ",", ErpSaleOrderRespVO.Item::getProductName)); + MapUtils.findAndThen(customerMap, saleOrder.getCustomerId(), supplier -> saleOrder.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java new file mode 100644 index 0000000..fb3ce97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 销售出库") +@RestController +@RequestMapping("/erp/sale-out") +@Validated +public class ErpSaleOutController { + + @Resource + private ErpSaleOutService saleOutService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建销售出库") + @PreAuthorize("@ss.hasPermission('erp:sale-out:create')") + public CommonResult createSaleOut(@Valid @RequestBody ErpSaleOutSaveReqVO createReqVO) { + return success(saleOutService.createSaleOut(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新销售出库") + @PreAuthorize("@ss.hasPermission('erp:sale-out:update')") + public CommonResult updateSaleOut(@Valid @RequestBody ErpSaleOutSaveReqVO updateReqVO) { + saleOutService.updateSaleOut(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新销售出库的状态") + @PreAuthorize("@ss.hasPermission('erp:sale-out:update-status')") + public CommonResult updateSaleOutStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + saleOutService.updateSaleOutStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售出库") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:sale-out:delete')") + public CommonResult deleteSaleOut(@RequestParam("ids") List ids) { + saleOutService.deleteSaleOut(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售出库") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:sale-out:query')") + public CommonResult getSaleOut(@RequestParam("id") Long id) { + ErpSaleOutDO saleOut = saleOutService.getSaleOut(id); + if (saleOut == null) { + return success(null); + } + List saleOutItemList = saleOutService.getSaleOutItemListByOutId(id); + Map productMap = productService.getProductVOMap( + convertSet(saleOutItemList, ErpSaleOutItemDO::getProductId)); + return success(BeanUtils.toBean(saleOut, ErpSaleOutRespVO.class, saleOutVO -> + saleOutVO.setItems(BeanUtils.toBean(saleOutItemList, ErpSaleOutRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得销售出库分页") + @PreAuthorize("@ss.hasPermission('erp:sale-out:query')") + public CommonResult> getSaleOutPage(@Valid ErpSaleOutPageReqVO pageReqVO) { + PageResult pageResult = saleOutService.getSaleOutPage(pageReqVO); + return success(buildSaleOutVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出销售出库 Excel") + @PreAuthorize("@ss.hasPermission('erp:sale-out:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSaleOutExcel(@Valid ErpSaleOutPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildSaleOutVOPageResult(saleOutService.getSaleOutPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "销售出库.xls", "数据", ErpSaleOutRespVO.class, list); + } + + private PageResult buildSaleOutVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List saleOutItemList = saleOutService.getSaleOutItemListByOutIds( + convertSet(pageResult.getList(), ErpSaleOutDO::getId)); + Map> saleOutItemMap = convertMultiMap(saleOutItemList, ErpSaleOutItemDO::getOutId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(saleOutItemList, ErpSaleOutItemDO::getProductId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpSaleOutDO::getCustomerId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), stockOut -> Long.parseLong(stockOut.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpSaleOutRespVO.class, saleOut -> { + saleOut.setItems(BeanUtils.toBean(saleOutItemMap.get(saleOut.getId()), ErpSaleOutRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + saleOut.setProductNames(CollUtil.join(saleOut.getItems(), ",", ErpSaleOutRespVO.Item::getProductName)); + MapUtils.findAndThen(customerMap, saleOut.getCustomerId(), supplier -> saleOut.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(saleOut.getCreator()), user -> saleOut.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java new file mode 100644 index 0000000..b3d7837 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleReturnService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 销售退货") +@RestController +@RequestMapping("/erp/sale-return") +@Validated +public class ErpSaleReturnController { + + @Resource + private ErpSaleReturnService saleReturnService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建销售退货") + @PreAuthorize("@ss.hasPermission('erp:sale-return:create')") + public CommonResult createSaleReturn(@Valid @RequestBody ErpSaleReturnSaveReqVO createReqVO) { + return success(saleReturnService.createSaleReturn(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新销售退货") + @PreAuthorize("@ss.hasPermission('erp:sale-return:update')") + public CommonResult updateSaleReturn(@Valid @RequestBody ErpSaleReturnSaveReqVO updateReqVO) { + saleReturnService.updateSaleReturn(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新销售退货的状态") + @PreAuthorize("@ss.hasPermission('erp:sale-return:update-status')") + public CommonResult updateSaleReturnStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + saleReturnService.updateSaleReturnStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售退货") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:sale-return:delete')") + public CommonResult deleteSaleReturn(@RequestParam("ids") List ids) { + saleReturnService.deleteSaleReturn(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售退货") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:sale-return:query')") + public CommonResult getSaleReturn(@RequestParam("id") Long id) { + ErpSaleReturnDO saleReturn = saleReturnService.getSaleReturn(id); + if (saleReturn == null) { + return success(null); + } + List saleReturnItemList = saleReturnService.getSaleReturnItemListByReturnId(id); + Map productMap = productService.getProductVOMap( + convertSet(saleReturnItemList, ErpSaleReturnItemDO::getProductId)); + return success(BeanUtils.toBean(saleReturn, ErpSaleReturnRespVO.class, saleReturnVO -> + saleReturnVO.setItems(BeanUtils.toBean(saleReturnItemList, ErpSaleReturnRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得销售退货分页") + @PreAuthorize("@ss.hasPermission('erp:sale-return:query')") + public CommonResult> getSaleReturnPage(@Valid ErpSaleReturnPageReqVO pageReqVO) { + PageResult pageResult = saleReturnService.getSaleReturnPage(pageReqVO); + return success(buildSaleReturnVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出销售退货 Excel") + @PreAuthorize("@ss.hasPermission('erp:sale-return:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSaleReturnExcel(@Valid ErpSaleReturnPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildSaleReturnVOPageResult(saleReturnService.getSaleReturnPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "销售退货.xls", "数据", ErpSaleReturnRespVO.class, list); + } + + private PageResult buildSaleReturnVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 退货项 + List saleReturnItemList = saleReturnService.getSaleReturnItemListByReturnIds( + convertSet(pageResult.getList(), ErpSaleReturnDO::getId)); + Map> saleReturnItemMap = convertMultiMap(saleReturnItemList, ErpSaleReturnItemDO::getReturnId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(saleReturnItemList, ErpSaleReturnItemDO::getProductId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpSaleReturnDO::getCustomerId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), saleReturn -> Long.parseLong(saleReturn.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpSaleReturnRespVO.class, saleReturn -> { + saleReturn.setItems(BeanUtils.toBean(saleReturnItemMap.get(saleReturn.getId()), ErpSaleReturnRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + saleReturn.setProductNames(CollUtil.join(saleReturn.getItems(), ",", ErpSaleReturnRespVO.Item::getProductName)); + MapUtils.findAndThen(customerMap, saleReturn.getCustomerId(), supplier -> saleReturn.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(saleReturn.getCreator()), user -> saleReturn.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java new file mode 100644 index 0000000..e790cb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerPageReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 客户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpCustomerPageReqVO extends PageParam { + + @Schema(description = "客户名称", example = "张三") + private String name; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + private String telephone; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java new file mode 100644 index 0000000..f1a58a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - ERP 客户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpCustomerRespVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27520") + @ExcelProperty("客户编号") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("客户名称") + private String name; + + @Schema(description = "联系人", example = "老王") + @ExcelProperty("联系人") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + @ExcelProperty("联系电话") + private String telephone; + + @Schema(description = "电子邮箱", example = "7685323@qq.com") + @ExcelProperty("电子邮箱") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + @ExcelProperty("传真") + private String fax; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + @ExcelProperty("纳税人识别号") + private String taxNo; + + @Schema(description = "税率", example = "10") + @ExcelProperty("税率") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "芋艿") + @ExcelProperty("开户行") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + @ExcelProperty("开户账号") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + @ExcelProperty("开户地址") + private String bankAddress; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java new file mode 100644 index 0000000..bff1547 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/customer/ErpCustomerSaveReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.*; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 客户新增/修改 Request VO") +@Data +public class ErpCustomerSaveReqVO { + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27520") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "客户名称不能为空") + private String name; + + @Schema(description = "联系人", example = "老王") + private String contact; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "联系电话", example = "15601691300") + private String telephone; + + @Schema(description = "电子邮箱", example = "7685323@qq.com") + private String email; + + @Schema(description = "传真", example = "20 7123 4567") + private String fax; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "纳税人识别号", example = "91130803MA098BY05W") + private String taxNo; + + @Schema(description = "税率", example = "10") + private BigDecimal taxPercent; + + @Schema(description = "开户行", example = "芋艿") + private String bankName; + + @Schema(description = "开户账号", example = "622908212277228617") + private String bankAccount; + + @Schema(description = "开户地址", example = "兴业银行浦东支行") + private String bankAddress; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java new file mode 100644 index 0000000..84d92fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderPageReqVO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 销售订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpSaleOrderPageReqVO extends PageParam { + + /** + * 出库状态 - 无 + */ + public static final Integer OUT_STATUS_NONE = 0; + /** + * 出库状态 - 部分 + */ + public static final Integer OUT_STATUS_PART = 1; + /** + * 出库状态 - 全部 + */ + public static final Integer OUT_STATUS_ALL = 2; + + /** + * 退货状态 - 无 + */ + public static final Integer RETURN_STATUS_NONE = 0; + /** + * 退货状态 - 部分 + */ + public static final Integer RETURN_STATUS_PART = 1; + /** + * 退货状态 - 全部 + */ + public static final Integer RETURN_STATUS_ALL = 2; + + @Schema(description = "销售单编号", example = "XS001") + private String no; + + @Schema(description = "客户编号", example = "1724") + private Long customerId; + + @Schema(description = "下单时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] orderTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "销售状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "出库状态", example = "2") + private Integer outStatus; + + @Schema(description = "退货状态", example = "2") + private Integer returnStatus; + + @Schema(description = "是否可出库", example = "true") + private Boolean outEnable; + + @Schema(description = "是否可退货", example = "true") + private Boolean returnEnable; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java new file mode 100644 index 0000000..370ea09 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java @@ -0,0 +1,155 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售订单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpSaleOrderRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "销售单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("销售单编号") + private String no; + + @Schema(description = "销售状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("销售状态") + private Integer status; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("下单时间") + private LocalDateTime orderTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal depositPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + // ========== 销售出库 ========== + + @Schema(description = "销售出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal outCount; + + // ========== 销售退货(出库)) ========== + + @Schema(description = "销售退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal returnCount; + + @Data + public static class Item { + + @Schema(description = "订单项编号", example = "11756") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 销售出库 ========== + + @Schema(description = "销售出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal outCount; + + // ========== 销售退货(入库)) ========== + + @Schema(description = "销售退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal returnCount; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java new file mode 100644 index 0000000..f743a84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售订单新增/修改 Request VO") +@Data +public class ErpSaleOrderSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + @NotNull(message = "客户编号不能为空") + private Long customerId; + + @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "下单时间不能为空") + private LocalDateTime orderTime; + + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "定金金额,单位:元", example = "7127") + private BigDecimal depositPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "订单清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "订单项编号", example = "11756") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutPageReqVO.java new file mode 100644 index 0000000..5afeeea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutPageReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 销售出库分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpSaleOutPageReqVO extends PageParam { + + public static final Integer RECEIPT_STATUS_NONE = 0; + public static final Integer RECEIPT_STATUS_PART = 1; + public static final Integer RECEIPT_STATUS_ALL = 2; + + @Schema(description = "销售单编号", example = "XS001") + private String no; + + @Schema(description = "客户编号", example = "1724") + private Long customerId; + + @Schema(description = "出库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] outTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "出库状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "结算账号编号", example = "1") + private Long accountId; + + @Schema(description = "收款状态", example = "1") + private Integer receiptStatus; + + @Schema(description = "是否可收款", example = "true") + private Boolean receiptEnable; // 对应 receiptStatus = [0, 1] + + @Schema(description = "销售单号", example = "1") + private String orderNo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutRespVO.java new file mode 100644 index 0000000..f852c41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutRespVO.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售出库 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpSaleOutRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "出库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("出库单编号") + private String no; + + @Schema(description = "出库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("出库状态") + private Integer status; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "出库员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出库时间") + private LocalDateTime outTime; + + @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long orderId; + @Schema(description = "销售订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + private String orderNo; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + @Schema(description = "已收款金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal receiptPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "其它金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutSaveReqVO.java new file mode 100644 index 0000000..61a87f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/out/ErpSaleOutSaveReqVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售出库新增/修改 Request VO") +@Data +public class ErpSaleOutSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库时间不能为空") + private LocalDateTime outTime; + + @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @NotNull(message = "销售订单编号不能为空") + private Long orderId; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "其它金额,单位:元", example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "出库清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "销售订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnPageReqVO.java new file mode 100644 index 0000000..a9be73b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnPageReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 销售退货分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpSaleReturnPageReqVO extends PageParam { + + public static final Integer REFUND_STATUS_NONE = 0; + public static final Integer REFUND_STATUS_PART = 1; + public static final Integer REFUND_STATUS_ALL = 2; + + @Schema(description = "销售单编号", example = "XS001") + private String no; + + @Schema(description = "客户编号", example = "1724") + private Long customerId; + + @Schema(description = "退货时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] returnTime; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "退货状态", example = "2") + private Integer status; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "结算账号编号", example = "1") + private Long accountId; + + @Schema(description = "销售单号", example = "1") + private String orderNo; + + @Schema(description = "退款状态", example = "1") + private Integer refundStatus; + + @Schema(description = "是否可退款", example = "true") + private Boolean refundEnable; // 对应 refundStatus = [0, 1] + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnRespVO.java new file mode 100644 index 0000000..2ca3384 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnRespVO.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售退货 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpSaleReturnRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "退货单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + @ExcelProperty("退货单编号") + private String no; + + @Schema(description = "退货状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("退货状态") + private Integer status; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724") + private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89") + @ExcelProperty("结算账户编号") + private Long accountId; + + @Schema(description = "退货员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "退货时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("退货时间") + private LocalDateTime returnTime; + + @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long orderId; + @Schema(description = "销售订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001") + private String orderNo; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + @Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("最终合计价格") + private BigDecimal totalPrice; + @Schema(description = "已退款金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal refundPrice; + + @Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalProductPrice; + + @Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal totalTaxPrice; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal discountPrice; + + @Schema(description = "其它金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + @ExcelProperty("附件地址") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "退货项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "退货项编号", example = "11756") + private Long id; + + @Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "税额,单位:元", example = "100.00") + private BigDecimal taxPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnSaveReqVO.java new file mode 100644 index 0000000..44eb0df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/returns/ErpSaleReturnSaveReqVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 销售退货新增/修改 Request VO") +@Data +public class ErpSaleReturnSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + private Long id; + + @Schema(description = "结算账户编号", example = "31189") + private Long accountId; + + @Schema(description = "销售员编号", example = "1888") + private Long saleUserId; + + @Schema(description = "退货时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "退货时间不能为空") + private LocalDateTime returnTime; + + @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386") + @NotNull(message = "销售订单编号不能为空") + private Long orderId; + + @Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88") + private BigDecimal discountPercent; + + @Schema(description = "其它金额,单位:元", example = "7127") + private BigDecimal otherPrice; + + @Schema(description = "附件地址", example = "https://www.iocoder.cn") + private String fileUrl; + + @Schema(description = "备注", example = "你猜") + private String remark; + + @Schema(description = "退货清单列表") + private List items; + + @Data + public static class Item { + + @Schema(description = "退货项编号", example = "11756") + private Long id; + + @Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "销售订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品单位单位不能为空") + private Long productUnitId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "税率,百分比", example = "99.88") + private BigDecimal taxPercent; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java new file mode 100644 index 0000000..be0258d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase.ErpPurchaseSummaryRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase.ErpPurchaseTimeSummaryRespVO; +import cn.iocoder.yudao.module.erp.service.statistics.ErpPurchaseStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static cn.hutool.core.date.DatePattern.NORM_MONTH_PATTERN; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - ERP 采购统计") +@RestController +@RequestMapping("/erp/purchase-statistics") +@Validated +public class ErpPurchaseStatisticsController { + + @Resource + private ErpPurchaseStatisticsService purchaseStatisticsService; + + @GetMapping("/summary") + @Operation(summary = "获得采购统计") + @PreAuthorize("@ss.hasPermission('erp:statistics:query')") + public CommonResult getPurchaseSummary() { + LocalDateTime today = LocalDateTimeUtils.getToday(); + LocalDateTime yesterday = LocalDateTimeUtils.getYesterday(); + LocalDateTime month = LocalDateTimeUtils.getMonth(); + LocalDateTime year = LocalDateTimeUtils.getYear(); + ErpPurchaseSummaryRespVO summary = new ErpPurchaseSummaryRespVO() + .setTodayPrice(purchaseStatisticsService.getPurchasePrice(today, null)) + .setYesterdayPrice(purchaseStatisticsService.getPurchasePrice(yesterday, today)) + .setMonthPrice(purchaseStatisticsService.getPurchasePrice(month, null)) + .setYearPrice(purchaseStatisticsService.getPurchasePrice(year, null)); + return success(summary); + } + + @GetMapping("/time-summary") + @Operation(summary = "获得采购时间段统计") + @Parameter(name = "count", description = "时间段数量", example = "6") + @PreAuthorize("@ss.hasPermission('erp:statistics:query')") + public CommonResult> getPurchaseTimeSummary( + @RequestParam(value = "count", defaultValue = "6") Integer count) { + List summaryList = new ArrayList<>(); + for (int i = count - 1; i >= 0; i--) { + LocalDateTime startTime = LocalDateTimeUtils.beginOfMonth(LocalDateTime.now().minusMonths(i)); + LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(startTime); + summaryList.add(new ErpPurchaseTimeSummaryRespVO() + .setTime(LocalDateTimeUtil.format(startTime, NORM_MONTH_PATTERN)) + .setPrice(purchaseStatisticsService.getPurchasePrice(startTime, endTime))); + } + return success(summaryList); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http new file mode 100644 index 0000000..5f5cab1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http @@ -0,0 +1,11 @@ +### 请求 /erp/sale-statistics/summary 接口 => 成功 +GET {{baseUrl}}/erp/sale-statistics/summary +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +### 请求 /erp/sale-statistics/time-summary 接口 => 成功 +GET {{baseUrl}}/erp/sale-statistics/time-summary +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java new file mode 100644 index 0000000..c43c971 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleSummaryRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleTimeSummaryRespVO; +import cn.iocoder.yudao.module.erp.service.statistics.ErpSaleStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static cn.hutool.core.date.DatePattern.NORM_MONTH_PATTERN; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - ERP 销售统计") +@RestController +@RequestMapping("/erp/sale-statistics") +@Validated +public class ErpSaleStatisticsController { + + @Resource + private ErpSaleStatisticsService saleStatisticsService; + + @GetMapping("/summary") + @Operation(summary = "获得销售统计") + @PreAuthorize("@ss.hasPermission('erp:statistics:query')") + public CommonResult getSaleSummary() { + LocalDateTime today = LocalDateTimeUtils.getToday(); + LocalDateTime yesterday = LocalDateTimeUtils.getYesterday(); + LocalDateTime month = LocalDateTimeUtils.getMonth(); + LocalDateTime year = LocalDateTimeUtils.getYear(); + ErpSaleSummaryRespVO summary = new ErpSaleSummaryRespVO() + .setTodayPrice(saleStatisticsService.getSalePrice(today, null)) + .setYesterdayPrice(saleStatisticsService.getSalePrice(yesterday, today)) + .setMonthPrice(saleStatisticsService.getSalePrice(month, null)) + .setYearPrice(saleStatisticsService.getSalePrice(year, null)); + return success(summary); + } + + @GetMapping("/time-summary") + @Operation(summary = "获得销售时间段统计") + @Parameter(name = "count", description = "时间段数量", example = "6") + @PreAuthorize("@ss.hasPermission('erp:statistics:query')") + public CommonResult> getSaleTimeSummary( + @RequestParam(value = "count", defaultValue = "6") Integer count) { + List summaryList = new ArrayList<>(); + for (int i = count - 1; i >= 0; i--) { + LocalDateTime startTime = LocalDateTimeUtils.beginOfMonth(LocalDateTime.now().minusMonths(i)); + LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(startTime); + summaryList.add(new ErpSaleTimeSummaryRespVO() + .setTime(LocalDateTimeUtil.format(startTime, NORM_MONTH_PATTERN)) + .setPrice(saleStatisticsService.getSalePrice(startTime, endTime))); + } + return success(summaryList); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java new file mode 100644 index 0000000..22635e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 采购全局统计 Response VO") +@Data +public class ErpPurchaseSummaryRespVO { + + @Schema(description = "今日采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal todayPrice; + + @Schema(description = "昨日采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private BigDecimal yesterdayPrice; + + @Schema(description = "本月采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal monthPrice; + + @Schema(description = "今年采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "88888") + private BigDecimal yearPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java new file mode 100644 index 0000000..15ae817 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 采购某个时间段的统计 Response VO") +@Data +public class ErpPurchaseTimeSummaryRespVO { + + @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-03") + private String time; + + @Schema(description = "采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java new file mode 100644 index 0000000..575d7da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 销售全局统计 Response VO") +@Data +public class ErpSaleSummaryRespVO { + + @Schema(description = "今日销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal todayPrice; + + @Schema(description = "昨日销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private BigDecimal yesterdayPrice; + + @Schema(description = "本月销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal monthPrice; + + @Schema(description = "今年销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "88888") + private BigDecimal yearPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java new file mode 100644 index 0000000..48b9b6e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 销售某个时间段的统计 Response VO") +@Data +public class ErpSaleTimeSummaryRespVO { + + @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-03") + private String time; + + @Schema(description = "销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private BigDecimal price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java new file mode 100644 index 0000000..e2a45ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockCheckService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 库存调拨单") +@RestController +@RequestMapping("/erp/stock-check") +@Validated +public class ErpStockCheckController { + + @Resource + private ErpStockCheckService stockCheckService; + @Resource + private ErpProductService productService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-check:create')") + public CommonResult createStockCheck(@Valid @RequestBody ErpStockCheckSaveReqVO createReqVO) { + return success(stockCheckService.createStockCheck(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-check:update')") + public CommonResult updateStockCheck(@Valid @RequestBody ErpStockCheckSaveReqVO updateReqVO) { + stockCheckService.updateStockCheck(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新库存调拨单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-check:update-status')") + public CommonResult updateStockCheckStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockCheckService.updateStockCheckStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除库存调拨单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-check:delete')") + public CommonResult deleteStockCheck(@RequestParam("ids") List ids) { + stockCheckService.deleteStockCheck(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得库存调拨单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-check:query')") + public CommonResult getStockCheck(@RequestParam("id") Long id) { + ErpStockCheckDO stockCheck = stockCheckService.getStockCheck(id); + if (stockCheck == null) { + return success(null); + } + List stockCheckItemList = stockCheckService.getStockCheckItemListByCheckId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockCheckItemList, ErpStockCheckItemDO::getProductId)); + return success(BeanUtils.toBean(stockCheck, ErpStockCheckRespVO.class, stockCheckVO -> + stockCheckVO.setItems(BeanUtils.toBean(stockCheckItemList, ErpStockCheckRespVO.Item.class, item -> + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))))); + } + + @GetMapping("/page") + @Operation(summary = "获得库存调拨单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-check:query')") + public CommonResult> getStockCheckPage(@Valid ErpStockCheckPageReqVO pageReqVO) { + PageResult pageResult = stockCheckService.getStockCheckPage(pageReqVO); + return success(buildStockCheckVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库存调拨单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-check:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockCheckExcel(@Valid ErpStockCheckPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockCheckVOPageResult(stockCheckService.getStockCheckPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "库存调拨单.xls", "数据", ErpStockCheckRespVO.class, list); + } + + private PageResult buildStockCheckVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 盘点项 + List stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds( + convertSet(pageResult.getList(), ErpStockCheckDO::getId)); + Map> stockCheckItemMap = convertMultiMap(stockCheckItemList, ErpStockCheckItemDO::getCheckId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockCheckItemList, ErpStockCheckItemDO::getProductId)); + // 1.3 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), stockCheck -> Long.parseLong(stockCheck.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockCheckRespVO.class, stockCheck -> { + stockCheck.setItems(BeanUtils.toBean(stockCheckItemMap.get(stockCheck.getId()), ErpStockCheckRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockCheck.setProductNames(CollUtil.join(stockCheck.getItems(), ",", ErpStockCheckRespVO.Item::getProductName)); + MapUtils.findAndThen(userMap, Long.parseLong(stockCheck.getCreator()), user -> stockCheck.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java new file mode 100644 index 0000000..b63f82d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 产品库存") +@RestController +@RequestMapping("/erp/stock") +@Validated +public class ErpStockController { + + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @GetMapping("/get") + @Operation(summary = "获得产品库存") + @Parameters({ + @Parameter(name = "id", description = "编号", example = "1"), // 方案一:传递 id + @Parameter(name = "productId", description = "产品编号", example = "10"), // 方案二:传递 productId + warehouseId + @Parameter(name = "warehouseId", description = "仓库编号", example = "2") + }) + @PreAuthorize("@ss.hasPermission('erp:stock:query')") + public CommonResult getStock(@RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "productId", required = false) Long productId, + @RequestParam(value = "warehouseId", required = false) Long warehouseId) { + ErpStockDO stock = id != null ? stockService.getStock(id) : stockService.getStock(productId, warehouseId); + return success(BeanUtils.toBean(stock, ErpStockRespVO.class)); + } + + @GetMapping("/get-count") + @Operation(summary = "获得产品库存数量") + @Parameter(name = "productId", description = "产品编号", example = "10") + public CommonResult getStockCount(@RequestParam("productId") Long productId) { + return success(stockService.getStockCount(productId)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品库存分页") + @PreAuthorize("@ss.hasPermission('erp:stock:query')") + public CommonResult> getStockPage(@Valid ErpStockPageReqVO pageReqVO) { + PageResult pageResult = stockService.getStockPage(pageReqVO); + return success(buildStockVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品库存 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockExcel(@Valid ErpStockPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockVOPageResult(stockService.getStockPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品库存.xls", "数据", ErpStockRespVO.class, list); + } + + private PageResult buildStockVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + Map productMap = productService.getProductVOMap( + convertSet(pageResult.getList(), ErpStockDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(pageResult.getList(), ErpStockDO::getWarehouseId)); + return BeanUtils.toBean(pageResult, ErpStockRespVO.class, stock -> { + MapUtils.findAndThen(productMap, stock.getProductId(), product -> stock.setProductName(product.getName()) + .setCategoryName(product.getCategoryName()).setUnitName(product.getUnitName())); + MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> stock.setWarehouseName(warehouse.getName())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java new file mode 100644 index 0000000..1103177 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 其它入库单") +@RestController +@RequestMapping("/erp/stock-in") +@Validated +public class ErpStockInController { + + @Resource + private ErpStockInService stockInService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建其它入库单") + @PreAuthorize("@ss.hasPermission('erp:stock-in:create')") + public CommonResult createStockIn(@Valid @RequestBody ErpStockInSaveReqVO createReqVO) { + return success(stockInService.createStockIn(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新其它入库单") + @PreAuthorize("@ss.hasPermission('erp:stock-in:update')") + public CommonResult updateStockIn(@Valid @RequestBody ErpStockInSaveReqVO updateReqVO) { + stockInService.updateStockIn(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新其它入库单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-in:update-status')") + public CommonResult updateStockInStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockInService.updateStockInStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除其它入库单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-in:delete')") + public CommonResult deleteStockIn(@RequestParam("ids") List ids) { + stockInService.deleteStockIn(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得其它入库单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-in:query')") + public CommonResult getStockIn(@RequestParam("id") Long id) { + ErpStockInDO stockIn = stockInService.getStockIn(id); + if (stockIn == null) { + return success(null); + } + List stockInItemList = stockInService.getStockInItemListByInId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockInItemList, ErpStockInItemDO::getProductId)); + return success(BeanUtils.toBean(stockIn, ErpStockInRespVO.class, stockInVO -> + stockInVO.setItems(BeanUtils.toBean(stockInItemList, ErpStockInRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得其它入库单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-in:query')") + public CommonResult> getStockInPage(@Valid ErpStockInPageReqVO pageReqVO) { + PageResult pageResult = stockInService.getStockInPage(pageReqVO); + return success(buildStockInVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出其它入库单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-in:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockInExcel(@Valid ErpStockInPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockInVOPageResult(stockInService.getStockInPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "其它入库单.xls", "数据", ErpStockInRespVO.class, list); + } + + private PageResult buildStockInVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 入库项 + List stockInItemList = stockInService.getStockInItemListByInIds( + convertSet(pageResult.getList(), ErpStockInDO::getId)); + Map> stockInItemMap = convertMultiMap(stockInItemList, ErpStockInItemDO::getInId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockInItemList, ErpStockInItemDO::getProductId)); + // 1.3 供应商信息 + Map supplierMap = supplierService.getSupplierMap( + convertSet(pageResult.getList(), ErpStockInDO::getSupplierId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), stockIn -> Long.parseLong(stockIn.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockInRespVO.class, stockIn -> { + stockIn.setItems(BeanUtils.toBean(stockInItemMap.get(stockIn.getId()), ErpStockInRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockIn.setProductNames(CollUtil.join(stockIn.getItems(), ",", ErpStockInRespVO.Item::getProductName)); + MapUtils.findAndThen(supplierMap, stockIn.getSupplierId(), supplier -> stockIn.setSupplierName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stockIn.getCreator()), user -> stockIn.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java new file mode 100644 index 0000000..72d67d2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 库存调拨单") +@RestController +@RequestMapping("/erp/stock-move") +@Validated +public class ErpStockMoveController { + + @Resource + private ErpStockMoveService stockMoveService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-move:create')") + public CommonResult createStockMove(@Valid @RequestBody ErpStockMoveSaveReqVO createReqVO) { + return success(stockMoveService.createStockMove(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-move:update')") + public CommonResult updateStockMove(@Valid @RequestBody ErpStockMoveSaveReqVO updateReqVO) { + stockMoveService.updateStockMove(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新库存调拨单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-move:update-status')") + public CommonResult updateStockMoveStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockMoveService.updateStockMoveStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除库存调拨单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-move:delete')") + public CommonResult deleteStockMove(@RequestParam("ids") List ids) { + stockMoveService.deleteStockMove(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得库存调拨单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult getStockMove(@RequestParam("id") Long id) { + ErpStockMoveDO stockMove = stockMoveService.getStockMove(id); + if (stockMove == null) { + return success(null); + } + List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); + return success(BeanUtils.toBean(stockMove, ErpStockMoveRespVO.class, stockMoveVO -> + stockMoveVO.setItems(BeanUtils.toBean(stockMoveItemList, ErpStockMoveRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getFromWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得库存调拨单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult> getStockMovePage(@Valid ErpStockMovePageReqVO pageReqVO) { + PageResult pageResult = stockMoveService.getStockMovePage(pageReqVO); + return success(buildStockMoveVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库存调拨单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-move:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockMoveExcel(@Valid ErpStockMovePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockMoveVOPageResult(stockMoveService.getStockMovePage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "库存调拨单.xls", "数据", ErpStockMoveRespVO.class, list); + } + + private PageResult buildStockMoveVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 调拨项 + List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveIds( + convertSet(pageResult.getList(), ErpStockMoveDO::getId)); + Map> stockMoveItemMap = convertMultiMap(stockMoveItemList, ErpStockMoveItemDO::getMoveId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); + // 1.3 TODO 芋艿:搞仓库信息 + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), stockMove -> Long.parseLong(stockMove.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockMoveRespVO.class, stockMove -> { + stockMove.setItems(BeanUtils.toBean(stockMoveItemMap.get(stockMove.getId()), ErpStockMoveRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockMove.setProductNames(CollUtil.join(stockMove.getItems(), ",", ErpStockMoveRespVO.Item::getProductName)); + // TODO 芋艿: +// MapUtils.findAndThen(customerMap, stockMove.getCustomerId(), supplier -> stockMove.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stockMove.getCreator()), user -> stockMove.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java new file mode 100644 index 0000000..7b207b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 其它出库单") +@RestController +@RequestMapping("/erp/stock-out") +@Validated +public class ErpStockOutController { + + @Resource + private ErpStockOutService stockOutService; + @Resource + private ErpStockService stockService; + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建其它出库单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:create')") + public CommonResult createStockOut(@Valid @RequestBody ErpStockOutSaveReqVO createReqVO) { + return success(stockOutService.createStockOut(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新其它出库单") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update')") + public CommonResult updateStockOut(@Valid @RequestBody ErpStockOutSaveReqVO updateReqVO) { + stockOutService.updateStockOut(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新其它出库单的状态") + @PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')") + public CommonResult updateStockOutStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + stockOutService.updateStockOutStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除其它出库单") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('erp:stock-out:delete')") + public CommonResult deleteStockOut(@RequestParam("ids") List ids) { + stockOutService.deleteStockOut(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得其它出库单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") + public CommonResult getStockOut(@RequestParam("id") Long id) { + ErpStockOutDO stockOut = stockOutService.getStockOut(id); + if (stockOut == null) { + return success(null); + } + List stockOutItemList = stockOutService.getStockOutItemListByOutId(id); + Map productMap = productService.getProductVOMap( + convertSet(stockOutItemList, ErpStockOutItemDO::getProductId)); + return success(BeanUtils.toBean(stockOut, ErpStockOutRespVO.class, stockOutVO -> + stockOutVO.setItems(BeanUtils.toBean(stockOutItemList, ErpStockOutRespVO.Item.class, item -> { + ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId()); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + })))); + } + + @GetMapping("/page") + @Operation(summary = "获得其它出库单分页") + @PreAuthorize("@ss.hasPermission('erp:stock-out:query')") + public CommonResult> getStockOutPage(@Valid ErpStockOutPageReqVO pageReqVO) { + PageResult pageResult = stockOutService.getStockOutPage(pageReqVO); + return success(buildStockOutVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出其它出库单 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-out:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockOutExcel(@Valid ErpStockOutPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockOutVOPageResult(stockOutService.getStockOutPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "其它出库单.xls", "数据", ErpStockOutRespVO.class, list); + } + + private PageResult buildStockOutVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + // 1.1 出库项 + List stockOutItemList = stockOutService.getStockOutItemListByOutIds( + convertSet(pageResult.getList(), ErpStockOutDO::getId)); + Map> stockOutItemMap = convertMultiMap(stockOutItemList, ErpStockOutItemDO::getOutId); + // 1.2 产品信息 + Map productMap = productService.getProductVOMap( + convertSet(stockOutItemList, ErpStockOutItemDO::getProductId)); + // 1.3 客户信息 + Map customerMap = customerService.getCustomerMap( + convertSet(pageResult.getList(), ErpStockOutDO::getCustomerId)); + // 1.4 管理员信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), stockOut -> Long.parseLong(stockOut.getCreator()))); + // 2. 开始拼接 + return BeanUtils.toBean(pageResult, ErpStockOutRespVO.class, stockOut -> { + stockOut.setItems(BeanUtils.toBean(stockOutItemMap.get(stockOut.getId()), ErpStockOutRespVO.Item.class, + item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + stockOut.setProductNames(CollUtil.join(stockOut.getItems(), ",", ErpStockOutRespVO.Item::getProductName)); + MapUtils.findAndThen(customerMap, stockOut.getCustomerId(), supplier -> stockOut.setCustomerName(supplier.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stockOut.getCreator()), user -> stockOut.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java new file mode 100644 index 0000000..5209eb1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - ERP 产品库存明细") +@RestController +@RequestMapping("/erp/stock-record") +@Validated +public class ErpStockRecordController { + + @Resource + private ErpStockRecordService stockRecordService; + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/get") + @Operation(summary = "获得产品库存明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:stock-record:query')") + public CommonResult getStockRecord(@RequestParam("id") Long id) { + ErpStockRecordDO stockRecord = stockRecordService.getStockRecord(id); + return success(BeanUtils.toBean(stockRecord, ErpStockRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品库存明细分页") + @PreAuthorize("@ss.hasPermission('erp:stock-record:query')") + public CommonResult> getStockRecordPage(@Valid ErpStockRecordPageReqVO pageReqVO) { + PageResult pageResult = stockRecordService.getStockRecordPage(pageReqVO); + return success(buildStockRecrodVOPageResult(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品库存明细 Excel") + @PreAuthorize("@ss.hasPermission('erp:stock-record:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportStockRecordExcel(@Valid ErpStockRecordPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = buildStockRecrodVOPageResult(stockRecordService.getStockRecordPage(pageReqVO)).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品库存明细.xls", "数据", ErpStockRecordRespVO.class, list); + } + + private PageResult buildStockRecrodVOPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + Map productMap = productService.getProductVOMap( + convertSet(pageResult.getList(), ErpStockRecordDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(pageResult.getList(), ErpStockRecordDO::getWarehouseId)); + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), record -> Long.parseLong(record.getCreator()))); + return BeanUtils.toBean(pageResult, ErpStockRecordRespVO.class, stock -> { + MapUtils.findAndThen(productMap, stock.getProductId(), product -> stock.setProductName(product.getName()) + .setCategoryName(product.getCategoryName()).setUnitName(product.getUnitName())); + MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> stock.setWarehouseName(warehouse.getName())); + MapUtils.findAndThen(userMap, Long.parseLong(stock.getCreator()), user -> stock.setCreatorName(user.getNickname())); + }); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java new file mode 100644 index 0000000..9de214b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 仓库") +@RestController +@RequestMapping("/erp/warehouse") +@Validated +public class ErpWarehouseController { + + @Resource + private ErpWarehouseService warehouseService; + + @PostMapping("/create") + @Operation(summary = "创建仓库") + @PreAuthorize("@ss.hasPermission('erp:warehouse:create')") + public CommonResult createWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO createReqVO) { + return success(warehouseService.createWarehouse(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新仓库") + @PreAuthorize("@ss.hasPermission('erp:warehouse:update')") + public CommonResult updateWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO updateReqVO) { + warehouseService.updateWarehouse(updateReqVO); + return success(true); + } + + @PutMapping("/update-default-status") + @Operation(summary = "更新仓库默认状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true), + @Parameter(name = "status", description = "状态", required = true) + }) + public CommonResult updateWarehouseDefaultStatus(@RequestParam("id") Long id, + @RequestParam("defaultStatus") Boolean defaultStatus) { + warehouseService.updateWarehouseDefaultStatus(id, defaultStatus); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除仓库") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:warehouse:delete')") + public CommonResult deleteWarehouse(@RequestParam("id") Long id) { + warehouseService.deleteWarehouse(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得仓库") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") + public CommonResult getWarehouse(@RequestParam("id") Long id) { + ErpWarehouseDO warehouse = warehouseService.getWarehouse(id); + return success(BeanUtils.toBean(warehouse, ErpWarehouseRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得仓库分页") + @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") + public CommonResult> getWarehousePage(@Valid ErpWarehousePageReqVO pageReqVO) { + PageResult pageResult = warehouseService.getWarehousePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpWarehouseRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") + public CommonResult> getWarehouseSimpleList() { + List list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId()) + .setName(warehouse.getName()).setDefaultStatus(warehouse.getDefaultStatus()))); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出仓库 Excel") + @PreAuthorize("@ss.hasPermission('erp:warehouse:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportWarehouseExcel(@Valid ErpWarehousePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = warehouseService.getWarehousePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "仓库.xls", "数据", ErpWarehouseRespVO.class, + BeanUtils.toBean(list, ErpWarehouseRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java new file mode 100644 index 0000000..2bae14c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 库存盘点单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockCheckPageReqVO extends PageParam { + + @Schema(description = "盘点单号", example = "S123") + private String no; + + @Schema(description = "仓库编号", example = "3113") + private Long warehouseId; + + @Schema(description = "盘点时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] checkTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java new file mode 100644 index 0000000..88b75bb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 库存盘点单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockCheckRespVO { + + @Schema(description = "盘点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("盘点编号") + private Long id; + + @Schema(description = "盘点单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("盘点单号") + private String no; + + @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("盘点时间") + private LocalDateTime checkTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "盘点项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "盘点项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "账面数量(当前库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "账面数量不能为空") + private BigDecimal stockCount; + + @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "实际数量不能为空") + private BigDecimal actualCount; + + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "盈亏数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java new file mode 100644 index 0000000..80e126a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它出库单新增/修改 Request VO") +@Data +public class ErpStockCheckSaveReqVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库时间不能为空") + private LocalDateTime checkTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "出库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "账面数量(当前库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "账面数量不能为空") + private BigDecimal stockCount; + + @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "实际数量不能为空") + private BigDecimal actualCount; + + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "盈亏数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java new file mode 100644 index 0000000..02e3db3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 其它入库单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockInPageReqVO extends PageParam { + + @Schema(description = "入库单号", example = "S123") + private String no; + + @Schema(description = "供应商编号", example = "3113") + private Long supplierId; + + @Schema(description = "入库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] inTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java new file mode 100644 index 0000000..077b9dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInRespVO.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 其它入库单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockInRespVO { + + @Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("入库编号") + private Long id; + + @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("入库单号") + private String no; + + @Schema(description = "供应商编号", example = "3113") + private Long supplierId; + @Schema(description = "供应商名称", example = "芋道") + @ExcelProperty("供应商名称") + private String supplierName; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("入库时间") + private LocalDateTime inTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "入库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java new file mode 100644 index 0000000..ef686d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInSaveReqVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它入库单新增/修改 Request VO") +@Data +public class ErpStockInSaveReqVO { + + @Schema(description = "入库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "供应商编号", example = "3113") + private Long supplierId; + + @Schema(description = "入库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "入库时间不能为空") + private LocalDateTime inTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "入库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "入库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "入库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java new file mode 100644 index 0000000..98a1fe9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 库存调拨单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockMovePageReqVO extends PageParam { + + @Schema(description = "调拨单号", example = "S123") + private String no; + + @Schema(description = "调拨时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] moveTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "调出仓库编号", example = "1") + private Long fromWarehouseId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java new file mode 100644 index 0000000..799ddc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 库存调拨单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockMoveRespVO { + + @Schema(description = "调拨编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("调拨编号") + private Long id; + + @Schema(description = "调拨单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("调拨单号") + private String no; + + @Schema(description = "调拨时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("调拨时间") + private LocalDateTime moveTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "调拨项编号", example = "11756") + private Long id; + + @Schema(description = "调出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long fromWarehouseId; + + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long toWarehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java new file mode 100644 index 0000000..dc80353 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 库存调拨单新增/修改 Request VO") +@Data +public class ErpStockMoveSaveReqVO { + + @Schema(description = "调拨编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "调拨时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调拨时间不能为空") + private LocalDateTime moveTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "调拨项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "调拨项编号", example = "11756") + private Long id; + + @Schema(description = "调出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "调出仓库编号不能为空") + private Long fromWarehouseId; + + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotNull(message = "调入仓库编号不能为空") + private Long toWarehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + @AssertTrue(message = "调出、调仓仓库不能相同") + @JsonIgnore + public boolean isWarehouseValid() { + return ObjectUtil.notEqual(fromWarehouseId, toWarehouseId); + } + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java new file mode 100644 index 0000000..5f6558b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 其它出库单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockOutPageReqVO extends PageParam { + + @Schema(description = "出库单号", example = "S123") + private String no; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "出库时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] outTime; + + @Schema(description = "状态", example = "10") + @InEnum(ErpAuditStatus.class) + private Integer status; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "创建者") + private String creator; + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java new file mode 100644 index 0000000..22a88e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutRespVO.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS; + +@Schema(description = "管理后台 - ERP 其它出库单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockOutRespVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @ExcelProperty("出库编号") + private Long id; + + @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "S123") + @ExcelProperty("出库单号") + private String no; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + @Schema(description = "客户名称", example = "芋道") + @ExcelProperty("客户名称") + private String customerName; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出库时间") + private LocalDateTime outTime; + + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") + @ExcelProperty("合计数量") + private BigDecimal totalCount; + + @Schema(description = "合计金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906") + @ExcelProperty("合计金额") + private BigDecimal totalPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(AUDIT_STATUS) + private Integer status; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "创建人", example = "芋道") + private String creator; + @Schema(description = "创建人名称", example = "芋道") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品信息") + private String productNames; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + // ========== 关联字段 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985") + private String productBarCode; + @Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒") + private String productUnitName; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal stockCount; // 该字段仅仅在“详情”和“编辑”时使用 + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java new file mode 100644 index 0000000..2630587 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutSaveReqVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - ERP 其它出库单新增/修改 Request VO") +@Data +public class ErpStockOutSaveReqVO { + + @Schema(description = "出库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + private Long id; + + @Schema(description = "客户编号", example = "3113") + private Long customerId; + + @Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出库时间不能为空") + private LocalDateTime outTime; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") + private String fileUrl; + + @Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "出库项列表不能为空") + @Valid + private List items; + + @Data + public static class Item { + + @Schema(description = "出库项编号", example = "11756") + private Long id; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "产品编号不能为空") + private Long productId; + + @Schema(description = "产品单价", example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + @NotNull(message = "产品数量不能为空") + private BigDecimal count; + + @Schema(description = "备注", example = "随便") + private String remark; + + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java new file mode 100644 index 0000000..c478e4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 产品库存明细分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockRecordPageReqVO extends PageParam { + + @Schema(description = "产品编号", example = "10625") + private Long productId; + + @Schema(description = "仓库编号", example = "32407") + private Long warehouseId; + + @Schema(description = "业务类型", example = "10") + private Integer bizType; + + @Schema(description = "业务单号", example = "Z110") + private String bizNo; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java new file mode 100644 index 0000000..ff4b3e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/record/ErpStockRecordRespVO.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.erp.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 产品库存明细 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockRecordRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18909") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10625") + private Long productId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32407") + private Long warehouseId; + + @Schema(description = "出入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "11084") + @ExcelProperty("出入库数量") + private BigDecimal count; + + @Schema(description = "总库存量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4307") + @ExcelProperty("总库存量") + private BigDecimal totalCount; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty(value = "业务类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.STOCK_RECORD_BIZ_TYPE) + private Integer bizType; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27093") + @ExcelProperty("业务编号") + private Long bizId; + + @Schema(description = "业务项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23516") + @ExcelProperty("业务项编号") + private Long bizItemId; + + @Schema(description = "业务单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "Z110") + @ExcelProperty("业务单号") + private String bizNo; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "25682") + private String creator; + + // ========== 产品信息 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + @ExcelProperty("产品名称") + private String productName; + + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; + + // ========== 仓库信息 ========== + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String warehouseName; + + // ========== 用户信息 ========== + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("创建人") + private String creatorName; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java new file mode 100644 index 0000000..f7f3fa3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 库存分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpStockPageReqVO extends PageParam { + + @Schema(description = "产品编号", example = "19614") + private Long productId; + + @Schema(description = "仓库编号", example = "2802") + private Long warehouseId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java new file mode 100644 index 0000000..06366a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/stock/ErpStockRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 库存 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpStockRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17086") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19614") + private Long productId; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2802") + private Long warehouseId; + + @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "21935") + @ExcelProperty("库存数量") + private BigDecimal count; + + // ========== 产品信息 ========== + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + @ExcelProperty("产品名称") + private String productName; + + @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果") + @ExcelProperty("产品分类") + private String categoryName; + + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个") + @ExcelProperty("单位") + private String unitName; + + // ========== 仓库信息 ========== + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String warehouseName; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java new file mode 100644 index 0000000..2accf9a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - ERP 仓库分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpWarehousePageReqVO extends PageParam { + + @Schema(description = "仓库名称", example = "李四") + private String name; + + @Schema(description = "开启状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java new file mode 100644 index 0000000..188d426 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 仓库 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpWarehouseRespVO { + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11614") + @ExcelProperty("仓库编号") + private Long id; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("仓库名称") + private String name; + + @Schema(description = "仓库地址", example = "上海陆家嘴") + @ExcelProperty("仓库地址") + private String address; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("排序") + private Long sort; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "负责人", example = "芋头") + @ExcelProperty("负责人") + private String principal; + + @Schema(description = "仓储费,单位:元", example = "13973") + @ExcelProperty("仓储费,单位:元") + private BigDecimal warehousePrice; + + @Schema(description = "搬运费,单位:元", example = "9903") + @ExcelProperty("搬运费,单位:元") + private BigDecimal truckagePrice; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "是否默认", example = "1") + @ExcelProperty("是否默认") + private Boolean defaultStatus; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java new file mode 100644 index 0000000..06bf558 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 仓库新增/修改 Request VO") +@Data +public class ErpWarehouseSaveReqVO { + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11614") + private Long id; + + @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "仓库名称不能为空") + private String name; + + @Schema(description = "仓库地址", example = "上海陆家嘴") + private String address; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Long sort; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "负责人", example = "芋头") + private String principal; + + @Schema(description = "仓储费,单位:元", example = "13973") + private BigDecimal warehousePrice; + + @Schema(description = "搬运费,单位:元", example = "9903") + private BigDecimal truckagePrice; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "开启状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/package-info.java new file mode 100644 index 0000000..ef0e5ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.erp.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpAccountDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpAccountDO.java new file mode 100644 index 0000000..fe01cc2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpAccountDO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.finance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * ERP 结算账户 DO + * + * @author 芋道源码 + */ +@TableName("erp_account") +@KeySequence("erp_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpAccountDO extends BaseDO { + + /** + * 结算账户编号 + */ + @TableId + private Long id; + /** + * 账户名称 + */ + private String name; + /** + * 账户编码 + */ + private String no; + /** + * 备注 + */ + private String remark; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + /** + * 是否默认 + */ + private Boolean defaultStatus; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentDO.java new file mode 100644 index 0000000..edb55ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.finance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 付款单 DO + * + * @author 芋道源码 + */ +@TableName("erp_finance_payment") +@KeySequence("erp_finance_payment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpFinancePaymentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 付款单号 + */ + private String no; + /** + * 付款状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 付款时间 + */ + private LocalDateTime paymentTime; + /** + * 财务人员编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long financeUserId; + /** + * 供应商编号 + * + * 关联 {@link ErpSupplierDO#getId()} + */ + private Long supplierId; + /** + * 付款账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + + /** + * 合计价格,单位:元 + */ + private BigDecimal totalPrice; + /** + * 优惠金额,单位:元 + */ + private BigDecimal discountPrice; + /** + * 实付金额,单位:分 + * + * paymentPrice = totalPrice - discountPrice + */ + private BigDecimal paymentPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentItemDO.java new file mode 100644 index 0000000..dd5bc5f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinancePaymentItemDO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.finance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 付款项 DO + * + * @author 芋道源码 + */ +@TableName("erp_finance_payment_item") +@KeySequence("erp_finance_payment_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpFinancePaymentItemDO extends BaseDO { + + /** + * 入库项编号 + */ + @TableId + private Long id; + /** + * 付款单编号 + * + * 关联 {@link ErpFinancePaymentDO#getId()} + */ + private Long paymentId; + + /** + * 业务类型 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum} 的采购入库、退货 + */ + private Integer bizType; + /** + * 业务编号 + * + * 例如说:{@link ErpPurchaseInDO#getId()} + */ + private Long bizId; + /** + * 业务单号 + * + * 例如说:{@link ErpPurchaseInDO#getNo()} + */ + private String bizNo; + + /** + * 应付金额,单位:分 + */ + private BigDecimal totalPrice; + /** + * 已付金额,单位:分 + */ + private BigDecimal paidPrice; + /** + * 本次付款,单位:分 + */ + private BigDecimal paymentPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptDO.java new file mode 100644 index 0000000..46a5595 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.finance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 收款单 DO + * + * @author 芋道源码 + */ +@TableName("erp_finance_receipt") +@KeySequence("erp_finance_receipt_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpFinanceReceiptDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 收款单号 + */ + private String no; + /** + * 收款状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 收款时间 + */ + private LocalDateTime receiptTime; + /** + * 财务人员编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long financeUserId; + /** + * 客户编号 + * + * 关联 {@link ErpCustomerDO#getId()} + */ + private Long customerId; + /** + * 收款账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + + /** + * 合计价格,单位:元 + */ + private BigDecimal totalPrice; + /** + * 优惠金额,单位:元 + */ + private BigDecimal discountPrice; + /** + * 实付金额,单位:分 + * + * receiptPrice = totalPrice - discountPrice + */ + private BigDecimal receiptPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptItemDO.java new file mode 100644 index 0000000..87f051d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/finance/ErpFinanceReceiptItemDO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.finance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 收款项 DO + * + * @author 芋道源码 + */ +@TableName("erp_finance_receipt_item") +@KeySequence("erp_finance_receipt_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpFinanceReceiptItemDO extends BaseDO { + + /** + * 入库项编号 + */ + @TableId + private Long id; + /** + * 收款单编号 + * + * 关联 {@link ErpFinanceReceiptDO#getId()} + */ + private Long receiptId; + + /** + * 业务类型 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum} 的销售出库、退货 + */ + private Integer bizType; + /** + * 业务编号 + * + * 例如说:{@link ErpSaleOutDO#getId()} + */ + private Long bizId; + /** + * 业务单号 + * + * 例如说:{@link ErpSaleOutDO#getNo()} + */ + private String bizNo; + + /** + * 应收金额,单位:分 + */ + private BigDecimal totalPrice; + /** + * 已收金额,单位:分 + */ + private BigDecimal receiptedPrice; + /** + * 本次收款,单位:分 + */ + private BigDecimal receiptPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductCategoryDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductCategoryDO.java new file mode 100644 index 0000000..4c62251 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductCategoryDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * ERP 产品分类 DO + * + * @author 芋道源码 + */ +@TableName("erp_product_category") +@KeySequence("erp_product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpProductCategoryDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 分类编号 + */ + @TableId + private Long id; + /** + * 父分类编号 + */ + private Long parentId; + /** + * 分类名称 + */ + private String name; + /** + * 分类编码 + */ + private String code; + /** + * 分类排序 + */ + private Integer sort; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java new file mode 100644 index 0000000..31e4aa2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 产品 DO + * + * @author 芋道源码 + */ +@TableName("erp_product") +@KeySequence("erp_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpProductDO extends BaseDO { + + /** + * 产品编号 + */ + @TableId + private Long id; + /** + * 产品名称 + */ + private String name; + /** + * 产品条码 + */ + private String barCode; + /** + * 产品分类编号 + * + * 关联 {@link ErpProductCategoryDO#getId()} + */ + private Long categoryId; + /** + * 单位编号 + * + * 关联 {@link ErpProductUnitDO#getId()} + */ + private Long unitId; + /** + * 产品状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 产品规格 + */ + private String standard; + /** + * 产品备注 + */ + private String remark; + /** + * 保质期天数 + */ + private Integer expiryDay; + /** + * 基础重量(kg) + */ + private BigDecimal weight; + /** + * 采购价格,单位:元 + */ + private BigDecimal purchasePrice; + /** + * 销售价格,单位:元 + */ + private BigDecimal salePrice; + /** + * 最低价格,单位:元 + */ + private BigDecimal minPrice; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductUnitDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductUnitDO.java new file mode 100644 index 0000000..73c96c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductUnitDO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.product; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * ERP 产品单位 DO + * + * @author 芋道源码 + */ +@TableName("erp_product_unit") +@KeySequence("erp_product_unit_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpProductUnitDO extends BaseDO { + + /** + * 单位编号 + */ + @TableId + private Long id; + /** + * 单位名字 + */ + private String name; + /** + * 单位状态 + */ + private Integer status; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java new file mode 100644 index 0000000..b8186f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购入库 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_purchase_in") +@KeySequence("erp_purchase_in_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseInDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购入库单号 + */ + private String no; + /** + * 入库状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 供应商编号 + * + * 关联 {@link ErpSupplierDO#getId()} + */ + private Long supplierId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 入库时间 + */ + private LocalDateTime inTime; + + /** + * 采购订单编号 + * + * 关联 {@link ErpPurchaseOrderDO#getId()} + */ + private Long orderId; + /** + * 采购订单号 + * + * 冗余 {@link ErpPurchaseOrderDO#getNo()} + */ + private String orderNo; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + otherPrice + */ + private BigDecimal totalPrice; + /** + * 已支付金额,单位:元 + * + * 目的:和 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO} 结合,记录已支付金额 + */ + private BigDecimal paymentPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 其它金额,单位:元 + */ + private BigDecimal otherPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInItemDO.java new file mode 100644 index 0000000..1597bc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInItemDO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 采购入库项 DO + * + * @author 芋道源码 + */ +@TableName("erp_purchase_in_items") +@KeySequence("erp_purchase_in_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseInItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购入库编号 + * + * 关联 {@link ErpPurchaseInDO##getId()} + */ + private Long inId; + /** + * 采购订单项编号 + * + * 关联 {@link ErpPurchaseOrderItemDO#getId()} + * 目的:方便更新关联的采购订单项的入库数量 + */ + private Long orderItemId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java new file mode 100644 index 0000000..bba1542 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java @@ -0,0 +1,115 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购订单 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_purchase_order") +@KeySequence("erp_purchase_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseOrderDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购订单号 + */ + private String no; + /** + * 采购状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 供应商编号 + * + * 关联 {@link ErpSupplierDO#getId()} + */ + private Long supplierId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 下单时间 + */ + private LocalDateTime orderTime; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + */ + private BigDecimal totalPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 定金金额,单位:元 + */ + private BigDecimal depositPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + + // ========== 采购入库 ========== + /** + * 采购入库数量 + */ + private BigDecimal inCount; + + // ========== 采购退货(出库)) ========== + /** + * 采购退货数量 + */ + private BigDecimal returnCount; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderItemDO.java new file mode 100644 index 0000000..aa54d33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderItemDO.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 采购订单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_purchase_order_items") +@KeySequence("erp_purchase_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseOrderItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购订单编号 + * + * 关联 {@link ErpPurchaseOrderDO#getId()} + */ + private Long orderId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + + // ========== 采购入库 ========== + /** + * 采购入库数量 + */ + private BigDecimal inCount; + + // ========== 采购退货(出库)) ========== + /** + * 采购退货数量 + */ + private BigDecimal returnCount; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnDO.java new file mode 100644 index 0000000..4189e0a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnDO.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购退货 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_purchase_return") +@KeySequence("erp_purchase_return_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseReturnDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购退货单号 + */ + private String no; + /** + * 退货状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 供应商编号 + * + * 关联 {@link ErpSupplierDO#getId()} + */ + private Long supplierId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 退货时间 + */ + private LocalDateTime returnTime; + + /** + * 采购订单编号 + * + * 关联 {@link ErpPurchaseOrderDO#getId()} + */ + private Long orderId; + /** + * 采购订单号 + * + * 冗余 {@link ErpPurchaseOrderDO#getNo()} + */ + private String orderNo; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + otherPrice + */ + private BigDecimal totalPrice; + /** + * 已退款金额,单位:元 + * + * 目的:和 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO} 结合,记录已支付金额 + */ + private BigDecimal refundPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 其它金额,单位:元 + */ + private BigDecimal otherPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnItemDO.java new file mode 100644 index 0000000..1e17132 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseReturnItemDO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 采购退货项 DO + * + * @author 芋道源码 + */ +@TableName("erp_purchase_return_items") +@KeySequence("erp_purchase_return_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPurchaseReturnItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 采购退货编号 + * + * 关联 {@link ErpPurchaseReturnDO##getId()} + */ + private Long returnId; + /** + * 采购订单项编号 + * + * 关联 {@link ErpPurchaseOrderItemDO#getId()} + * 目的:方便更新关联的采购订单项的退货数量 + */ + private Long orderItemId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java new file mode 100644 index 0000000..6e94c66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpSupplierDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 供应商 DO + * + * @author 芋道源码 + */ +@TableName("erp_supplier") +@KeySequence("erp_supplier_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSupplierDO extends BaseDO { + + /** + * 供应商编号 + */ + @TableId + private Long id; + /** + * 供应商名称 + */ + private String name; + /** + * 联系人 + */ + private String contact; + /** + * 手机号码 + */ + private String mobile; + /** + * 联系电话 + */ + private String telephone; + /** + * 电子邮箱 + */ + private String email; + /** + * 传真 + */ + private String fax; + /** + * 备注 + */ + private String remark; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + /** + * 纳税人识别号 + */ + private String taxNo; + /** + * 税率 + */ + private BigDecimal taxPercent; + /** + * 开户行 + */ + private String bankName; + /** + * 开户账号 + */ + private String bankAccount; + /** + * 开户地址 + */ + private String bankAddress; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java new file mode 100644 index 0000000..7bffcc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpCustomerDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 客户 DO + * + * @author 芋道源码 + */ +@TableName("erp_customer") +@KeySequence("erp_customer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpCustomerDO extends BaseDO { + + /** + * 客户编号 + */ + @TableId + private Long id; + /** + * 客户名称 + */ + private String name; + /** + * 联系人 + */ + private String contact; + /** + * 手机号码 + */ + private String mobile; + /** + * 联系电话 + */ + private String telephone; + /** + * 电子邮箱 + */ + private String email; + /** + * 传真 + */ + private String fax; + /** + * 备注 + */ + private String remark; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + /** + * 纳税人识别号 + */ + private String taxNo; + /** + * 税率 + */ + private BigDecimal taxPercent; + /** + * 开户行 + */ + private String bankName; + /** + * 开户账号 + */ + private String bankAccount; + /** + * 开户地址 + */ + private String bankAddress; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java new file mode 100644 index 0000000..5cdd434 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java @@ -0,0 +1,121 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售订单 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_sale_order") +@KeySequence("erp_sale_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleOrderDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售订单号 + */ + private String no; + /** + * 销售状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 客户编号 + * + * 关联 {@link ErpCustomerDO#getId()} + */ + private Long customerId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 销售员编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long saleUserId; + /** + * 下单时间 + */ + private LocalDateTime orderTime; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + */ + private BigDecimal totalPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 定金金额,单位:元 + */ + private BigDecimal depositPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + + // ========== 销售出库 ========== + /** + * 销售出库数量 + */ + private BigDecimal outCount; + + // ========== 销售退货(入库)) ========== + /** + * 销售退货数量 + */ + private BigDecimal returnCount; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java new file mode 100644 index 0000000..4c82976 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderItemDO.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 销售订单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_sale_order_items") +@KeySequence("erp_sale_order_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleOrderItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售订单编号 + * + * 关联 {@link ErpSaleOrderDO#getId()} + */ + private Long orderId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + + // ========== 销售出库 ========== + /** + * 销售出库数量 + */ + private BigDecimal outCount; + + // ========== 销售退货(入库)) ========== + /** + * 销售退货数量 + */ + private BigDecimal returnCount; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java new file mode 100644 index 0000000..65b9d94 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java @@ -0,0 +1,128 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售出库 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_sale_out") +@KeySequence("erp_sale_out_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleOutDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售出库单号 + */ + private String no; + /** + * 出库状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 客户编号 + * + * 关联 {@link ErpCustomerDO#getId()} + */ + private Long customerId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 销售员编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long saleUserId; + /** + * 出库时间 + */ + private LocalDateTime outTime; + + /** + * 销售订单编号 + * + * 关联 {@link ErpSaleOrderDO#getId()} + */ + private Long orderId; + /** + * 销售订单号 + * + * 冗余 {@link ErpSaleOrderDO#getNo()} + */ + private String orderNo; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + otherPrice + */ + private BigDecimal totalPrice; + /** + * 已收款金额,单位:元 + * + * 目的:和 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO} 结合,记录已收款金额 + */ + private BigDecimal receiptPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 其它金额,单位:元 + */ + private BigDecimal otherPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutItemDO.java new file mode 100644 index 0000000..b9b4064 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutItemDO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 销售出库项 DO + * + * @author 芋道源码 + */ +@TableName("erp_sale_out_items") +@KeySequence("erp_sale_out_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleOutItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售出库编号 + * + * 关联 {@link ErpStockOutDO##getId()} + */ + private Long outId; + /** + * 销售订单项编号 + * + * 关联 {@link ErpSaleOrderItemDO#getId()} + * 目的:方便更新关联的销售订单项的出库数量 + */ + private Long orderItemId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnDO.java new file mode 100644 index 0000000..ba41ac9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnDO.java @@ -0,0 +1,128 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售退货 DO + * + * @author 芋道源码 + */ +@TableName(value = "erp_sale_return") +@KeySequence("erp_sale_return_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleReturnDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售退货单号 + */ + private String no; + /** + * 退货状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 客户编号 + * + * 关联 {@link ErpCustomerDO#getId()} + */ + private Long customerId; + /** + * 结算账户编号 + * + * 关联 {@link ErpAccountDO#getId()} + */ + private Long accountId; + /** + * 销售员编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long saleUserId; + /** + * 退货时间 + */ + private LocalDateTime returnTime; + + /** + * 销售订单编号 + * + * 关联 {@link ErpSaleOrderDO#getId()} + */ + private Long orderId; + /** + * 销售订单号 + * + * 冗余 {@link ErpSaleOrderDO#getNo()} + */ + private String orderNo; + + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 最终合计价格,单位:元 + * + * totalPrice = totalProductPrice + totalTaxPrice - discountPrice + otherPrice + */ + private BigDecimal totalPrice; + /** + * 已退款金额,单位:元 + * + * 目的:和 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO} 结合,记录已退款金额 + */ + private BigDecimal refundPrice; + + /** + * 合计产品价格,单位:元 + */ + private BigDecimal totalProductPrice; + /** + * 合计税额,单位:元 + */ + private BigDecimal totalTaxPrice; + /** + * 优惠率,百分比 + */ + private BigDecimal discountPercent; + /** + * 优惠金额,单位:元 + * + * discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent + */ + private BigDecimal discountPrice; + /** + * 其它金额,单位:元 + */ + private BigDecimal otherPrice; + + /** + * 附件地址 + */ + private String fileUrl; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnItemDO.java new file mode 100644 index 0000000..8851d15 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleReturnItemDO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.sale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 销售退货项 DO + * + * @author 芋道源码 + */ +@TableName("erp_sale_return_items") +@KeySequence("erp_sale_return_items_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpSaleReturnItemDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 销售退货编号 + * + * 关联 {@link ErpSaleReturnDO##getId()} + */ + private Long returnId; + /** + * 销售订单项编号 + * + * 关联 {@link ErpSaleOrderItemDO#getId()} + * 目的:方便更新关联的销售订单项的退货数量 + */ + private Long orderItemId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位单位 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + + /** + * 产品单位单价,单位:元 + */ + private BigDecimal productPrice; + /** + * 数量 + */ + private BigDecimal count; + /** + * 总价,单位:元 + * + * totalPrice = productPrice * count + */ + private BigDecimal totalPrice; + /** + * 税率,百分比 + */ + private BigDecimal taxPercent; + /** + * 税额,单位:元 + * + * taxPrice = totalPrice * taxPercent + */ + private BigDecimal taxPrice; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java new file mode 100644 index 0000000..e916827 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 库存盘点单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_check") +@KeySequence("erp_stock_check_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockCheckDO extends BaseDO { + + /** + * 盘点编号 + */ + @TableId + private Long id; + /** + * 盘点单号 + */ + private String no; + /** + * 盘点时间 + */ + private LocalDateTime checkTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java new file mode 100644 index 0000000..c3c4dbf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckItemDO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 库存盘点单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_check_item") +@KeySequence("erp_stock_check_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockCheckItemDO extends BaseDO { + + /** + * 盘点项编号 + */ + @TableId + private Long id; + /** + * 盘点编号 + * + * 关联 {@link ErpStockCheckDO#getId()} + */ + private Long checkId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 账面数量(当前库存) + */ + private BigDecimal stockCount; + /** + * 实际数量(实际库存) + */ + private BigDecimal actualCount; + /** + * 盈亏数量 + * + * count = stockCount - actualCount + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java new file mode 100644 index 0000000..558c6c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 产品库存 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock") +@KeySequence("erp_stock_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 库存数量 + */ + private BigDecimal count; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java new file mode 100644 index 0000000..ee2512a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 其它入库单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in") +@KeySequence("erp_stock_in_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockInDO extends BaseDO { + + /** + * 入库编号 + */ + @TableId + private Long id; + /** + * 入库单号 + */ + private String no; + /** + * 供应商编号 + * + * 关联 {@link ErpSupplierDO#getId()} + */ + private Long supplierId; + /** + * 入库时间 + */ + private LocalDateTime inTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java new file mode 100644 index 0000000..3e3ca9c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockInItemDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 其它入库单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_in_item") +@KeySequence("erp_stock_in_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockInItemDO extends BaseDO { + + /** + * 入库项编号 + */ + @TableId + private Long id; + /** + * 入库编号 + * + * 关联 {@link ErpStockInDO#getId()} + */ + private Long inId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java new file mode 100644 index 0000000..682b331 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 库存调拨单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_move") +@KeySequence("erp_stock_move_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockMoveDO extends BaseDO { + + /** + * 调拨编号 + */ + @TableId + private Long id; + /** + * 调拨单号 + */ + private String no; + /** + * 调拨时间 + */ + private LocalDateTime moveTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java new file mode 100644 index 0000000..aee2036 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 库存调拨单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_move_item") +@KeySequence("erp_stock_move_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockMoveItemDO extends BaseDO { + + /** + * 调拨项编号 + */ + @TableId + private Long id; + /** + * 调拨编号 + * + * 关联 {@link ErpStockMoveDO#getId()} + */ + private Long moveId; + /** + * 调出仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long fromWarehouseId; + /** + * 调入仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long toWarehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java new file mode 100644 index 0000000..e0b337a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutDO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 其它出库单 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_out") +@KeySequence("erp_stock_out_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockOutDO extends BaseDO { + + /** + * 出库编号 + */ + @TableId + private Long id; + /** + * 出库单号 + */ + private String no; + /** + * 客户编号 + * + * TODO 芋艿:待关联 + */ + private Long customerId; + /** + * 出库时间 + */ + private LocalDateTime outTime; + /** + * 合计数量 + */ + private BigDecimal totalCount; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 附件 URL + */ + private String fileUrl; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java new file mode 100644 index 0000000..065c525 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockOutItemDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 其它出库单项 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_out_item") +@KeySequence("erp_stock_out_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockOutItemDO extends BaseDO { + + /** + * 出库项编号 + */ + @TableId + private Long id; + /** + * 出库编号 + * + * 关联 {@link ErpStockOutDO#getId()} + */ + private Long outId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 产品单位编号 + * + * 冗余 {@link ErpProductDO#getUnitId()} + */ + private Long productUnitId; + /** + * 产品单价 + */ + private BigDecimal productPrice; + /** + * 产品数量 + */ + private BigDecimal count; + /** + * 合计金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java new file mode 100644 index 0000000..7bc5e5a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockRecordDO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 产品库存明细 DO + * + * @author 芋道源码 + */ +@TableName("erp_stock_record") +@KeySequence("erp_stock_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品编号 + * + * 关联 {@link ErpProductDO#getId()} + */ + private Long productId; + /** + * 仓库编号 + * + * 关联 {@link ErpWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 出入库数量 + * + * 正数,表示入库;负数,表示出库 + */ + private BigDecimal count; + /** + * 总库存量 + * + * 出入库之后,目前的库存量 + */ + private BigDecimal totalCount; + /** + * 业务类型 + * + * 枚举 {@link ErpStockRecordBizTypeEnum} + */ + private Integer bizType; + /** + * 业务编号 + * + * 例如说:{@link ErpStockInDO#getId()} + */ + private Long bizId; + /** + * 业务项编号 + * + * 例如说:{@link ErpStockInItemDO#getId()} + */ + private Long bizItemId; + /** + * 业务单号 + * + * 例如说:{@link ErpStockInDO#getNo()} + */ + private String bizNo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java new file mode 100644 index 0000000..4f20617 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * ERP 仓库 DO + * + * @author 芋道源码 + */ +@TableName("erp_warehouse") +@KeySequence("erp_warehouse_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpWarehouseDO extends BaseDO { + + /** + * 仓库编号 + */ + @TableId + private Long id; + /** + * 仓库名称 + */ + private String name; + /** + * 仓库地址 + */ + private String address; + /** + * 排序 + */ + private Long sort; + /** + * 备注 + */ + private String remark; + /** + * 负责人 + */ + private String principal; + /** + * 仓储费,单位:元 + */ + private BigDecimal warehousePrice; + /** + * 搬运费,单位:元 + */ + private BigDecimal truckagePrice; + /** + * 开启状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 是否默认 + */ + private Boolean defaultStatus; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpAccountMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpAccountMapper.java new file mode 100644 index 0000000..2f98147 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpAccountMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 结算账户 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpAccountMapper extends BaseMapperX { + + default PageResult selectPage(ErpAccountPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpAccountDO::getName, reqVO.getName()) + .likeIfPresent(ErpAccountDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpAccountDO::getRemark, reqVO.getRemark()) + .orderByDesc(ErpAccountDO::getId)); + } + + default ErpAccountDO selectByDefaultStatus() { + return selectOne(ErpAccountDO::getDefaultStatus, true); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpAccountDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java new file mode 100644 index 0000000..7787e8d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * ERP 付款单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpFinancePaymentItemMapper extends BaseMapperX { + + default List selectListByPaymentId(Long paymentId) { + return selectList(ErpFinancePaymentItemDO::getPaymentId, paymentId); + } + + default List selectListByPaymentIds(Collection paymentIds) { + return selectList(ErpFinancePaymentItemDO::getPaymentId, paymentIds); + } + + default BigDecimal selectPaymentPriceSumByBizIdAndBizType(Long bizId, Integer bizType) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(payment_price) AS paymentPriceSum") + .eq("biz_id", bizId) + .eq("biz_type", bizType)); + // 获得数量 + if (CollUtil.isEmpty(result)) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "paymentPriceSum", 0D)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentMapper.java new file mode 100644 index 0000000..5ad0ccc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentMapper.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 付款单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpFinancePaymentMapper extends BaseMapperX { + + default PageResult selectPage(ErpFinancePaymentPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpFinancePaymentDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpFinancePaymentDO::getPaymentTime, reqVO.getPaymentTime()) + .eqIfPresent(ErpFinancePaymentDO::getSupplierId, reqVO.getSupplierId()) + .eqIfPresent(ErpFinancePaymentDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpFinancePaymentDO::getFinanceUserId, reqVO.getFinanceUserId()) + .eqIfPresent(ErpFinancePaymentDO::getAccountId, reqVO.getAccountId()) + .eqIfPresent(ErpFinancePaymentDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpFinancePaymentDO::getRemark, reqVO.getRemark()) + .orderByDesc(ErpFinancePaymentDO::getId); + if (reqVO.getBizNo() != null) { + query.leftJoin(ErpFinancePaymentItemDO.class, ErpFinancePaymentItemDO::getPaymentId, ErpFinancePaymentDO::getId) + .eq(reqVO.getBizNo() != null, ErpFinancePaymentItemDO::getBizNo, reqVO.getBizNo()) + .groupBy(ErpFinancePaymentDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpFinancePaymentDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpFinancePaymentDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpFinancePaymentDO::getId, id).eq(ErpFinancePaymentDO::getStatus, status)); + } + + default ErpFinancePaymentDO selectByNo(String no) { + return selectOne(ErpFinancePaymentDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java new file mode 100644 index 0000000..cb6082b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * ERP 收款单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpFinanceReceiptItemMapper extends BaseMapperX { + + default List selectListByReceiptId(Long receiptId) { + return selectList(ErpFinanceReceiptItemDO::getReceiptId, receiptId); + } + + default List selectListByReceiptIds(Collection receiptIds) { + return selectList(ErpFinanceReceiptItemDO::getReceiptId, receiptIds); + } + + default BigDecimal selectReceiptPriceSumByBizIdAndBizType(Long bizId, Integer bizType) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(receipt_price) AS receiptPriceSum") + .eq("biz_id", bizId) + .eq("biz_type", bizType)); + // 获得数量 + if (CollUtil.isEmpty(result)) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "receiptPriceSum", 0D)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptMapper.java new file mode 100644 index 0000000..d895ade --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptMapper.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 收款单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpFinanceReceiptMapper extends BaseMapperX { + + default PageResult selectPage(ErpFinanceReceiptPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpFinanceReceiptDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpFinanceReceiptDO::getReceiptTime, reqVO.getReceiptTime()) + .eqIfPresent(ErpFinanceReceiptDO::getCustomerId, reqVO.getCustomerId()) + .eqIfPresent(ErpFinanceReceiptDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpFinanceReceiptDO::getFinanceUserId, reqVO.getFinanceUserId()) + .eqIfPresent(ErpFinanceReceiptDO::getAccountId, reqVO.getAccountId()) + .eqIfPresent(ErpFinanceReceiptDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpFinanceReceiptDO::getRemark, reqVO.getRemark()) + .orderByDesc(ErpFinanceReceiptDO::getId); + if (reqVO.getBizNo() != null) { + query.leftJoin(ErpFinanceReceiptItemDO.class, ErpFinanceReceiptItemDO::getReceiptId, ErpFinanceReceiptDO::getId) + .eq(reqVO.getBizNo() != null, ErpFinanceReceiptItemDO::getBizNo, reqVO.getBizNo()) + .groupBy(ErpFinanceReceiptDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpFinanceReceiptDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpFinanceReceiptDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpFinanceReceiptDO::getId, id).eq(ErpFinanceReceiptDO::getStatus, status)); + } + + default ErpFinanceReceiptDO selectByNo(String no) { + return selectOne(ErpFinanceReceiptDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductCategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductCategoryMapper.java new file mode 100644 index 0000000..70bbc64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductCategoryMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.product; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 产品分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpProductCategoryMapper extends BaseMapperX { + + default List selectList(ErpProductCategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(ErpProductCategoryDO::getName, reqVO.getName()) + .eqIfPresent(ErpProductCategoryDO::getStatus, reqVO.getStatus()) + .orderByDesc(ErpProductCategoryDO::getId)); + } + + default ErpProductCategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(ErpProductCategoryDO::getParentId, parentId, ErpProductCategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(ErpProductCategoryDO::getParentId, parentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java new file mode 100644 index 0000000..ff491fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 产品 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpProductMapper extends BaseMapperX { + + default PageResult selectPage(ErpProductPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpProductDO::getName, reqVO.getName()) + .eqIfPresent(ErpProductDO::getCategoryId, reqVO.getCategoryId()) + .betweenIfPresent(ErpProductDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErpProductDO::getId)); + } + + default Long selectCountByCategoryId(Long categoryId) { + return selectCount(ErpProductDO::getCategoryId, categoryId); + } + + default Long selectCountByUnitId(Long unitId) { + return selectCount(ErpProductDO::getUnitId, unitId); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpProductDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java new file mode 100644 index 0000000..45db6a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 产品单位 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpProductUnitMapper extends BaseMapperX { + + default PageResult selectPage(ErpProductUnitPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpProductUnitDO::getName, reqVO.getName()) + .eqIfPresent(ErpProductUnitDO::getStatus, reqVO.getStatus()) + .orderByDesc(ErpProductUnitDO::getId)); + } + + default ErpProductUnitDO selectByName(String name) { + return selectOne(ErpProductUnitDO::getName, name); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpProductUnitDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java new file mode 100644 index 0000000..9140f95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 采购入库项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseInItemMapper extends BaseMapperX { + + default List selectListByInId(Long inId) { + return selectList(ErpPurchaseInItemDO::getInId, inId); + } + + default List selectListByInIds(Collection inIds) { + return selectList(ErpPurchaseInItemDO::getInId, inIds); + } + + default int deleteByInId(Long inId) { + return delete(ErpPurchaseInItemDO::getInId, inId); + } + + /** + * 基于采购订单编号,查询每个采购订单项的入库数量之和 + * + * @param inIds 入库订单项编号数组 + * @return key:采购订单项编号;value:入库数量之和 + */ + default Map selectOrderItemCountSumMapByInIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyMap(); + } + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("order_item_id, SUM(count) AS sumCount") + .groupBy("order_item_id") + .in("in_id", inIds)); + // 获得数量 + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInMapper.java new file mode 100644 index 0000000..c155d8c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInMapper.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Objects; + +/** + * ERP 采购入库 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseInMapper extends BaseMapperX { + + default PageResult selectPage(ErpPurchaseInPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpPurchaseInDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpPurchaseInDO::getSupplierId, reqVO.getSupplierId()) + .betweenIfPresent(ErpPurchaseInDO::getInTime, reqVO.getInTime()) + .eqIfPresent(ErpPurchaseInDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpPurchaseInDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpPurchaseInDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpPurchaseInDO::getAccountId, reqVO.getAccountId()) + .likeIfPresent(ErpPurchaseInDO::getOrderNo, reqVO.getOrderNo()) + .orderByDesc(ErpPurchaseInDO::getId); + // 付款状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报字段不存在的错误 + if (Objects.equals(reqVO.getPaymentStatus(), ErpPurchaseInPageReqVO.PAYMENT_STATUS_NONE)) { + query.eq(ErpPurchaseInDO::getPaymentPrice, 0); + } else if (Objects.equals(reqVO.getPaymentStatus(), ErpPurchaseInPageReqVO.PAYMENT_STATUS_PART)) { + query.gt(ErpPurchaseInDO::getPaymentPrice, 0).apply("t.payment_price < t.total_price"); + } else if (Objects.equals(reqVO.getPaymentStatus(), ErpPurchaseInPageReqVO.PAYMENT_STATUS_ALL)) { + query.apply("t.payment_price = t.total_price"); + } + if (Boolean.TRUE.equals(reqVO.getPaymentEnable())) { + query.eq(ErpPurchaseInDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.payment_price < t.total_price"); + } + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpPurchaseInItemDO.class, ErpPurchaseInItemDO::getInId, ErpPurchaseInDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpPurchaseInItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpPurchaseInItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpPurchaseInDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpPurchaseInDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpPurchaseInDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpPurchaseInDO::getId, id).eq(ErpPurchaseInDO::getStatus, status)); + } + + default ErpPurchaseInDO selectByNo(String no) { + return selectOne(ErpPurchaseInDO::getNo, no); + } + + default List selectListByOrderId(Long orderId) { + return selectList(ErpPurchaseInDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderItemMapper.java new file mode 100644 index 0000000..17f1fe2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 采购订单明项目 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseOrderItemMapper extends BaseMapperX { + + default List selectListByOrderId(Long orderId) { + return selectList(ErpPurchaseOrderItemDO::getOrderId, orderId); + } + + default List selectListByOrderIds(Collection orderIds) { + return selectList(ErpPurchaseOrderItemDO::getOrderId, orderIds); + } + + default int deleteByOrderId(Long orderId) { + return delete(ErpPurchaseOrderItemDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java new file mode 100644 index 0000000..01f0303 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Objects; + +/** + * ERP 采购订单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseOrderMapper extends BaseMapperX { + + default PageResult selectPage(ErpPurchaseOrderPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpPurchaseOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpPurchaseOrderDO::getSupplierId, reqVO.getSupplierId()) + .betweenIfPresent(ErpPurchaseOrderDO::getOrderTime, reqVO.getOrderTime()) + .eqIfPresent(ErpPurchaseOrderDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpPurchaseOrderDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpPurchaseOrderDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpPurchaseOrderDO::getId); + // 入库状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报 in_count 错误 + if (Objects.equals(reqVO.getInStatus(), ErpPurchaseOrderPageReqVO.IN_STATUS_NONE)) { + query.eq(ErpPurchaseOrderDO::getInCount, 0); + } else if (Objects.equals(reqVO.getInStatus(), ErpPurchaseOrderPageReqVO.IN_STATUS_PART)) { + query.gt(ErpPurchaseOrderDO::getInCount, 0).apply("t.in_count < t.total_count"); + } else if (Objects.equals(reqVO.getInStatus(), ErpPurchaseOrderPageReqVO.IN_STATUS_ALL)) { + query.apply("t.in_count = t.total_count"); + } + // 退货状态 + if (Objects.equals(reqVO.getReturnStatus(), ErpPurchaseOrderPageReqVO.RETURN_STATUS_NONE)) { + query.eq(ErpPurchaseOrderDO::getReturnCount, 0); + } else if (Objects.equals(reqVO.getReturnStatus(), ErpPurchaseOrderPageReqVO.RETURN_STATUS_PART)) { + query.gt(ErpPurchaseOrderDO::getReturnCount, 0).apply("t.return_count < t.total_count"); + } else if (Objects.equals(reqVO.getReturnStatus(), ErpPurchaseOrderPageReqVO.RETURN_STATUS_ALL)) { + query.apply("t.return_count = t.total_count"); + } + // 可采购入库 + if (Boolean.TRUE.equals(reqVO.getInEnable())) { + query.eq(ErpPurchaseOrderDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.in_count < t.total_count"); + } + // 可采购退货 + if (Boolean.TRUE.equals(reqVO.getReturnEnable())) { + query.eq(ErpPurchaseOrderDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.return_count < t.in_count"); + } + if (reqVO.getProductId() != null) { + query.leftJoin(ErpPurchaseOrderItemDO.class, ErpPurchaseOrderItemDO::getOrderId, ErpPurchaseOrderDO::getId) + .eq(reqVO.getProductId() != null, ErpPurchaseOrderItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpPurchaseOrderDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpPurchaseOrderDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpPurchaseOrderDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpPurchaseOrderDO::getId, id).eq(ErpPurchaseOrderDO::getStatus, status)); + } + + default ErpPurchaseOrderDO selectByNo(String no) { + return selectOne(ErpPurchaseOrderDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java new file mode 100644 index 0000000..2a80119 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 采购退货项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseReturnItemMapper extends BaseMapperX { + + default List selectListByReturnId(Long returnId) { + return selectList(ErpPurchaseReturnItemDO::getReturnId, returnId); + } + + default List selectListByReturnIds(Collection returnIds) { + return selectList(ErpPurchaseReturnItemDO::getReturnId, returnIds); + } + + default int deleteByReturnId(Long returnId) { + return delete(ErpPurchaseReturnItemDO::getReturnId, returnId); + } + + /** + * 基于采购订单编号,查询每个采购订单项的退货数量之和 + * + * @param returnIds 入库订单项编号数组 + * @return key:采购订单项编号;value:退货数量之和 + */ + default Map selectOrderItemCountSumMapByReturnIds(Collection returnIds) { + if (CollUtil.isEmpty(returnIds)) { + return Collections.emptyMap(); + } + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("order_item_id, SUM(count) AS sumCount") + .groupBy("order_item_id") + .in("return_id", returnIds)); + // 获得数量 + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnMapper.java new file mode 100644 index 0000000..689a55d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnMapper.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Objects; + +/** + * ERP 采购退货 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseReturnMapper extends BaseMapperX { + + default PageResult selectPage(ErpPurchaseReturnPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpPurchaseReturnDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpPurchaseReturnDO::getSupplierId, reqVO.getSupplierId()) + .betweenIfPresent(ErpPurchaseReturnDO::getReturnTime, reqVO.getReturnTime()) + .eqIfPresent(ErpPurchaseReturnDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpPurchaseReturnDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpPurchaseReturnDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpPurchaseReturnDO::getAccountId, reqVO.getAccountId()) + .likeIfPresent(ErpPurchaseReturnDO::getOrderNo, reqVO.getOrderNo()) + .orderByDesc(ErpPurchaseReturnDO::getId); + // 退款状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报字段不存在的错误 + if (Objects.equals(reqVO.getRefundStatus(), ErpPurchaseReturnPageReqVO.REFUND_STATUS_NONE)) { + query.eq(ErpPurchaseReturnDO::getRefundPrice, 0); + } else if (Objects.equals(reqVO.getRefundStatus(), ErpPurchaseReturnPageReqVO.REFUND_STATUS_PART)) { + query.gt(ErpPurchaseReturnDO::getRefundPrice, 0).apply("t.refund_price < t.total_price"); + } else if (Objects.equals(reqVO.getRefundStatus(), ErpPurchaseReturnPageReqVO.REFUND_STATUS_ALL)) { + query.apply("t.refund_price = t.total_price"); + } + if (Boolean.TRUE.equals(reqVO.getRefundEnable())) { + query.eq(ErpPurchaseInDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.refund_price < t.total_price"); + } + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpPurchaseReturnItemDO.class, ErpPurchaseReturnItemDO::getReturnId, ErpPurchaseReturnDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpPurchaseReturnItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpPurchaseReturnItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpPurchaseReturnDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpPurchaseReturnDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpPurchaseReturnDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpPurchaseReturnDO::getId, id).eq(ErpPurchaseReturnDO::getStatus, status)); + } + + default ErpPurchaseReturnDO selectByNo(String no) { + return selectOne(ErpPurchaseReturnDO::getNo, no); + } + + default List selectListByOrderId(Long orderId) { + return selectList(ErpPurchaseReturnDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java new file mode 100644 index 0000000..c74f1e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpSupplierMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 供应商 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSupplierMapper extends BaseMapperX { + + default PageResult selectPage(ErpSupplierPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpSupplierDO::getName, reqVO.getName()) + .likeIfPresent(ErpSupplierDO::getMobile, reqVO.getMobile()) + .likeIfPresent(ErpSupplierDO::getTelephone, reqVO.getTelephone()) + .orderByDesc(ErpSupplierDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpSupplierDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java new file mode 100644 index 0000000..4970f9a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpCustomerMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 客户 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpCustomerMapper extends BaseMapperX { + + default PageResult selectPage(ErpCustomerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpCustomerDO::getName, reqVO.getName()) + .eqIfPresent(ErpCustomerDO::getMobile, reqVO.getMobile()) + .eqIfPresent(ErpCustomerDO::getTelephone, reqVO.getTelephone()) + .orderByDesc(ErpCustomerDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpCustomerDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java new file mode 100644 index 0000000..d2825e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 销售订单明项目 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleOrderItemMapper extends BaseMapperX { + + default List selectListByOrderId(Long orderId) { + return selectList(ErpSaleOrderItemDO::getOrderId, orderId); + } + + default List selectListByOrderIds(Collection orderIds) { + return selectList(ErpSaleOrderItemDO::getOrderId, orderIds); + } + + default int deleteByOrderId(Long orderId) { + return delete(ErpSaleOrderItemDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java new file mode 100644 index 0000000..8ed3b6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOrderMapper.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Objects; + +/** + * ERP 销售订单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleOrderMapper extends BaseMapperX { + + default PageResult selectPage(ErpSaleOrderPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpSaleOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpSaleOrderDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(ErpSaleOrderDO::getOrderTime, reqVO.getOrderTime()) + .eqIfPresent(ErpSaleOrderDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpSaleOrderDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpSaleOrderDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpSaleOrderDO::getId); + // 入库状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报 out_count 错误 + if (Objects.equals(reqVO.getOutStatus(), ErpSaleOrderPageReqVO.OUT_STATUS_NONE)) { + query.eq(ErpSaleOrderDO::getOutCount, 0); + } else if (Objects.equals(reqVO.getOutStatus(), ErpSaleOrderPageReqVO.OUT_STATUS_PART)) { + query.gt(ErpSaleOrderDO::getOutCount, 0).apply("t.out_count < t.total_count"); + } else if (Objects.equals(reqVO.getOutStatus(), ErpSaleOrderPageReqVO.OUT_STATUS_ALL)) { + query.apply("t.out_count = t.total_count"); + } + // 退货状态 + if (Objects.equals(reqVO.getReturnStatus(), ErpSaleOrderPageReqVO.RETURN_STATUS_NONE)) { + query.eq(ErpSaleOrderDO::getReturnCount, 0); + } else if (Objects.equals(reqVO.getReturnStatus(), ErpSaleOrderPageReqVO.RETURN_STATUS_PART)) { + query.gt(ErpSaleOrderDO::getReturnCount, 0).apply("t.return_count < t.total_count"); + } else if (Objects.equals(reqVO.getReturnStatus(), ErpSaleOrderPageReqVO.RETURN_STATUS_ALL)) { + query.apply("t.return_count = t.total_count"); + } + // 可销售出库 + if (Boolean.TRUE.equals(reqVO.getOutEnable())) { + query.eq(ErpSaleOrderDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.out_count < t.total_count"); + } + // 可销售退货 + if (Boolean.TRUE.equals(reqVO.getReturnEnable())) { + query.eq(ErpSaleOrderDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.return_count < t.out_count"); + } + if (reqVO.getProductId() != null) { + query.leftJoin(ErpSaleOrderItemDO.class, ErpSaleOrderItemDO::getOrderId, ErpSaleOrderDO::getId) + .eq(reqVO.getProductId() != null, ErpSaleOrderItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpSaleOrderDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpSaleOrderDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpSaleOrderDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpSaleOrderDO::getId, id).eq(ErpSaleOrderDO::getStatus, status)); + } + + default ErpSaleOrderDO selectByNo(String no) { + return selectOne(ErpSaleOrderDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java new file mode 100644 index 0000000..9cd5ded --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 销售出库项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleOutItemMapper extends BaseMapperX { + + default List selectListByOutId(Long outId) { + return selectList(ErpSaleOutItemDO::getOutId, outId); + } + + default List selectListByOutIds(Collection outIds) { + return selectList(ErpSaleOutItemDO::getOutId, outIds); + } + + default int deleteByOutId(Long outId) { + return delete(ErpSaleOutItemDO::getOutId, outId); + } + + /** + * 基于销售订单编号,查询每个销售订单项的出库数量之和 + * + * @param outIds 出库订单项编号数组 + * @return key:销售订单项编号;value:出库数量之和 + */ + default Map selectOrderItemCountSumMapByOutIds(Collection outIds) { + if (CollUtil.isEmpty(outIds)) { + return Collections.emptyMap(); + } + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("order_item_id, SUM(count) AS sumCount") + .groupBy("order_item_id") + .in("out_id", outIds)); + // 获得数量 + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutMapper.java new file mode 100644 index 0000000..128913f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutMapper.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Objects; + +/** + * ERP 销售出库 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleOutMapper extends BaseMapperX { + + default PageResult selectPage(ErpSaleOutPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpSaleOutDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpSaleOutDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(ErpSaleOutDO::getOutTime, reqVO.getOutTime()) + .eqIfPresent(ErpSaleOutDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpSaleOutDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpSaleOutDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpSaleOutDO::getAccountId, reqVO.getAccountId()) + .likeIfPresent(ErpSaleOutDO::getOrderNo, reqVO.getOrderNo()) + .orderByDesc(ErpSaleOutDO::getId); + // 收款状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报字段不存在的错误 + if (Objects.equals(reqVO.getReceiptStatus(), ErpSaleOutPageReqVO.RECEIPT_STATUS_NONE)) { + query.eq(ErpSaleOutDO::getReceiptPrice, 0); + } else if (Objects.equals(reqVO.getReceiptStatus(), ErpSaleOutPageReqVO.RECEIPT_STATUS_PART)) { + query.gt(ErpSaleOutDO::getReceiptPrice, 0).apply("t.receipt_price < t.total_price"); + } else if (Objects.equals(reqVO.getReceiptStatus(), ErpSaleOutPageReqVO.RECEIPT_STATUS_ALL)) { + query.apply("t.receipt_price = t.total_price"); + } + if (Boolean.TRUE.equals(reqVO.getReceiptEnable())) { + query.eq(ErpSaleOutDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.receipt_price < t.total_price"); + } + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpSaleOutItemDO.class, ErpSaleOutItemDO::getOutId, ErpSaleOutDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpSaleOutItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpSaleOutItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpSaleOutDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpSaleOutDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpSaleOutDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpSaleOutDO::getId, id).eq(ErpSaleOutDO::getStatus, status)); + } + + default ErpSaleOutDO selectByNo(String no) { + return selectOne(ErpSaleOutDO::getNo, no); + } + + default List selectListByOrderId(Long orderId) { + return selectList(ErpSaleOutDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java new file mode 100644 index 0000000..fdc5729 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 销售退货项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleReturnItemMapper extends BaseMapperX { + + default List selectListByReturnId(Long returnId) { + return selectList(ErpSaleReturnItemDO::getReturnId, returnId); + } + + default List selectListByReturnIds(Collection returnIds) { + return selectList(ErpSaleReturnItemDO::getReturnId, returnIds); + } + + default int deleteByReturnId(Long returnId) { + return delete(ErpSaleReturnItemDO::getReturnId, returnId); + } + + /** + * 基于销售订单编号,查询每个销售订单项的退货数量之和 + * + * @param returnIds 出库订单项编号数组 + * @return key:销售订单项编号;value:退货数量之和 + */ + default Map selectOrderItemCountSumMapByReturnIds(Collection returnIds) { + if (CollUtil.isEmpty(returnIds)) { + return Collections.emptyMap(); + } + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("order_item_id, SUM(count) AS sumCount") + .groupBy("order_item_id") + .in("return_id", returnIds)); + // 获得数量 + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnMapper.java new file mode 100644 index 0000000..867b454 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnMapper.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.sale; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Objects; + +/** + * ERP 销售退货 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleReturnMapper extends BaseMapperX { + + default PageResult selectPage(ErpSaleReturnPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpSaleReturnDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpSaleReturnDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(ErpSaleReturnDO::getReturnTime, reqVO.getReturnTime()) + .eqIfPresent(ErpSaleReturnDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpSaleReturnDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpSaleReturnDO::getCreator, reqVO.getCreator()) + .eqIfPresent(ErpSaleReturnDO::getAccountId, reqVO.getAccountId()) + .likeIfPresent(ErpSaleReturnDO::getOrderNo, reqVO.getOrderNo()) + .orderByDesc(ErpSaleReturnDO::getId); + // 退款状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报字段不存在的错误 + if (Objects.equals(reqVO.getRefundStatus(), ErpSaleReturnPageReqVO.REFUND_STATUS_NONE)) { + query.eq(ErpSaleReturnDO::getRefundPrice, 0); + } else if (Objects.equals(reqVO.getRefundStatus(), ErpSaleReturnPageReqVO.REFUND_STATUS_PART)) { + query.gt(ErpSaleReturnDO::getRefundPrice, 0).apply("t.refund_price < t.total_price"); + } else if (Objects.equals(reqVO.getRefundStatus(), ErpSaleReturnPageReqVO.REFUND_STATUS_ALL)) { + query.apply("t.refund_price = t.total_price"); + } + if (Boolean.TRUE.equals(reqVO.getRefundEnable())) { + query.eq(ErpSaleOutDO::getStatus, ErpAuditStatus.APPROVE.getStatus()) + .apply("t.refund_price < t.total_price"); + } + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpSaleReturnItemDO.class, ErpSaleReturnItemDO::getReturnId, ErpSaleReturnDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpSaleReturnItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpSaleReturnItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpSaleReturnDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpSaleReturnDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpSaleReturnDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpSaleReturnDO::getId, id).eq(ErpSaleReturnDO::getStatus, status)); + } + + default ErpSaleReturnDO selectByNo(String no) { + return selectOne(ErpSaleReturnDO::getNo, no); + } + + default List selectListByOrderId(Long orderId) { + return selectList(ErpSaleReturnDO::getOrderId, orderId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java new file mode 100644 index 0000000..14b4e51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.statistics; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购统计 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpPurchaseStatisticsMapper { + + BigDecimal getPurchasePrice(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java new file mode 100644 index 0000000..b29f194 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.statistics; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售统计 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpSaleStatisticsMapper { + + BigDecimal getSalePrice(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java new file mode 100644 index 0000000..ae13f9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存盘点单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockCheckItemMapper extends BaseMapperX { + + default List selectListByCheckId(Long checkId) { + return selectList(ErpStockCheckItemDO::getCheckId, checkId); + } + + default List selectListByCheckIds(Collection checkIds) { + return selectList(ErpStockCheckItemDO::getCheckId, checkIds); + } + + default int deleteByCheckId(Long checkId) { + return delete(ErpStockCheckItemDO::getCheckId, checkId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java new file mode 100644 index 0000000..dd976df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 库存调拨单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockCheckMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockCheckPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpStockCheckDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpStockCheckDO::getCheckTime, reqVO.getCheckTime()) + .eqIfPresent(ErpStockCheckDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockCheckDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockCheckDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockCheckItemDO.class, ErpStockCheckItemDO::getCheckId, ErpStockCheckDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockCheckItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockCheckDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockCheckDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockCheckDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockCheckDO::getId, id).eq(ErpStockCheckDO::getStatus, status)); + } + + default ErpStockCheckDO selectByNo(String no) { + return selectOne(ErpStockCheckDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java new file mode 100644 index 0000000..2731aa7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它入库单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockInItemMapper extends BaseMapperX { + + default List selectListByInId(Long inId) { + return selectList(ErpStockInItemDO::getInId, inId); + } + + default List selectListByInIds(Collection inIds) { + return selectList(ErpStockInItemDO::getInId, inIds); + } + + default int deleteByInId(Long inId) { + return delete(ErpStockInItemDO::getInId, inId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java new file mode 100644 index 0000000..e815583 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockInMapper.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 其它入库单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockInMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockInPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpStockInDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpStockInDO::getSupplierId, reqVO.getSupplierId()) + .betweenIfPresent(ErpStockInDO::getInTime, reqVO.getInTime()) + .eqIfPresent(ErpStockInDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockInDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockInDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockInDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockInItemDO.class, ErpStockInItemDO::getInId, ErpStockInDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockInItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockInItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockInDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockInDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockInDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockInDO::getId, id).eq(ErpStockInDO::getStatus, status)); + } + + default ErpStockInDO selectByNo(String no) { + return selectOne(ErpStockInDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java new file mode 100644 index 0000000..0ebc985 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * ERP 产品库存 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErpStockDO::getProductId, reqVO.getProductId()) + .eqIfPresent(ErpStockDO::getWarehouseId, reqVO.getWarehouseId()) + .orderByDesc(ErpStockDO::getId)); + } + + default ErpStockDO selectByProductIdAndWarehouseId(Long productId, Long warehouseId) { + return selectOne(ErpStockDO::getProductId, productId, + ErpStockDO::getWarehouseId, warehouseId); + } + + default int updateCountIncrement(Long id, BigDecimal count, boolean negativeEnable) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + .eq(ErpStockDO::getId, id); + if (count.compareTo(BigDecimal.ZERO) > 0) { + updateWrapper.setSql("count = count + " + count); + } else if (count.compareTo(BigDecimal.ZERO) < 0) { + if (!negativeEnable) { + updateWrapper.ge(ErpStockDO::getCount, count.abs()); + } + updateWrapper.setSql("count = count - " + count.abs()); + } + return update(null, updateWrapper); + } + + default BigDecimal selectSumByProductId(Long productId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("product_id", productId)); + // 获得数量 + if (CollUtil.isEmpty(result)) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "sumCount", 0D)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java new file mode 100644 index 0000000..21a2670 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存调拨单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMoveItemMapper extends BaseMapperX { + + default List selectListByMoveId(Long moveId) { + return selectList(ErpStockMoveItemDO::getMoveId, moveId); + } + + default List selectListByMoveIds(Collection moveIds) { + return selectList(ErpStockMoveItemDO::getMoveId, moveIds); + } + + default int deleteByMoveId(Long moveId) { + return delete(ErpStockMoveItemDO::getMoveId, moveId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java new file mode 100644 index 0000000..9a8ce0b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 库存调拨单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockMoveMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockMovePageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpStockMoveDO::getNo, reqVO.getNo()) + .betweenIfPresent(ErpStockMoveDO::getMoveTime, reqVO.getMoveTime()) + .eqIfPresent(ErpStockMoveDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockMoveDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockMoveDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockMoveDO::getId); + if (reqVO.getFromWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockMoveItemDO.class, ErpStockMoveItemDO::getMoveId, ErpStockMoveDO::getId) + .eq(reqVO.getFromWarehouseId() != null, ErpStockMoveItemDO::getFromWarehouseId, reqVO.getFromWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockMoveItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockMoveDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockMoveDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockMoveDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockMoveDO::getId, id).eq(ErpStockMoveDO::getStatus, status)); + } + + default ErpStockMoveDO selectByNo(String no) { + return selectOne(ErpStockMoveDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java new file mode 100644 index 0000000..3b27cd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutItemMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它出库单项 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockOutItemMapper extends BaseMapperX { + + default List selectListByOutId(Long outId) { + return selectList(ErpStockOutItemDO::getOutId, outId); + } + + default List selectListByOutIds(Collection outIds) { + return selectList(ErpStockOutItemDO::getOutId, outIds); + } + + default int deleteByOutId(Long outId) { + return delete(ErpStockOutItemDO::getOutId, outId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java new file mode 100644 index 0000000..a73dd3c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockOutMapper.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 其它出库单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockOutMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockOutPageReqVO reqVO) { + MPJLambdaWrapperX query = new MPJLambdaWrapperX() + .likeIfPresent(ErpStockOutDO::getNo, reqVO.getNo()) + .eqIfPresent(ErpStockOutDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(ErpStockOutDO::getOutTime, reqVO.getOutTime()) + .eqIfPresent(ErpStockOutDO::getStatus, reqVO.getStatus()) + .likeIfPresent(ErpStockOutDO::getRemark, reqVO.getRemark()) + .eqIfPresent(ErpStockOutDO::getCreator, reqVO.getCreator()) + .orderByDesc(ErpStockOutDO::getId); + if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { + query.leftJoin(ErpStockOutItemDO.class, ErpStockOutItemDO::getOutId, ErpStockOutDO::getId) + .eq(reqVO.getWarehouseId() != null, ErpStockOutItemDO::getWarehouseId, reqVO.getWarehouseId()) + .eq(reqVO.getProductId() != null, ErpStockOutItemDO::getProductId, reqVO.getProductId()) + .groupBy(ErpStockOutDO::getId); // 避免 1 对多查询,产生相同的 1 + } + return selectJoinPage(reqVO, ErpStockOutDO.class, query); + } + + default int updateByIdAndStatus(Long id, Integer status, ErpStockOutDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(ErpStockOutDO::getId, id).eq(ErpStockOutDO::getStatus, status)); + } + + default ErpStockOutDO selectByNo(String no) { + return selectOne(ErpStockOutDO::getNo, no); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java new file mode 100644 index 0000000..bfd8b67 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockRecordMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ERP 产品库存明细 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpStockRecordMapper extends BaseMapperX { + + default PageResult selectPage(ErpStockRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErpStockRecordDO::getProductId, reqVO.getProductId()) + .eqIfPresent(ErpStockRecordDO::getWarehouseId, reqVO.getWarehouseId()) + .eqIfPresent(ErpStockRecordDO::getBizType, reqVO.getBizType()) + .likeIfPresent(ErpStockRecordDO::getBizNo, reqVO.getBizNo()) + .betweenIfPresent(ErpStockRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErpStockRecordDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java new file mode 100644 index 0000000..0442011 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * ERP 仓库 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ErpWarehouseMapper extends BaseMapperX { + + default PageResult selectPage(ErpWarehousePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpWarehouseDO::getName, reqVO.getName()) + .eqIfPresent(ErpWarehouseDO::getStatus, reqVO.getStatus()) + .orderByDesc(ErpWarehouseDO::getId)); + } + + default ErpWarehouseDO selectByDefaultStatus() { + return selectOne(ErpWarehouseDO::getDefaultStatus, true); + } + + default List selectListByStatus(Integer status) { + return selectList(ErpWarehouseDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..06ec313 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.erp.dal.redis; + +/** + * ERP Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 序号的缓存 + * + * KEY 格式:seq_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String NO = "erp:seq_no:"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java new file mode 100644 index 0000000..f7d976d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.erp.dal.redis.no; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + + +/** + * Erp 订单序号的 Redis DAO + * + * @author HUIHUI + */ +@Repository +public class ErpNoRedisDAO { + + /** + * 其它入库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO} + */ + public static final String STOCK_IN_NO_PREFIX = "QTRK"; + /** + * 其它出库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO} + */ + public static final String STOCK_OUT_NO_PREFIX = "QCKD"; + + /** + * 库存调拨 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO} + */ + public static final String STOCK_MOVE_NO_PREFIX = "QCDB"; + + /** + * 库存盘点 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO} + */ + public static final String STOCK_CHECK_NO_PREFIX = "QCPD"; + + /** + * 销售订单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO} + */ + public static final String SALE_ORDER_NO_PREFIX = "XSDD"; + /** + * 销售出库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO} + */ + public static final String SALE_OUT_NO_PREFIX = "XSCK"; + /** + * 销售退货 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO} + */ + public static final String SALE_RETURN_NO_PREFIX = "XSTH"; + + /** + * 采购订单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO} + */ + public static final String PURCHASE_ORDER_NO_PREFIX = "CGDD"; + /** + * 采购入库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO} + */ + public static final String PURCHASE_IN_NO_PREFIX = "CGRK"; + /** + * 采购退货 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO} + */ + public static final String PURCHASE_RETURN_NO_PREFIX = "CGTH"; + + /** + * 付款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO} + */ + public static final String FINANCE_PAYMENT_NO_PREFIX = "FKD"; + /** + * 收款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO} + */ + public static final String FINANCE_RECEIPT_NO_PREFIX = "SKD"; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增 + * 例如说:QTRK 202109 000001 (没有中间空格) + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); + String key = RedisKeyConstants.NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofDays(1L)); + return noPrefix + String.format("%06d", no); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/package-info.java new file mode 100644 index 0000000..af7bc12 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 erp 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.erp.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/config/ErpWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/config/ErpWebConfiguration.java new file mode 100644 index 0000000..5d866a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/config/ErpWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * erp 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class ErpWebConfiguration { + + /** + * erp 模块的 API 分组 + */ + @Bean + public GroupedOpenApi erpGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("erp"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/package-info.java new file mode 100644 index 0000000..70f70c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * trade 模块的 web 配置 + */ +package cn.iocoder.yudao.module.erp.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/package-info.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/package-info.java new file mode 100644 index 0000000..2608a98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/package-info.java @@ -0,0 +1,10 @@ +/** + * erp 包下,企业资源管理(Enterprise Resource Planning)。 + * 例如说:采购、销售、库存、财务、产品等等 + * + * 1. Controller URL:以 /erp/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 erp_ 开头,方便在数据库中区分 + * + * 注意,由于 Erp 模块下,容易和其它模块重名,所以类名都加载 Erp 的前缀~ + */ +package cn.iocoder.yudao.module.erp; diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountService.java new file mode 100644 index 0000000..9226e15 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 结算账户 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpAccountService { + + /** + * 创建结算账户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAccount(@Valid ErpAccountSaveReqVO createReqVO); + + /** + * 更新ERP 结算账户 + * + * @param updateReqVO 更新信息 + */ + void updateAccount(@Valid ErpAccountSaveReqVO updateReqVO); + + /** + * 更新结算账户默认状态 + * + * @param id 编号 + * @param defaultStatus 默认状态 + */ + void updateAccountDefaultStatus(Long id, Boolean defaultStatus); + + /** + * 删除结算账户 + * + * @param id 编号 + */ + void deleteAccount(Long id); + + /** + * 获得结算账户 + * + * @param id 编号 + * @return 结算账户 + */ + ErpAccountDO getAccount(Long id); + + /** + * 校验结算账户 + * + * @param id 编号 + * @return 结算账户 + */ + ErpAccountDO validateAccount(Long id); + + /** + * 获得指定状态的结算账户列表 + * + * @param status 状态 + * @return 结算账户 + */ + List getAccountListByStatus(Integer status); + + /** + * 获得结算账户列表 + * + * @param ids 编号数组 + * @return 结算账户列表 + */ + List getAccountList(Collection ids); + + /** + * 获得结算账户 Map + * + * @param ids 编号数组 + * @return 结算账户 Map + */ + default Map getAccountMap(Collection ids) { + return convertMap(getAccountList(ids), ErpAccountDO::getId); + } + + /** + * 获得结算账户分页 + * + * @param pageReqVO 分页查询 + * @return 结算账户分页 + */ + PageResult getAccountPage(ErpAccountPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountServiceImpl.java new file mode 100644 index 0000000..578698b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpAccountServiceImpl.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.account.ErpAccountSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpAccountMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.ACCOUNT_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.ACCOUNT_NOT_EXISTS; + +/** + * ERP 结算账户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpAccountServiceImpl implements ErpAccountService { + + @Resource + private ErpAccountMapper accountMapper; + + @Override + public Long createAccount(ErpAccountSaveReqVO createReqVO) { + // 插入 + ErpAccountDO account = BeanUtils.toBean(createReqVO, ErpAccountDO.class); + accountMapper.insert(account); + // 返回 + return account.getId(); + } + + @Override + public void updateAccount(ErpAccountSaveReqVO updateReqVO) { + // 校验存在 + validateAccountExists(updateReqVO.getId()); + // 更新 + ErpAccountDO updateObj = BeanUtils.toBean(updateReqVO, ErpAccountDO.class); + accountMapper.updateById(updateObj); + } + + @Override + public void updateAccountDefaultStatus(Long id, Boolean defaultStatus) { + // 1. 校验存在 + validateAccountExists(id); + + // 2.1 如果开启,则需要关闭所有其它的默认 + if (defaultStatus) { + ErpAccountDO account = accountMapper.selectByDefaultStatus(); + if (account != null) { + accountMapper.updateById(new ErpAccountDO().setId(account.getId()).setDefaultStatus(false)); + } + } + // 2.2 更新对应的默认状态 + accountMapper.updateById(new ErpAccountDO().setId(id).setDefaultStatus(defaultStatus)); + } + + @Override + public void deleteAccount(Long id) { + // 校验存在 + validateAccountExists(id); + // 删除 + accountMapper.deleteById(id); + } + + private void validateAccountExists(Long id) { + if (accountMapper.selectById(id) == null) { + throw exception(ACCOUNT_NOT_EXISTS); + } + } + + @Override + public ErpAccountDO getAccount(Long id) { + return accountMapper.selectById(id); + } + + @Override + public ErpAccountDO validateAccount(Long id) { + ErpAccountDO account = accountMapper.selectById(id); + if (account == null) { + throw exception(ACCOUNT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(account.getStatus())) { + throw exception(ACCOUNT_NOT_ENABLE, account.getName()); + } + return account; + } + + @Override + public List getAccountListByStatus(Integer status) { + return accountMapper.selectListByStatus(status); + } + + @Override + public List getAccountList(Collection ids) { + return accountMapper.selectBatchIds(ids); + } + + @Override + public PageResult getAccountPage(ErpAccountPageReqVO pageReqVO) { + return accountMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentService.java new file mode 100644 index 0000000..d66cfbe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 付款单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpFinancePaymentService { + + /** + * 创建付款单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFinancePayment(@Valid ErpFinancePaymentSaveReqVO createReqVO); + + /** + * 更新付款单 + * + * @param updateReqVO 更新信息 + */ + void updateFinancePayment(@Valid ErpFinancePaymentSaveReqVO updateReqVO); + + /** + * 更新付款单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateFinancePaymentStatus(Long id, Integer status); + + /** + * 删除付款单 + * + * @param ids 编号数组 + */ + void deleteFinancePayment(List ids); + + /** + * 获得付款单 + * + * @param id 编号 + * @return 付款单 + */ + ErpFinancePaymentDO getFinancePayment(Long id); + + /** + * 获得付款单分页 + * + * @param pageReqVO 分页查询 + * @return 付款单分页 + */ + PageResult getFinancePaymentPage(ErpFinancePaymentPageReqVO pageReqVO); + + // ==================== 付款单项 ==================== + + /** + * 获得付款单项列表 + * + * @param paymentId 付款单编号 + * @return 付款单项列表 + */ + List getFinancePaymentItemListByPaymentId(Long paymentId); + + /** + * 获得付款单项 List + * + * @param paymentIds 付款单编号数组 + * @return 付款单项 List + */ + List getFinancePaymentItemListByPaymentIds(Collection paymentIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentServiceImpl.java new file mode 100644 index 0000000..c7ed6b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinancePaymentServiceImpl.java @@ -0,0 +1,273 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment.ErpFinancePaymentSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinancePaymentItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinancePaymentMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseReturnService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 付款单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpFinancePaymentServiceImpl implements ErpFinancePaymentService { + + @Resource + private ErpFinancePaymentMapper financePaymentMapper; + @Resource + private ErpFinancePaymentItemMapper financePaymentItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpSupplierService supplierService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpPurchaseInService purchaseInService; + @Resource + private ErpPurchaseReturnService purchaseReturnService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createFinancePayment(ErpFinancePaymentSaveReqVO createReqVO) { + // 1.1 校验订单项的有效性 + List paymentItems = validateFinancePaymentItems( + createReqVO.getSupplierId(), createReqVO.getItems()); + // 1.2 校验供应商 + supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.3 校验结算账户 + if (createReqVO.getAccountId() != null) { + accountService.validateAccount(createReqVO.getAccountId()); + } + // 1.4 校验财务人员 + if (createReqVO.getFinanceUserId() != null) { + adminUserApi.validateUser(createReqVO.getFinanceUserId()); + } + // 1.5 生成付款单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.FINANCE_PAYMENT_NO_PREFIX); + if (financePaymentMapper.selectByNo(no) != null) { + throw exception(FINANCE_PAYMENT_NO_EXISTS); + } + + // 2.1 插入付款单 + ErpFinancePaymentDO payment = BeanUtils.toBean(createReqVO, ErpFinancePaymentDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())); + calculateTotalPrice(payment, paymentItems); + financePaymentMapper.insert(payment); + // 2.2 插入付款单项 + paymentItems.forEach(o -> o.setPaymentId(payment.getId())); + financePaymentItemMapper.insertBatch(paymentItems); + + // 3. 更新采购入库、退货的付款金额情况 + updatePurchasePrice(paymentItems); + return payment.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFinancePayment(ErpFinancePaymentSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpFinancePaymentDO payment = validateFinancePaymentExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(payment.getStatus())) { + throw exception(FINANCE_PAYMENT_UPDATE_FAIL_APPROVE, payment.getNo()); + } + // 1.2 校验供应商 + supplierService.validateSupplier(updateReqVO.getSupplierId()); + // 1.3 校验结算账户 + if (updateReqVO.getAccountId() != null) { + accountService.validateAccount(updateReqVO.getAccountId()); + } + // 1.4 校验财务人员 + if (updateReqVO.getFinanceUserId() != null) { + adminUserApi.validateUser(updateReqVO.getFinanceUserId()); + } + // 1.5 校验付款单项的有效性 + List paymentItems = validateFinancePaymentItems( + updateReqVO.getSupplierId(), updateReqVO.getItems()); + + // 2.1 更新付款单 + ErpFinancePaymentDO updateObj = BeanUtils.toBean(updateReqVO, ErpFinancePaymentDO.class); + calculateTotalPrice(updateObj, paymentItems); + financePaymentMapper.updateById(updateObj); + // 2.2 更新付款单项 + updateFinancePaymentItemList(updateReqVO.getId(), paymentItems); + } + + private void calculateTotalPrice(ErpFinancePaymentDO payment, List paymentItems) { + payment.setTotalPrice(getSumValue(paymentItems, ErpFinancePaymentItemDO::getPaymentPrice, BigDecimal::add, BigDecimal.ZERO)); + payment.setPaymentPrice(payment.getTotalPrice().subtract(payment.getDiscountPrice())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFinancePaymentStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpFinancePaymentDO payment = validateFinancePaymentExists(id); + // 1.2 校验状态 + if (payment.getStatus().equals(status)) { + throw exception(approve ? FINANCE_PAYMENT_APPROVE_FAIL : FINANCE_PAYMENT_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = financePaymentMapper.updateByIdAndStatus(id, payment.getStatus(), + new ErpFinancePaymentDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? FINANCE_PAYMENT_APPROVE_FAIL : FINANCE_PAYMENT_PROCESS_FAIL); + } + } + + private List validateFinancePaymentItems( + Long supplierId, + List list) { + return convertList(list, o -> BeanUtils.toBean(o, ErpFinancePaymentItemDO.class, item -> { + if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.PURCHASE_IN.getType())) { + ErpPurchaseInDO purchaseIn = purchaseInService.validatePurchaseIn(item.getBizId()); + Assert.equals(purchaseIn.getSupplierId(), supplierId, "供应商必须相同"); + item.setTotalPrice(purchaseIn.getTotalPrice()).setBizNo(purchaseIn.getNo()); + } else if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.PURCHASE_RETURN.getType())) { + ErpPurchaseReturnDO purchaseReturn = purchaseReturnService.validatePurchaseReturn(item.getBizId()); + Assert.equals(purchaseReturn.getSupplierId(), supplierId, "供应商必须相同"); + item.setTotalPrice(purchaseReturn.getTotalPrice().negate()).setBizNo(purchaseReturn.getNo()); + } else { + throw new IllegalArgumentException("业务类型不正确:" + item.getBizType()); + } + })); + } + + private void updateFinancePaymentItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = financePaymentItemMapper.selectListByPaymentId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setPaymentId(id)); + financePaymentItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + financePaymentItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + financePaymentItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpFinancePaymentItemDO::getId)); + } + + // 第三步,更新采购入库、退货的付款金额情况 + updatePurchasePrice(CollectionUtils.newArrayList(diffList)); + } + + private void updatePurchasePrice(List paymentItems) { + paymentItems.forEach(paymentItem -> { + BigDecimal totalPaymentPrice = financePaymentItemMapper.selectPaymentPriceSumByBizIdAndBizType( + paymentItem.getBizId(), paymentItem.getBizType()); + if (ErpBizTypeEnum.PURCHASE_IN.getType().equals(paymentItem.getBizType())) { + purchaseInService.updatePurchaseInPaymentPrice(paymentItem.getBizId(), totalPaymentPrice); + } else if (ErpBizTypeEnum.PURCHASE_RETURN.getType().equals(paymentItem.getBizType())) { + purchaseReturnService.updatePurchaseReturnRefundPrice(paymentItem.getBizId(), totalPaymentPrice.negate()); + } else { + throw new IllegalArgumentException("业务类型不正确:" + paymentItem.getBizType()); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteFinancePayment(List ids) { + // 1. 校验不处于已审批 + List payments = financePaymentMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(payments)) { + return; + } + payments.forEach(payment -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(payment.getStatus())) { + throw exception(FINANCE_PAYMENT_DELETE_FAIL_APPROVE, payment.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + payments.forEach(payment -> { + // 2.1 删除付款单 + financePaymentMapper.deleteById(payment.getId()); + // 2.2 删除付款单项 + List paymentItems = financePaymentItemMapper.selectListByPaymentId(payment.getId()); + financePaymentItemMapper.deleteBatchIds(convertSet(paymentItems, ErpFinancePaymentItemDO::getId)); + + // 2.3 更新采购入库、退货的付款金额情况 + updatePurchasePrice(paymentItems); + }); + } + + private ErpFinancePaymentDO validateFinancePaymentExists(Long id) { + ErpFinancePaymentDO payment = financePaymentMapper.selectById(id); + if (payment == null) { + throw exception(FINANCE_PAYMENT_NOT_EXISTS); + } + return payment; + } + + @Override + public ErpFinancePaymentDO getFinancePayment(Long id) { + return financePaymentMapper.selectById(id); + } + + @Override + public PageResult getFinancePaymentPage(ErpFinancePaymentPageReqVO pageReqVO) { + return financePaymentMapper.selectPage(pageReqVO); + } + + // ==================== 付款单项 ==================== + + @Override + public List getFinancePaymentItemListByPaymentId(Long paymentId) { + return financePaymentItemMapper.selectListByPaymentId(paymentId); + } + + @Override + public List getFinancePaymentItemListByPaymentIds(Collection paymentIds) { + if (CollUtil.isEmpty(paymentIds)) { + return Collections.emptyList(); + } + return financePaymentItemMapper.selectListByPaymentIds(paymentIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptService.java new file mode 100644 index 0000000..8e24d5d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 收款单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpFinanceReceiptService { + + /** + * 创建收款单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFinanceReceipt(@Valid ErpFinanceReceiptSaveReqVO createReqVO); + + /** + * 更新收款单 + * + * @param updateReqVO 更新信息 + */ + void updateFinanceReceipt(@Valid ErpFinanceReceiptSaveReqVO updateReqVO); + + /** + * 更新收款单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateFinanceReceiptStatus(Long id, Integer status); + + /** + * 删除收款单 + * + * @param ids 编号数组 + */ + void deleteFinanceReceipt(List ids); + + /** + * 获得收款单 + * + * @param id 编号 + * @return 收款单 + */ + ErpFinanceReceiptDO getFinanceReceipt(Long id); + + /** + * 获得收款单分页 + * + * @param pageReqVO 分页查询 + * @return 收款单分页 + */ + PageResult getFinanceReceiptPage(ErpFinanceReceiptPageReqVO pageReqVO); + + // ==================== 收款单项 ==================== + + /** + * 获得收款单项列表 + * + * @param receiptId 收款单编号 + * @return 收款单项列表 + */ + List getFinanceReceiptItemListByReceiptId(Long receiptId); + + /** + * 获得收款单项 List + * + * @param receiptIds 收款单编号数组 + * @return 收款单项 List + */ + List getFinanceReceiptItemListByReceiptIds(Collection receiptIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java new file mode 100644 index 0000000..031043a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/finance/ErpFinanceReceiptServiceImpl.java @@ -0,0 +1,273 @@ +package cn.iocoder.yudao.module.erp.service.finance; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt.ErpFinanceReceiptSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinanceReceiptItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.finance.ErpFinanceReceiptMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.common.ErpBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService; +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleReturnService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 收款单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpFinanceReceiptServiceImpl implements ErpFinanceReceiptService { + + @Resource + private ErpFinanceReceiptMapper financeReceiptMapper; + @Resource + private ErpFinanceReceiptItemMapper financeReceiptItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpCustomerService customerService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpSaleOutService saleOutService; + @Resource + private ErpSaleReturnService saleReturnService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createFinanceReceipt(ErpFinanceReceiptSaveReqVO createReqVO) { + // 1.1 校验订单项的有效性 + List receiptItems = validateFinanceReceiptItems( + createReqVO.getCustomerId(), createReqVO.getItems()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); + // 1.3 校验结算账户 + if (createReqVO.getAccountId() != null) { + accountService.validateAccount(createReqVO.getAccountId()); + } + // 1.4 校验财务人员 + if (createReqVO.getFinanceUserId() != null) { + adminUserApi.validateUser(createReqVO.getFinanceUserId()); + } + // 1.5 生成收款单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.FINANCE_RECEIPT_NO_PREFIX); + if (financeReceiptMapper.selectByNo(no) != null) { + throw exception(FINANCE_RECEIPT_NO_EXISTS); + } + + // 2.1 插入收款单 + ErpFinanceReceiptDO receipt = BeanUtils.toBean(createReqVO, ErpFinanceReceiptDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())); + calculateTotalPrice(receipt, receiptItems); + financeReceiptMapper.insert(receipt); + // 2.2 插入收款单项 + receiptItems.forEach(o -> o.setReceiptId(receipt.getId())); + financeReceiptItemMapper.insertBatch(receiptItems); + + // 3. 更新销售出库、退货的收款金额情况 + updateSalePrice(receiptItems); + return receipt.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFinanceReceipt(ErpFinanceReceiptSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpFinanceReceiptDO receipt = validateFinanceReceiptExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(receipt.getStatus())) { + throw exception(FINANCE_RECEIPT_UPDATE_FAIL_APPROVE, receipt.getNo()); + } + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); + // 1.3 校验结算账户 + if (updateReqVO.getAccountId() != null) { + accountService.validateAccount(updateReqVO.getAccountId()); + } + // 1.4 校验财务人员 + if (updateReqVO.getFinanceUserId() != null) { + adminUserApi.validateUser(updateReqVO.getFinanceUserId()); + } + // 1.5 校验收款单项的有效性 + List receiptItems = validateFinanceReceiptItems( + updateReqVO.getCustomerId(), updateReqVO.getItems()); + + // 2.1 更新收款单 + ErpFinanceReceiptDO updateObj = BeanUtils.toBean(updateReqVO, ErpFinanceReceiptDO.class); + calculateTotalPrice(updateObj, receiptItems); + financeReceiptMapper.updateById(updateObj); + // 2.2 更新收款单项 + updateFinanceReceiptItemList(updateReqVO.getId(), receiptItems); + } + + private void calculateTotalPrice(ErpFinanceReceiptDO receipt, List receiptItems) { + receipt.setTotalPrice(getSumValue(receiptItems, ErpFinanceReceiptItemDO::getReceiptPrice, BigDecimal::add, BigDecimal.ZERO)); + receipt.setReceiptPrice(receipt.getTotalPrice().subtract(receipt.getDiscountPrice())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFinanceReceiptStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpFinanceReceiptDO receipt = validateFinanceReceiptExists(id); + // 1.2 校验状态 + if (receipt.getStatus().equals(status)) { + throw exception(approve ? FINANCE_RECEIPT_APPROVE_FAIL : FINANCE_RECEIPT_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = financeReceiptMapper.updateByIdAndStatus(id, receipt.getStatus(), + new ErpFinanceReceiptDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? FINANCE_RECEIPT_APPROVE_FAIL : FINANCE_RECEIPT_PROCESS_FAIL); + } + } + + private List validateFinanceReceiptItems( + Long customerId, + List list) { + return convertList(list, o -> BeanUtils.toBean(o, ErpFinanceReceiptItemDO.class, item -> { + if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_OUT.getType())) { + ErpSaleOutDO saleOut = saleOutService.validateSaleOut(item.getBizId()); + Assert.equals(saleOut.getCustomerId(), customerId, "客户必须相同"); + item.setTotalPrice(saleOut.getTotalPrice()).setBizNo(saleOut.getNo()); + } else if (ObjectUtil.equal(item.getBizType(), ErpBizTypeEnum.SALE_RETURN.getType())) { + ErpSaleReturnDO saleReturn = saleReturnService.validateSaleReturn(item.getBizId()); + Assert.equals(saleReturn.getCustomerId(), customerId, "客户必须相同"); + item.setTotalPrice(saleReturn.getTotalPrice().negate()).setBizNo(saleReturn.getNo()); + } else { + throw new IllegalArgumentException("业务类型不正确:" + item.getBizType()); + } + })); + } + + private void updateFinanceReceiptItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = financeReceiptItemMapper.selectListByReceiptId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setReceiptId(id)); + financeReceiptItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + financeReceiptItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + financeReceiptItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpFinanceReceiptItemDO::getId)); + } + + // 第三步,更新销售出库、退货的收款金额情况 + updateSalePrice(CollectionUtils.newArrayList(diffList)); + } + + private void updateSalePrice(List receiptItems) { + receiptItems.forEach(receiptItem -> { + BigDecimal totalReceiptPrice = financeReceiptItemMapper.selectReceiptPriceSumByBizIdAndBizType( + receiptItem.getBizId(), receiptItem.getBizType()); + if (ErpBizTypeEnum.SALE_OUT.getType().equals(receiptItem.getBizType())) { + saleOutService.updateSaleInReceiptPrice(receiptItem.getBizId(), totalReceiptPrice); + } else if (ErpBizTypeEnum.SALE_RETURN.getType().equals(receiptItem.getBizType())) { + saleReturnService.updateSaleReturnRefundPrice(receiptItem.getBizId(), totalReceiptPrice.negate()); + } else { + throw new IllegalArgumentException("业务类型不正确:" + receiptItem.getBizType()); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteFinanceReceipt(List ids) { + // 1. 校验不处于已审批 + List receipts = financeReceiptMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(receipts)) { + return; + } + receipts.forEach(receipt -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(receipt.getStatus())) { + throw exception(FINANCE_RECEIPT_DELETE_FAIL_APPROVE, receipt.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + receipts.forEach(receipt -> { + // 2.1 删除收款单 + financeReceiptMapper.deleteById(receipt.getId()); + // 2.2 删除收款单项 + List receiptItems = financeReceiptItemMapper.selectListByReceiptId(receipt.getId()); + financeReceiptItemMapper.deleteBatchIds(convertSet(receiptItems, ErpFinanceReceiptItemDO::getId)); + + // 2.3 更新销售出库、退货的收款金额情况 + updateSalePrice(receiptItems); + }); + } + + private ErpFinanceReceiptDO validateFinanceReceiptExists(Long id) { + ErpFinanceReceiptDO receipt = financeReceiptMapper.selectById(id); + if (receipt == null) { + throw exception(FINANCE_RECEIPT_NOT_EXISTS); + } + return receipt; + } + + @Override + public ErpFinanceReceiptDO getFinanceReceipt(Long id) { + return financeReceiptMapper.selectById(id); + } + + @Override + public PageResult getFinanceReceiptPage(ErpFinanceReceiptPageReqVO pageReqVO) { + return financeReceiptMapper.selectPage(pageReqVO); + } + + // ==================== 收款单项 ==================== + + @Override + public List getFinanceReceiptItemListByReceiptId(Long receiptId) { + return financeReceiptItemMapper.selectListByReceiptId(receiptId); + } + + @Override + public List getFinanceReceiptItemListByReceiptIds(Collection receiptIds) { + if (CollUtil.isEmpty(receiptIds)) { + return Collections.emptyList(); + } + return financeReceiptItemMapper.selectListByReceiptIds(receiptIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java new file mode 100644 index 0000000..609bc41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategorySaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 产品分类 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpProductCategoryService { + + /** + * 创建产品分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductCategory(@Valid ErpProductCategorySaveReqVO createReqVO); + + /** + * 更新产品分类 + * + * @param updateReqVO 更新信息 + */ + void updateProductCategory(@Valid ErpProductCategorySaveReqVO updateReqVO); + + /** + * 删除产品分类 + * + * @param id 编号 + */ + void deleteProductCategory(Long id); + + /** + * 获得产品分类 + * + * @param id 编号 + * @return 产品分类 + */ + ErpProductCategoryDO getProductCategory(Long id); + + /** + * 获得产品分类列表 + * + * @param listReqVO 查询条件 + * @return 产品分类列表 + */ + List getProductCategoryList(ErpProductCategoryListReqVO listReqVO); + + /** + * 获得产品分类列表 + * + * @param ids 编号数组 + * @return 产品分类列表 + */ + List getProductCategoryList(Collection ids); + + /** + * 获得产品分类 Map + * + * @param ids 编号数组 + * @return 产品分类 Map + */ + default Map getProductCategoryMap(Collection ids) { + return convertMap(getProductCategoryList(ids), ErpProductCategoryDO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java new file mode 100644 index 0000000..70062c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategorySaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +/** + * ERP 产品分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpProductCategoryServiceImpl implements ErpProductCategoryService { + + @Resource + private ErpProductCategoryMapper erpProductCategoryMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpProductService productService; + + @Override + public Long createProductCategory(ErpProductCategorySaveReqVO createReqVO) { + // 校验父分类编号的有效性 + validateParentProductCategory(null, createReqVO.getParentId()); + // 校验分类名称的唯一性 + validateProductCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + ErpProductCategoryDO category = BeanUtils.toBean(createReqVO, ErpProductCategoryDO.class); + erpProductCategoryMapper.insert(category); + // 返回 + return category.getId(); + } + + @Override + public void updateProductCategory(ErpProductCategorySaveReqVO updateReqVO) { + // 校验存在 + validateProductCategoryExists(updateReqVO.getId()); + // 校验父分类编号的有效性 + validateParentProductCategory(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验分类名称的唯一性 + validateProductCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + ErpProductCategoryDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductCategoryDO.class); + erpProductCategoryMapper.updateById(updateObj); + } + + @Override + public void deleteProductCategory(Long id) { + // 1.1 校验存在 + validateProductCategoryExists(id); + // 1.2 校验是否有子产品分类 + if (erpProductCategoryMapper.selectCountByParentId(id) > 0) { + throw exception(PRODUCT_CATEGORY_EXITS_CHILDREN); + } + // 1.3 校验是否有产品 + if (productService.getProductCountByCategoryId(id) > 0) { + throw exception(PRODUCT_CATEGORY_EXITS_PRODUCT); + } + // 2. 删除 + erpProductCategoryMapper.deleteById(id); + } + + private void validateProductCategoryExists(Long id) { + if (erpProductCategoryMapper.selectById(id) == null) { + throw exception(PRODUCT_CATEGORY_NOT_EXISTS); + } + } + + private void validateParentProductCategory(Long id, Long parentId) { + if (parentId == null || ErpProductCategoryDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父产品分类 + if (Objects.equals(id, parentId)) { + throw exception(PRODUCT_CATEGORY_PARENT_ERROR); + } + // 2. 父产品分类不存在 + ErpProductCategoryDO parentCategory = erpProductCategoryMapper.selectById(parentId); + if (parentCategory == null) { + throw exception(PRODUCT_CATEGORY_PARENT_NOT_EXITS); + } + // 3. 递归校验父产品分类,如果父产品分类是自己的子产品分类,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentCategory.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(PRODUCT_CATEGORY_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父产品分类 + if (parentId == null || ErpProductCategoryDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentCategory = erpProductCategoryMapper.selectById(parentId); + if (parentCategory == null) { + break; + } + } + } + + private void validateProductCategoryNameUnique(Long id, Long parentId, String name) { + ErpProductCategoryDO productCategory = erpProductCategoryMapper.selectByParentIdAndName(parentId, name); + if (productCategory == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的产品分类 + if (id == null) { + throw exception(PRODUCT_CATEGORY_NAME_DUPLICATE); + } + if (!Objects.equals(productCategory.getId(), id)) { + throw exception(PRODUCT_CATEGORY_NAME_DUPLICATE); + } + } + + @Override + public ErpProductCategoryDO getProductCategory(Long id) { + return erpProductCategoryMapper.selectById(id); + } + + @Override + public List getProductCategoryList(ErpProductCategoryListReqVO listReqVO) { + return erpProductCategoryMapper.selectList(listReqVO); + } + + @Override + public List getProductCategoryList(Collection ids) { + return erpProductCategoryMapper.selectBatchIds(ids); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java new file mode 100644 index 0000000..a947e3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 产品 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpProductService { + + /** + * 创建产品 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProduct(@Valid ProductSaveReqVO createReqVO); + + /** + * 更新产品 + * + * @param updateReqVO 更新信息 + */ + void updateProduct(@Valid ProductSaveReqVO updateReqVO); + + /** + * 删除产品 + * + * @param id 编号 + */ + void deleteProduct(Long id); + + /** + * 校验产品们的有效性 + * + * @param ids 编号数组 + * @return 产品列表 + */ + List validProductList(Collection ids); + + /** + * 获得产品 + * + * @param id 编号 + * @return 产品 + */ + ErpProductDO getProduct(Long id); + + /** + * 获得指定状态的产品 VO 列表 + * + * @param status 状态 + * @return 产品 VO 列表 + */ + List getProductVOListByStatus(Integer status); + + /** + * 获得产品 VO 列表 + * + * @param ids 编号数组 + * @return 产品 VO 列表 + */ + List getProductVOList(Collection ids); + + /** + * 获得产品 VO Map + * + * @param ids 编号数组 + * @return 产品 VO Map + */ + default Map getProductVOMap(Collection ids) { + return convertMap(getProductVOList(ids), ErpProductRespVO::getId); + } + + /** + * 获得产品 VO 分页 + * + * @param pageReqVO 分页查询 + * @return 产品分页 + */ + PageResult getProductVOPage(ErpProductPageReqVO pageReqVO); + + /** + * 基于产品分类编号,获得产品数量 + * + * @param categoryId 产品分类编号 + * @return 产品数量 + */ + Long getProductCountByCategoryId(Long categoryId); + + /** + * 基于产品单位编号,获得产品数量 + * + * @param unitId 产品单位编号 + * @return 产品数量 + */ + Long getProductCountByUnitId(Long unitId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java new file mode 100644 index 0000000..c264b8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -0,0 +1,152 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; + +/** + * ERP 产品 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpProductServiceImpl implements ErpProductService { + + @Resource + private ErpProductMapper productMapper; + + @Resource + private ErpProductCategoryService productCategoryService; + @Resource + private ErpProductUnitService productUnitService; + + @Override + public Long createProduct(ProductSaveReqVO createReqVO) { + // TODO 芋艿:校验分类 + // 插入 + ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class); + productMapper.insert(product); + // 返回 + return product.getId(); + } + + @Override + public void updateProduct(ProductSaveReqVO updateReqVO) { + // TODO 芋艿:校验分类 + // 校验存在 + validateProductExists(updateReqVO.getId()); + // 更新 + ErpProductDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductDO.class); + productMapper.updateById(updateObj); + } + + @Override + public void deleteProduct(Long id) { + // 校验存在 + validateProductExists(id); + // 删除 + productMapper.deleteById(id); + } + + @Override + public List validProductList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = productMapper.selectBatchIds(ids); + Map productMap = convertMap(list, ErpProductDO::getId); + for (Long id : ids) { + ErpProductDO product = productMap.get(id); + if (productMap.get(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(product.getStatus())) { + throw exception(PRODUCT_NOT_ENABLE, product.getName()); + } + } + return list; + } + + private void validateProductExists(Long id) { + if (productMapper.selectById(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + } + + @Override + public ErpProductDO getProduct(Long id) { + return productMapper.selectById(id); + } + + @Override + public List getProductVOListByStatus(Integer status) { + List list = productMapper.selectListByStatus(status); + return buildProductVOList(list); + } + + @Override + public List getProductVOList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = productMapper.selectBatchIds(ids); + return buildProductVOList(list); + } + + @Override + public PageResult getProductVOPage(ErpProductPageReqVO pageReqVO) { + PageResult pageResult = productMapper.selectPage(pageReqVO); + return new PageResult<>(buildProductVOList(pageResult.getList()), pageResult.getTotal()); + } + + private List buildProductVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + Map categoryMap = productCategoryService.getProductCategoryMap( + convertSet(list, ErpProductDO::getCategoryId)); + Map unitMap = productUnitService.getProductUnitMap( + convertSet(list, ErpProductDO::getUnitId)); + return BeanUtils.toBean(list, ErpProductRespVO.class, product -> { + MapUtils.findAndThen(categoryMap, product.getCategoryId(), + category -> product.setCategoryName(category.getName())); + MapUtils.findAndThen(unitMap, product.getUnitId(), + unit -> product.setUnitName(unit.getName())); + }); + } + + @Override + public Long getProductCountByCategoryId(Long categoryId) { + return productMapper.selectCountByCategoryId(categoryId); + } + + @Override + public Long getProductCountByUnitId(Long unitId) { + return productMapper.selectCountByUnitId(unitId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java new file mode 100644 index 0000000..93776ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 产品单位 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpProductUnitService { + + /** + * 创建产品单位 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductUnit(@Valid ErpProductUnitSaveReqVO createReqVO); + + /** + * 更新产品单位 + * + * @param updateReqVO 更新信息 + */ + void updateProductUnit(@Valid ErpProductUnitSaveReqVO updateReqVO); + + /** + * 删除产品单位 + * + * @param id 编号 + */ + void deleteProductUnit(Long id); + + /** + * 获得产品单位 + * + * @param id 编号 + * @return 产品单位 + */ + ErpProductUnitDO getProductUnit(Long id); + + /** + * 获得产品单位分页 + * + * @param pageReqVO 分页查询 + * @return 产品单位分页 + */ + PageResult getProductUnitPage(ErpProductUnitPageReqVO pageReqVO); + + /** + * 获得指定状态的产品单位列表 + * + * @param status 状态 + * @return 产品单位列表 + */ + List getProductUnitListByStatus(Integer status); + + /** + * 获得产品单位列表 + * + * @param ids 编号数组 + * @return 产品单位列表 + */ + List getProductUnitList(Collection ids); + + /** + * 获得产品单位 Map + * + * @param ids 编号数组 + * @return 产品单位 Map + */ + default Map getProductUnitMap(Collection ids) { + return convertMap(getProductUnitList(ids), ErpProductUnitDO::getId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java new file mode 100644 index 0000000..d2592a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.erp.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; +import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +/** + * ERP 产品单位 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpProductUnitServiceImpl implements ErpProductUnitService { + + @Resource + private ErpProductUnitMapper productUnitMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpProductService productService; + + @Override + public Long createProductUnit(ErpProductUnitSaveReqVO createReqVO) { + // 1. 校验名字唯一 + validateProductUnitNameUnique(null, createReqVO.getName()); + // 2. 插入 + ErpProductUnitDO unit = BeanUtils.toBean(createReqVO, ErpProductUnitDO.class); + productUnitMapper.insert(unit); + return unit.getId(); + } + + @Override + public void updateProductUnit(ErpProductUnitSaveReqVO updateReqVO) { + // 1.1 校验存在 + validateProductUnitExists(updateReqVO.getId()); + // 1.2 校验名字唯一 + validateProductUnitNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 2. 更新 + ErpProductUnitDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductUnitDO.class); + productUnitMapper.updateById(updateObj); + } + + @VisibleForTesting + void validateProductUnitNameUnique(Long id, String name) { + ErpProductUnitDO unit = productUnitMapper.selectByName(name); + if (unit == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(PRODUCT_UNIT_NAME_DUPLICATE); + } + if (!unit.getId().equals(id)) { + throw exception(PRODUCT_UNIT_NAME_DUPLICATE); + } + } + + @Override + public void deleteProductUnit(Long id) { + // 1.1 校验存在 + validateProductUnitExists(id); + // 1.2 校验产品是否使用 + if (productService.getProductCountByUnitId(id) > 0) { + throw exception(PRODUCT_UNIT_EXITS_PRODUCT); + } + // 2. 删除 + productUnitMapper.deleteById(id); + } + + private void validateProductUnitExists(Long id) { + if (productUnitMapper.selectById(id) == null) { + throw exception(PRODUCT_UNIT_NOT_EXISTS); + } + } + + @Override + public ErpProductUnitDO getProductUnit(Long id) { + return productUnitMapper.selectById(id); + } + + @Override + public PageResult getProductUnitPage(ErpProductUnitPageReqVO pageReqVO) { + return productUnitMapper.selectPage(pageReqVO); + } + + @Override + public List getProductUnitListByStatus(Integer status) { + return productUnitMapper.selectListByStatus(status); + } + + @Override + public List getProductUnitList(Collection ids) { + return productUnitMapper.selectBatchIds(ids); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java new file mode 100644 index 0000000..6c994e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * ERP 采购入库 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpPurchaseInService { + + /** + * 创建采购入库 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPurchaseIn(@Valid ErpPurchaseInSaveReqVO createReqVO); + + /** + * 更新采购入库 + * + * @param updateReqVO 更新信息 + */ + void updatePurchaseIn(@Valid ErpPurchaseInSaveReqVO updateReqVO); + + /** + * 更新采购入库的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updatePurchaseInStatus(Long id, Integer status); + + /** + * 更新采购入库的付款金额 + * + * @param id 编号 + * @param paymentPrice 付款金额 + */ + void updatePurchaseInPaymentPrice(Long id, BigDecimal paymentPrice); + + /** + * 删除采购入库 + * + * @param ids 编号数组 + */ + void deletePurchaseIn(List ids); + + /** + * 获得采购入库 + * + * @param id 编号 + * @return 采购入库 + */ + ErpPurchaseInDO getPurchaseIn(Long id); + + /** + * 校验采购入库,已经审核通过 + * + * @param id 编号 + * @return 采购入库 + */ + ErpPurchaseInDO validatePurchaseIn(Long id); + + /** + * 获得采购入库分页 + * + * @param pageReqVO 分页查询 + * @return 采购入库分页 + */ + PageResult getPurchaseInPage(ErpPurchaseInPageReqVO pageReqVO); + + // ==================== 采购入库项 ==================== + + /** + * 获得采购入库项列表 + * + * @param inId 采购入库编号 + * @return 采购入库项列表 + */ + List getPurchaseInItemListByInId(Long inId); + + /** + * 获得采购入库项 List + * + * @param inIds 采购入库编号数组 + * @return 采购入库项 List + */ + List getPurchaseInItemListByInIds(Collection inIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java new file mode 100644 index 0000000..a0017ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java @@ -0,0 +1,308 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 采购入库 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpPurchaseInServiceImpl implements ErpPurchaseInService { + + @Resource + private ErpPurchaseInMapper purchaseInMapper; + @Resource + private ErpPurchaseInItemMapper purchaseInItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpPurchaseOrderService purchaseOrderService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpStockRecordService stockRecordService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createPurchaseIn(ErpPurchaseInSaveReqVO createReqVO) { + // 1.1 校验采购订单已审核 + ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(createReqVO.getOrderId()); + // 1.2 校验入库项的有效性 + List purchaseInItems = validatePurchaseInItems(createReqVO.getItems()); + // 1.3 校验结算账户 + accountService.validateAccount(createReqVO.getAccountId()); + // 1.4 生成入库单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_IN_NO_PREFIX); + if (purchaseInMapper.selectByNo(no) != null) { + throw exception(PURCHASE_IN_NO_EXISTS); + } + + // 2.1 插入入库 + ErpPurchaseInDO purchaseIn = BeanUtils.toBean(createReqVO, ErpPurchaseInDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) + .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); + calculateTotalPrice(purchaseIn, purchaseInItems); + purchaseInMapper.insert(purchaseIn); + // 2.2 插入入库项 + purchaseInItems.forEach(o -> o.setInId(purchaseIn.getId())); + purchaseInItemMapper.insertBatch(purchaseInItems); + + // 3. 更新采购订单的入库数量 + updatePurchaseOrderInCount(createReqVO.getOrderId()); + return purchaseIn.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseIn(ErpPurchaseInSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpPurchaseInDO purchaseIn = validatePurchaseInExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseIn.getStatus())) { + throw exception(PURCHASE_IN_UPDATE_FAIL_APPROVE, purchaseIn.getNo()); + } + // 1.2 校验采购订单已审核 + ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(updateReqVO.getOrderId()); + // 1.3 校验结算账户 + accountService.validateAccount(updateReqVO.getAccountId()); + // 1.4 校验订单项的有效性 + List purchaseInItems = validatePurchaseInItems(updateReqVO.getItems()); + + // 2.1 更新入库 + ErpPurchaseInDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseInDO.class) + .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); + calculateTotalPrice(updateObj, purchaseInItems); + purchaseInMapper.updateById(updateObj); + // 2.2 更新入库项 + updatePurchaseInItemList(updateReqVO.getId(), purchaseInItems); + + // 3.1 更新采购订单的入库数量 + updatePurchaseOrderInCount(updateObj.getOrderId()); + // 3.2 注意:如果采购订单编号变更了,需要更新“老”采购订单的入库数量 + if (ObjectUtil.notEqual(purchaseIn.getOrderId(), updateObj.getOrderId())) { + updatePurchaseOrderInCount(purchaseIn.getOrderId()); + } + } + + private void calculateTotalPrice(ErpPurchaseInDO purchaseIn, List purchaseInItems) { + purchaseIn.setTotalCount(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getCount, BigDecimal::add)); + purchaseIn.setTotalProductPrice(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseIn.setTotalTaxPrice(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseIn.setTotalPrice(purchaseIn.getTotalProductPrice().add(purchaseIn.getTotalTaxPrice())); + // 计算优惠价格 + if (purchaseIn.getDiscountPercent() == null) { + purchaseIn.setDiscountPercent(BigDecimal.ZERO); + } + purchaseIn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseIn.getTotalPrice(), purchaseIn.getDiscountPercent())); + purchaseIn.setTotalPrice(purchaseIn.getTotalPrice().subtract(purchaseIn.getDiscountPrice()).add(purchaseIn.getOtherPrice())); + } + + private void updatePurchaseOrderInCount(Long orderId) { + // 1.1 查询采购订单对应的采购入库单列表 + List purchaseIns = purchaseInMapper.selectListByOrderId(orderId); + // 1.2 查询对应的采购订单项的入库数量 + Map returnCountMap = purchaseInItemMapper.selectOrderItemCountSumMapByInIds( + convertList(purchaseIns, ErpPurchaseInDO::getId)); + // 2. 更新采购订单的入库数量 + purchaseOrderService.updatePurchaseOrderInCount(orderId, returnCountMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseInStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id); + // 1.2 校验状态 + if (purchaseIn.getStatus().equals(status)) { + throw exception(approve ? PURCHASE_IN_APPROVE_FAIL : PURCHASE_IN_PROCESS_FAIL); + } + // 1.3 校验已付款 + if (!approve && purchaseIn.getPaymentPrice().compareTo(BigDecimal.ZERO) > 0) { + throw exception(PURCHASE_IN_PROCESS_FAIL_EXISTS_PAYMENT); + } + + // 2. 更新状态 + int updateCount = purchaseInMapper.updateByIdAndStatus(id, purchaseIn.getStatus(), + new ErpPurchaseInDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? PURCHASE_IN_APPROVE_FAIL : PURCHASE_IN_PROCESS_FAIL); + } + + // 3. 变更库存 + List purchaseInItems = purchaseInItemMapper.selectListByInId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.PURCHASE_IN.getType() + : ErpStockRecordBizTypeEnum.PURCHASE_IN_CANCEL.getType(); + purchaseInItems.forEach(purchaseInItem -> { + BigDecimal count = approve ? purchaseInItem.getCount() : purchaseInItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + purchaseInItem.getProductId(), purchaseInItem.getWarehouseId(), count, + bizType, purchaseInItem.getInId(), purchaseInItem.getId(), purchaseIn.getNo())); + }); + } + + @Override + public void updatePurchaseInPaymentPrice(Long id, BigDecimal paymentPrice) { + ErpPurchaseInDO purchaseIn = purchaseInMapper.selectById(id); + if (purchaseIn.getPaymentPrice().equals(paymentPrice)) { + return; + } + if (paymentPrice.compareTo(purchaseIn.getTotalPrice()) > 0) { + throw exception(PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED, paymentPrice, purchaseIn.getTotalPrice()); + } + purchaseInMapper.updateById(new ErpPurchaseInDO().setId(id).setPaymentPrice(paymentPrice)); + } + + private List validatePurchaseInItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpPurchaseInSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpPurchaseInItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseInItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updatePurchaseInItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = purchaseInItemMapper.selectListByInId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setInId(id)); + purchaseInItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + purchaseInItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + purchaseInItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpPurchaseInItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deletePurchaseIn(List ids) { + // 1. 校验不处于已审批 + List purchaseIns = purchaseInMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(purchaseIns)) { + return; + } + purchaseIns.forEach(purchaseIn -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseIn.getStatus())) { + throw exception(PURCHASE_IN_DELETE_FAIL_APPROVE, purchaseIn.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + purchaseIns.forEach(purchaseIn -> { + // 2.1 删除订单 + purchaseInMapper.deleteById(purchaseIn.getId()); + // 2.2 删除订单项 + purchaseInItemMapper.deleteByInId(purchaseIn.getId()); + + // 2.3 更新采购订单的入库数量 + updatePurchaseOrderInCount(purchaseIn.getOrderId()); + }); + + } + + private ErpPurchaseInDO validatePurchaseInExists(Long id) { + ErpPurchaseInDO purchaseIn = purchaseInMapper.selectById(id); + if (purchaseIn == null) { + throw exception(PURCHASE_IN_NOT_EXISTS); + } + return purchaseIn; + } + + @Override + public ErpPurchaseInDO getPurchaseIn(Long id) { + return purchaseInMapper.selectById(id); + } + + @Override + public ErpPurchaseInDO validatePurchaseIn(Long id) { + ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id); + if (ObjectUtil.notEqual(purchaseIn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(PURCHASE_IN_NOT_APPROVE); + } + return purchaseIn; + } + + @Override + public PageResult getPurchaseInPage(ErpPurchaseInPageReqVO pageReqVO) { + return purchaseInMapper.selectPage(pageReqVO); + } + + // ==================== 采购入库项 ==================== + + @Override + public List getPurchaseInItemListByInId(Long inId) { + return purchaseInItemMapper.selectListByInId(inId); + } + + @Override + public List getPurchaseInItemListByInIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyList(); + } + return purchaseInItemMapper.selectListByInIds(inIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java new file mode 100644 index 0000000..29d5f6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * ERP 采购订单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpPurchaseOrderService { + + /** + * 创建采购订单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPurchaseOrder(@Valid ErpPurchaseOrderSaveReqVO createReqVO); + + /** + * 更新采购订单 + * + * @param updateReqVO 更新信息 + */ + void updatePurchaseOrder(@Valid ErpPurchaseOrderSaveReqVO updateReqVO); + + /** + * 更新采购订单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updatePurchaseOrderStatus(Long id, Integer status); + + /** + * 更新采购订单的入库数量 + * + * @param id 编号 + * @param inCountMap 入库数量 Map:key 采购订单项编号;value 入库数量 + */ + void updatePurchaseOrderInCount(Long id, Map inCountMap); + + /** + * 更新采购订单的退货数量 + * + * @param orderId 编号 + * @param returnCountMap 退货数量 Map:key 采购订单项编号;value 退货数量 + */ + void updatePurchaseOrderReturnCount(Long orderId, Map returnCountMap); + + /** + * 删除采购订单 + * + * @param ids 编号数组 + */ + void deletePurchaseOrder(List ids); + + /** + * 获得采购订单 + * + * @param id 编号 + * @return 采购订单 + */ + ErpPurchaseOrderDO getPurchaseOrder(Long id); + + /** + * 校验采购订单,已经审核通过 + * + * @param id 编号 + * @return 采购订单 + */ + ErpPurchaseOrderDO validatePurchaseOrder(Long id); + + /** + * 获得采购订单分页 + * + * @param pageReqVO 分页查询 + * @return 采购订单分页 + */ + PageResult getPurchaseOrderPage(ErpPurchaseOrderPageReqVO pageReqVO); + + // ==================== 采购订单项 ==================== + + /** + * 获得采购订单项列表 + * + * @param orderId 采购订单编号 + * @return 采购订单项列表 + */ + List getPurchaseOrderItemListByOrderId(Long orderId); + + /** + * 获得采购订单项 List + * + * @param orderIds 采购订单编号数组 + * @return 采购订单项 List + */ + List getPurchaseOrderItemListByOrderIds(Collection orderIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java new file mode 100644 index 0000000..c585490 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java @@ -0,0 +1,295 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 采购订单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService { + + @Resource + private ErpPurchaseOrderMapper purchaseOrderMapper; + @Resource + private ErpPurchaseOrderItemMapper purchaseOrderItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpSupplierService supplierService; + @Resource + private ErpAccountService accountService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createPurchaseOrder(ErpPurchaseOrderSaveReqVO createReqVO) { + // 1.1 校验订单项的有效性 + List purchaseOrderItems = validatePurchaseOrderItems(createReqVO.getItems()); + // 1.2 校验供应商 + supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.3 校验结算账户 + if (createReqVO.getAccountId() != null) { + accountService.validateAccount(createReqVO.getAccountId()); + } + // 1.4 生成订单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_ORDER_NO_PREFIX); + if (purchaseOrderMapper.selectByNo(no) != null) { + throw exception(PURCHASE_ORDER_NO_EXISTS); + } + + // 2.1 插入订单 + ErpPurchaseOrderDO purchaseOrder = BeanUtils.toBean(createReqVO, ErpPurchaseOrderDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())); + calculateTotalPrice(purchaseOrder, purchaseOrderItems); + purchaseOrderMapper.insert(purchaseOrder); + // 2.2 插入订单项 + purchaseOrderItems.forEach(o -> o.setOrderId(purchaseOrder.getId())); + purchaseOrderItemMapper.insertBatch(purchaseOrderItems); + return purchaseOrder.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseOrder(ErpPurchaseOrderSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseOrder.getStatus())) { + throw exception(PURCHASE_ORDER_UPDATE_FAIL_APPROVE, purchaseOrder.getNo()); + } + // 1.2 校验供应商 + supplierService.validateSupplier(updateReqVO.getSupplierId()); + // 1.3 校验结算账户 + if (updateReqVO.getAccountId() != null) { + accountService.validateAccount(updateReqVO.getAccountId()); + } + // 1.4 校验订单项的有效性 + List purchaseOrderItems = validatePurchaseOrderItems(updateReqVO.getItems()); + + // 2.1 更新订单 + ErpPurchaseOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseOrderDO.class); + calculateTotalPrice(updateObj, purchaseOrderItems); + purchaseOrderMapper.updateById(updateObj); + // 2.2 更新订单项 + updatePurchaseOrderItemList(updateReqVO.getId(), purchaseOrderItems); + } + + private void calculateTotalPrice(ErpPurchaseOrderDO purchaseOrder, List purchaseOrderItems) { + purchaseOrder.setTotalCount(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getCount, BigDecimal::add)); + purchaseOrder.setTotalProductPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseOrder.setTotalTaxPrice(getSumValue(purchaseOrderItems, ErpPurchaseOrderItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseOrder.setTotalPrice(purchaseOrder.getTotalProductPrice().add(purchaseOrder.getTotalTaxPrice())); + // 计算优惠价格 + if (purchaseOrder.getDiscountPercent() == null) { + purchaseOrder.setDiscountPercent(BigDecimal.ZERO); + } + purchaseOrder.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseOrder.getTotalPrice(), purchaseOrder.getDiscountPercent())); + purchaseOrder.setTotalPrice(purchaseOrder.getTotalPrice().subtract(purchaseOrder.getDiscountPrice())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseOrderStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id); + // 1.2 校验状态 + if (purchaseOrder.getStatus().equals(status)) { + throw exception(approve ? PURCHASE_ORDER_APPROVE_FAIL : PURCHASE_ORDER_PROCESS_FAIL); + } + // 1.3 存在采购入单,无法反审核 + if (!approve && purchaseOrder.getInCount().compareTo(BigDecimal.ZERO) > 0) { + throw exception(PURCHASE_ORDER_PROCESS_FAIL_EXISTS_IN); + } + // 1.4 存在采购退货单,无法反审核 + if (!approve && purchaseOrder.getReturnCount().compareTo(BigDecimal.ZERO) > 0) { + throw exception(PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN); + } + + // 2. 更新状态 + int updateCount = purchaseOrderMapper.updateByIdAndStatus(id, purchaseOrder.getStatus(), + new ErpPurchaseOrderDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? PURCHASE_ORDER_APPROVE_FAIL : PURCHASE_ORDER_PROCESS_FAIL); + } + } + + private List validatePurchaseOrderItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpPurchaseOrderSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpPurchaseOrderItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseOrderItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updatePurchaseOrderItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = purchaseOrderItemMapper.selectListByOrderId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setOrderId(id)); + purchaseOrderItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + purchaseOrderItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + purchaseOrderItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpPurchaseOrderItemDO::getId)); + } + } + + @Override + public void updatePurchaseOrderInCount(Long id, Map inCountMap) { + List orderItems = purchaseOrderItemMapper.selectListByOrderId(id); + // 1. 更新每个采购订单项 + orderItems.forEach(item -> { + BigDecimal inCount = inCountMap.getOrDefault(item.getId(), BigDecimal.ZERO); + if (item.getInCount().equals(inCount)) { + return; + } + if (inCount.compareTo(item.getCount()) > 0) { + throw exception(PURCHASE_ORDER_ITEM_IN_FAIL_PRODUCT_EXCEED, + productService.getProduct(item.getProductId()).getName(), item.getCount()); + } + purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setInCount(inCount)); + }); + // 2. 更新采购订单 + BigDecimal totalInCount = getSumValue(inCountMap.values(), value -> value, BigDecimal::add, BigDecimal.ZERO); + purchaseOrderMapper.updateById(new ErpPurchaseOrderDO().setId(id).setInCount(totalInCount)); + } + + @Override + public void updatePurchaseOrderReturnCount(Long orderId, Map returnCountMap) { + List orderItems = purchaseOrderItemMapper.selectListByOrderId(orderId); + // 1. 更新每个采购订单项 + orderItems.forEach(item -> { + BigDecimal returnCount = returnCountMap.getOrDefault(item.getId(), BigDecimal.ZERO); + if (item.getReturnCount().equals(returnCount)) { + return; + } + if (returnCount.compareTo(item.getInCount()) > 0) { + throw exception(PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED, + productService.getProduct(item.getProductId()).getName(), item.getInCount()); + } + purchaseOrderItemMapper.updateById(new ErpPurchaseOrderItemDO().setId(item.getId()).setReturnCount(returnCount)); + }); + // 2. 更新采购订单 + BigDecimal totalReturnCount = getSumValue(returnCountMap.values(), value -> value, BigDecimal::add, BigDecimal.ZERO); + purchaseOrderMapper.updateById(new ErpPurchaseOrderDO().setId(orderId).setReturnCount(totalReturnCount)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deletePurchaseOrder(List ids) { + // 1. 校验不处于已审批 + List purchaseOrders = purchaseOrderMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(purchaseOrders)) { + return; + } + purchaseOrders.forEach(purchaseOrder -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseOrder.getStatus())) { + throw exception(PURCHASE_ORDER_DELETE_FAIL_APPROVE, purchaseOrder.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + purchaseOrders.forEach(purchaseOrder -> { + // 2.1 删除订单 + purchaseOrderMapper.deleteById(purchaseOrder.getId()); + // 2.2 删除订单项 + purchaseOrderItemMapper.deleteByOrderId(purchaseOrder.getId()); + }); + } + + private ErpPurchaseOrderDO validatePurchaseOrderExists(Long id) { + ErpPurchaseOrderDO purchaseOrder = purchaseOrderMapper.selectById(id); + if (purchaseOrder == null) { + throw exception(PURCHASE_ORDER_NOT_EXISTS); + } + return purchaseOrder; + } + + @Override + public ErpPurchaseOrderDO getPurchaseOrder(Long id) { + return purchaseOrderMapper.selectById(id); + } + + @Override + public ErpPurchaseOrderDO validatePurchaseOrder(Long id) { + ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id); + if (ObjectUtil.notEqual(purchaseOrder.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(PURCHASE_ORDER_NOT_APPROVE); + } + return purchaseOrder; + } + + @Override + public PageResult getPurchaseOrderPage(ErpPurchaseOrderPageReqVO pageReqVO) { + return purchaseOrderMapper.selectPage(pageReqVO); + } + + // ==================== 订单项 ==================== + + @Override + public List getPurchaseOrderItemListByOrderId(Long orderId) { + return purchaseOrderItemMapper.selectListByOrderId(orderId); + } + + @Override + public List getPurchaseOrderItemListByOrderIds(Collection orderIds) { + if (CollUtil.isEmpty(orderIds)) { + return Collections.emptyList(); + } + return purchaseOrderItemMapper.selectListByOrderIds(orderIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnService.java new file mode 100644 index 0000000..9c4a4ab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnService.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * ERP 采购退货 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpPurchaseReturnService { + + /** + * 创建采购退货 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPurchaseReturn(@Valid ErpPurchaseReturnSaveReqVO createReqVO); + + /** + * 更新采购退货 + * + * @param updateReqVO 更新信息 + */ + void updatePurchaseReturn(@Valid ErpPurchaseReturnSaveReqVO updateReqVO); + + /** + * 更新采购退货的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updatePurchaseReturnStatus(Long id, Integer status); + + /** + * 更新采购退货的退款金额 + * + * @param id 编号 + * @param refundPrice 退款金额 + */ + void updatePurchaseReturnRefundPrice(Long id, BigDecimal refundPrice); + + /** + * 删除采购退货 + * + * @param ids 编号数组 + */ + void deletePurchaseReturn(List ids); + + /** + * 获得采购退货 + * + * @param id 编号 + * @return 采购退货 + */ + ErpPurchaseReturnDO getPurchaseReturn(Long id); + + /** + * 校验采购退货,已经审核通过 + * + * @param id 编号 + * @return 采购退货 + */ + ErpPurchaseReturnDO validatePurchaseReturn(Long id); + + /** + * 获得采购退货分页 + * + * @param pageReqVO 分页查询 + * @return 采购退货分页 + */ + PageResult getPurchaseReturnPage(ErpPurchaseReturnPageReqVO pageReqVO); + + // ==================== 采购退货项 ==================== + + /** + * 获得采购退货项列表 + * + * @param returnId 采购退货编号 + * @return 采购退货项列表 + */ + List getPurchaseReturnItemListByReturnId(Long returnId); + + /** + * 获得采购退货项 List + * + * @param returnIds 采购退货编号数组 + * @return 采购退货项 List + */ + List getPurchaseReturnItemListByReturnIds(Collection returnIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java new file mode 100644 index 0000000..00527cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java @@ -0,0 +1,304 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseReturnItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseReturnMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 采购退货 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpPurchaseReturnServiceImpl implements ErpPurchaseReturnService { + + @Resource + private ErpPurchaseReturnMapper purchaseReturnMapper; + @Resource + private ErpPurchaseReturnItemMapper purchaseReturnItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpPurchaseOrderService purchaseOrderService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createPurchaseReturn(ErpPurchaseReturnSaveReqVO createReqVO) { + // 1.1 校验采购订单已审核 + ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(createReqVO.getOrderId()); + // 1.2 校验退货项的有效性 + List purchaseReturnItems = validatePurchaseReturnItems(createReqVO.getItems()); + // 1.3 校验结算账户 + accountService.validateAccount(createReqVO.getAccountId()); + // 1.4 生成退货单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_RETURN_NO_PREFIX); + if (purchaseReturnMapper.selectByNo(no) != null) { + throw exception(PURCHASE_RETURN_NO_EXISTS); + } + + // 2.1 插入退货 + ErpPurchaseReturnDO purchaseReturn = BeanUtils.toBean(createReqVO, ErpPurchaseReturnDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) + .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); + calculateTotalPrice(purchaseReturn, purchaseReturnItems); + purchaseReturnMapper.insert(purchaseReturn); + // 2.2 插入退货项 + purchaseReturnItems.forEach(o -> o.setReturnId(purchaseReturn.getId())); + purchaseReturnItemMapper.insertBatch(purchaseReturnItems); + + // 3. 更新采购订单的退货数量 + updatePurchaseOrderReturnCount(createReqVO.getOrderId()); + return purchaseReturn.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseReturn(ErpPurchaseReturnSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpPurchaseReturnDO purchaseReturn = validatePurchaseReturnExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseReturn.getStatus())) { + throw exception(PURCHASE_RETURN_UPDATE_FAIL_APPROVE, purchaseReturn.getNo()); + } + // 1.2 校验采购订单已审核 + ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(updateReqVO.getOrderId()); + // 1.3 校验结算账户 + accountService.validateAccount(updateReqVO.getAccountId()); + // 1.4 校验订单项的有效性 + List purchaseReturnItems = validatePurchaseReturnItems(updateReqVO.getItems()); + + // 2.1 更新退货 + ErpPurchaseReturnDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseReturnDO.class) + .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); + calculateTotalPrice(updateObj, purchaseReturnItems); + purchaseReturnMapper.updateById(updateObj); + // 2.2 更新退货项 + updatePurchaseReturnItemList(updateReqVO.getId(), purchaseReturnItems); + + // 3.1 更新采购订单的出库数量 + updatePurchaseOrderReturnCount(updateObj.getOrderId()); + // 3.2 注意:如果采购订单编号变更了,需要更新“老”采购订单的出库数量 + if (ObjectUtil.notEqual(purchaseReturn.getOrderId(), updateObj.getOrderId())) { + updatePurchaseOrderReturnCount(purchaseReturn.getOrderId()); + } + } + + private void calculateTotalPrice(ErpPurchaseReturnDO purchaseReturn, List purchaseReturnItems) { + purchaseReturn.setTotalCount(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getCount, BigDecimal::add)); + purchaseReturn.setTotalProductPrice(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseReturn.setTotalTaxPrice(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + purchaseReturn.setTotalPrice(purchaseReturn.getTotalProductPrice().add(purchaseReturn.getTotalTaxPrice())); + // 计算优惠价格 + if (purchaseReturn.getDiscountPercent() == null) { + purchaseReturn.setDiscountPercent(BigDecimal.ZERO); + } + purchaseReturn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseReturn.getTotalPrice(), purchaseReturn.getDiscountPercent())); + purchaseReturn.setTotalPrice(purchaseReturn.getTotalPrice().subtract(purchaseReturn.getDiscountPrice()).add(purchaseReturn.getOtherPrice())); + } + + private void updatePurchaseOrderReturnCount(Long orderId) { + // 1.1 查询采购订单对应的采购出库单列表 + List purchaseReturns = purchaseReturnMapper.selectListByOrderId(orderId); + // 1.2 查询对应的采购订单项的退货数量 + Map returnCountMap = purchaseReturnItemMapper.selectOrderItemCountSumMapByReturnIds( + convertList(purchaseReturns, ErpPurchaseReturnDO::getId)); + // 2. 更新采购订单的出库数量 + purchaseOrderService.updatePurchaseOrderReturnCount(orderId, returnCountMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePurchaseReturnStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpPurchaseReturnDO purchaseReturn = validatePurchaseReturnExists(id); + // 1.2 校验状态 + if (purchaseReturn.getStatus().equals(status)) { + throw exception(approve ? PURCHASE_RETURN_APPROVE_FAIL : PURCHASE_RETURN_PROCESS_FAIL); + } + // 1.3 校验已退款 + if (!approve && purchaseReturn.getRefundPrice().compareTo(BigDecimal.ZERO) > 0) { + throw exception(PURCHASE_RETURN_PROCESS_FAIL_EXISTS_REFUND); + } + + // 2. 更新状态 + int updateCount = purchaseReturnMapper.updateByIdAndStatus(id, purchaseReturn.getStatus(), + new ErpPurchaseReturnDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? PURCHASE_RETURN_APPROVE_FAIL : PURCHASE_RETURN_PROCESS_FAIL); + } + + // 3. 变更库存 + List purchaseReturnItems = purchaseReturnItemMapper.selectListByReturnId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.PURCHASE_RETURN.getType() + : ErpStockRecordBizTypeEnum.PURCHASE_RETURN_CANCEL.getType(); + purchaseReturnItems.forEach(purchaseReturnItem -> { + BigDecimal count = approve ? purchaseReturnItem.getCount().negate() : purchaseReturnItem.getCount(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + purchaseReturnItem.getProductId(), purchaseReturnItem.getWarehouseId(), count, + bizType, purchaseReturnItem.getReturnId(), purchaseReturnItem.getId(), purchaseReturn.getNo())); + }); + } + + @Override + public void updatePurchaseReturnRefundPrice(Long id, BigDecimal refundPrice) { + ErpPurchaseReturnDO purchaseReturn = purchaseReturnMapper.selectById(id); + if (purchaseReturn.getRefundPrice().equals(refundPrice)) { + return; + } + if (refundPrice.compareTo(purchaseReturn.getTotalPrice()) > 0) { + throw exception(PURCHASE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, purchaseReturn.getTotalPrice()); + } + purchaseReturnMapper.updateById(new ErpPurchaseReturnDO().setId(id).setRefundPrice(refundPrice)); + } + + private List validatePurchaseReturnItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpPurchaseReturnSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpPurchaseReturnItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseReturnItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updatePurchaseReturnItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = purchaseReturnItemMapper.selectListByReturnId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setReturnId(id)); + purchaseReturnItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + purchaseReturnItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + purchaseReturnItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpPurchaseReturnItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deletePurchaseReturn(List ids) { + // 1. 校验不处于已审批 + List purchaseReturns = purchaseReturnMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(purchaseReturns)) { + return; + } + purchaseReturns.forEach(purchaseReturn -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseReturn.getStatus())) { + throw exception(PURCHASE_RETURN_DELETE_FAIL_APPROVE, purchaseReturn.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + purchaseReturns.forEach(purchaseReturn -> { + // 2.1 删除订单 + purchaseReturnMapper.deleteById(purchaseReturn.getId()); + // 2.2 删除订单项 + purchaseReturnItemMapper.deleteByReturnId(purchaseReturn.getId()); + + // 2.3 更新采购订单的出库数量 + updatePurchaseOrderReturnCount(purchaseReturn.getOrderId()); + }); + + } + + private ErpPurchaseReturnDO validatePurchaseReturnExists(Long id) { + ErpPurchaseReturnDO purchaseReturn = purchaseReturnMapper.selectById(id); + if (purchaseReturn == null) { + throw exception(PURCHASE_RETURN_NOT_EXISTS); + } + return purchaseReturn; + } + + @Override + public ErpPurchaseReturnDO getPurchaseReturn(Long id) { + return purchaseReturnMapper.selectById(id); + } + + @Override + public ErpPurchaseReturnDO validatePurchaseReturn(Long id) { + ErpPurchaseReturnDO purchaseReturn = getPurchaseReturn(id); + if (ObjectUtil.notEqual(purchaseReturn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(PURCHASE_RETURN_NOT_APPROVE); + } + return purchaseReturn; + } + + @Override + public PageResult getPurchaseReturnPage(ErpPurchaseReturnPageReqVO pageReqVO) { + return purchaseReturnMapper.selectPage(pageReqVO); + } + + // ==================== 采购退货项 ==================== + + @Override + public List getPurchaseReturnItemListByReturnId(Long returnId) { + return purchaseReturnItemMapper.selectListByReturnId(returnId); + } + + @Override + public List getPurchaseReturnItemListByReturnIds(Collection returnIds) { + if (CollUtil.isEmpty(returnIds)) { + return Collections.emptyList(); + } + return purchaseReturnItemMapper.selectListByReturnIds(returnIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java new file mode 100644 index 0000000..f1afb6a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierService.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 供应商 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSupplierService { + + /** + * 创建供应商 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSupplier(@Valid ErpSupplierSaveReqVO createReqVO); + + /** + * 更新供应商 + * + * @param updateReqVO 更新信息 + */ + void updateSupplier(@Valid ErpSupplierSaveReqVO updateReqVO); + + /** + * 删除供应商 + * + * @param id 编号 + */ + void deleteSupplier(Long id); + + /** + * 获得供应商 + * + * @param id 编号 + * @return 供应商 + */ + ErpSupplierDO getSupplier(Long id); + + /** + * 校验供应商 + * + * @param id 编号 + * @return 供应商 + */ + ErpSupplierDO validateSupplier(Long id); + + /** + * 获得供应商列表 + * + * @param ids 编号列表 + * @return 供应商列表 + */ + List getSupplierList(Collection ids); + + /** + * 获得供应商 Map + * + * @param ids 编号列表 + * @return 供应商 Map + */ + default Map getSupplierMap(Collection ids) { + return convertMap(getSupplierList(ids), ErpSupplierDO::getId); + } + + /** + * 获得供应商分页 + * + * @param pageReqVO 分页查询 + * @return 供应商分页 + */ + PageResult getSupplierPage(ErpSupplierPageReqVO pageReqVO); + + /** + * 获得指定状态的供应商列表 + * + * @param status 状态 + * @return 供应商列表 + */ + List getSupplierListByStatus(Integer status); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java new file mode 100644 index 0000000..af6f2ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.erp.service.purchase; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpSupplierMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.SUPPLIER_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.SUPPLIER_NOT_EXISTS; + +/** + * ERP 供应商 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpSupplierServiceImpl implements ErpSupplierService { + + @Resource + private ErpSupplierMapper supplierMapper; + + @Override + public Long createSupplier(ErpSupplierSaveReqVO createReqVO) { + ErpSupplierDO supplier = BeanUtils.toBean(createReqVO, ErpSupplierDO.class); + supplierMapper.insert(supplier); + return supplier.getId(); + } + + @Override + public void updateSupplier(ErpSupplierSaveReqVO updateReqVO) { + // 校验存在 + validateSupplierExists(updateReqVO.getId()); + // 更新 + ErpSupplierDO updateObj = BeanUtils.toBean(updateReqVO, ErpSupplierDO.class); + supplierMapper.updateById(updateObj); + } + + @Override + public void deleteSupplier(Long id) { + // 校验存在 + validateSupplierExists(id); + // 删除 + supplierMapper.deleteById(id); + } + + private void validateSupplierExists(Long id) { + if (supplierMapper.selectById(id) == null) { + throw exception(SUPPLIER_NOT_EXISTS); + } + } + + @Override + public ErpSupplierDO getSupplier(Long id) { + return supplierMapper.selectById(id); + } + + @Override + public ErpSupplierDO validateSupplier(Long id) { + ErpSupplierDO supplier = supplierMapper.selectById(id); + if (supplier == null) { + throw exception(SUPPLIER_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(supplier.getStatus())) { + throw exception(SUPPLIER_NOT_ENABLE, supplier.getName()); + } + return supplier; + } + + @Override + public List getSupplierList(Collection ids) { + return supplierMapper.selectBatchIds(ids); + } + + @Override + public PageResult getSupplierPage(ErpSupplierPageReqVO pageReqVO) { + return supplierMapper.selectPage(pageReqVO); + } + + @Override + public List getSupplierListByStatus(Integer status) { + return supplierMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java new file mode 100644 index 0000000..e70c090 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerService.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 客户 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpCustomerService { + + /** + * 创建客户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCustomer(@Valid ErpCustomerSaveReqVO createReqVO); + + /** + * 更新客户 + * + * @param updateReqVO 更新信息 + */ + void updateCustomer(@Valid ErpCustomerSaveReqVO updateReqVO); + + /** + * 删除客户 + * + * @param id 编号 + */ + void deleteCustomer(Long id); + + /** + * 获得客户 + * + * @param id 编号 + * @return 客户 + */ + ErpCustomerDO getCustomer(Long id); + + /** + * 校验客户 + * + * @param id 编号 + * @return 客户 + */ + ErpCustomerDO validateCustomer(Long id); + + /** + * 获得客户列表 + * + * @param ids 编号列表 + * @return 客户列表 + */ + List getCustomerList(Collection ids); + + /** + * 获得客户 Map + * + * @param ids 编号列表 + * @return 客户 Map + */ + default Map getCustomerMap(Collection ids) { + return convertMap(getCustomerList(ids), ErpCustomerDO::getId); + } + + /** + * 获得客户分页 + * + * @param pageReqVO 分页查询 + * @return 客户分页 + */ + PageResult getCustomerPage(ErpCustomerPageReqVO pageReqVO); + + /** + * 获得指定状态的客户列表 + * + * @param status 状态 + * @return 客户列表 + */ + List getCustomerListByStatus(Integer status); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java new file mode 100644 index 0000000..7df07fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpCustomerServiceImpl.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.customer.ErpCustomerSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpCustomerMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.CUSTOMER_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; + +/** + * ERP 客户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpCustomerServiceImpl implements ErpCustomerService { + + @Resource + private ErpCustomerMapper customerMapper; + + @Override + public Long createCustomer(ErpCustomerSaveReqVO createReqVO) { + // 插入 + ErpCustomerDO customer = BeanUtils.toBean(createReqVO, ErpCustomerDO.class); + customerMapper.insert(customer); + // 返回 + return customer.getId(); + } + + @Override + public void updateCustomer(ErpCustomerSaveReqVO updateReqVO) { + // 校验存在 + validateCustomerExists(updateReqVO.getId()); + // 更新 + ErpCustomerDO updateObj = BeanUtils.toBean(updateReqVO, ErpCustomerDO.class); + customerMapper.updateById(updateObj); + } + + @Override + public void deleteCustomer(Long id) { + // 校验存在 + validateCustomerExists(id); + // 删除 + customerMapper.deleteById(id); + } + + private void validateCustomerExists(Long id) { + if (customerMapper.selectById(id) == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + } + + @Override + public ErpCustomerDO getCustomer(Long id) { + return customerMapper.selectById(id); + } + + @Override + public ErpCustomerDO validateCustomer(Long id) { + ErpCustomerDO customer = customerMapper.selectById(id); + if (customer == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(customer.getStatus())) { + throw exception(CUSTOMER_NOT_ENABLE, customer.getName()); + } + return customer; + } + + @Override + public List getCustomerList(Collection ids) { + return customerMapper.selectBatchIds(ids); + } + + @Override + public PageResult getCustomerPage(ErpCustomerPageReqVO pageReqVO) { + return customerMapper.selectPage(pageReqVO); + } + + @Override + public List getCustomerListByStatus(Integer status) { + return customerMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java new file mode 100644 index 0000000..dad0894 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * ERP 销售订单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSaleOrderService { + + /** + * 创建销售订单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSaleOrder(@Valid ErpSaleOrderSaveReqVO createReqVO); + + /** + * 更新销售订单 + * + * @param updateReqVO 更新信息 + */ + void updateSaleOrder(@Valid ErpSaleOrderSaveReqVO updateReqVO); + + /** + * 更新销售订单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateSaleOrderStatus(Long id, Integer status); + + /** + * 更新销售订单的出库数量 + * + * @param id 编号 + * @param outCountMap 出库数量 Map:key 销售订单项编号;value 出库数量 + */ + void updateSaleOrderOutCount(Long id, Map outCountMap); + + /** + * 更新销售订单的退货数量 + * + * @param orderId 编号 + * @param returnCountMap 退货数量 Map:key 销售订单项编号;value 退货数量 + */ + void updateSaleOrderReturnCount(Long orderId, Map returnCountMap); + + /** + * 删除销售订单 + * + * @param ids 编号数组 + */ + void deleteSaleOrder(List ids); + + /** + * 获得销售订单 + * + * @param id 编号 + * @return 销售订单 + */ + ErpSaleOrderDO getSaleOrder(Long id); + + /** + * 校验销售订单,已经审核通过 + * + * @param id 编号 + * @return 销售订单 + */ + ErpSaleOrderDO validateSaleOrder(Long id); + + /** + * 获得销售订单分页 + * + * @param pageReqVO 分页查询 + * @return 销售订单分页 + */ + PageResult getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO); + + // ==================== 销售订单项 ==================== + + /** + * 获得销售订单项列表 + * + * @param orderId 销售订单编号 + * @return 销售订单项列表 + */ + List getSaleOrderItemListByOrderId(Long orderId); + + /** + * 获得销售订单项 List + * + * @param orderIds 销售订单编号数组 + * @return 销售订单项 List + */ + List getSaleOrderItemListByOrderIds(Collection orderIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java new file mode 100644 index 0000000..7c25d06 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java @@ -0,0 +1,307 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 销售订单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { + + @Resource + private ErpSaleOrderMapper saleOrderMapper; + @Resource + private ErpSaleOrderItemMapper saleOrderItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpCustomerService customerService; + @Resource + private ErpAccountService accountService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createSaleOrder(ErpSaleOrderSaveReqVO createReqVO) { + // 1.1 校验订单项的有效性 + List saleOrderItems = validateSaleOrderItems(createReqVO.getItems()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); + // 1.3 校验结算账户 + if (createReqVO.getAccountId() != null) { + accountService.validateAccount(createReqVO.getAccountId()); + } + // 1.4 校验销售人员 + if (createReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(createReqVO.getSaleUserId()); + } + // 1.5 生成订单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_ORDER_NO_PREFIX); + if (saleOrderMapper.selectByNo(no) != null) { + throw exception(SALE_ORDER_NO_EXISTS); + } + + // 2.1 插入订单 + ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())); + calculateTotalPrice(saleOrder, saleOrderItems); + saleOrderMapper.insert(saleOrder); + // 2.2 插入订单项 + saleOrderItems.forEach(o -> o.setOrderId(saleOrder.getId())); + saleOrderItemMapper.insertBatch(saleOrderItems); + return saleOrder.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpSaleOrderDO saleOrder = validateSaleOrderExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { + throw exception(SALE_ORDER_UPDATE_FAIL_APPROVE, saleOrder.getNo()); + } + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); + // 1.3 校验结算账户 + if (updateReqVO.getAccountId() != null) { + accountService.validateAccount(updateReqVO.getAccountId()); + } + // 1.4 校验销售人员 + if (updateReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(updateReqVO.getSaleUserId()); + } + // 1.5 校验订单项的有效性 + List saleOrderItems = validateSaleOrderItems(updateReqVO.getItems()); + + // 2.1 更新订单 + ErpSaleOrderDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOrderDO.class); + calculateTotalPrice(updateObj, saleOrderItems); + saleOrderMapper.updateById(updateObj); + // 2.2 更新订单项 + updateSaleOrderItemList(updateReqVO.getId(), saleOrderItems); + } + + private void calculateTotalPrice(ErpSaleOrderDO saleOrder, List saleOrderItems) { + saleOrder.setTotalCount(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getCount, BigDecimal::add)); + saleOrder.setTotalProductPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + saleOrder.setTotalTaxPrice(getSumValue(saleOrderItems, ErpSaleOrderItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + saleOrder.setTotalPrice(saleOrder.getTotalProductPrice().add(saleOrder.getTotalTaxPrice())); + // 计算优惠价格 + if (saleOrder.getDiscountPercent() == null) { + saleOrder.setDiscountPercent(BigDecimal.ZERO); + } + saleOrder.setDiscountPrice(MoneyUtils.priceMultiplyPercent(saleOrder.getTotalPrice(), saleOrder.getDiscountPercent())); + saleOrder.setTotalPrice(saleOrder.getTotalPrice().subtract(saleOrder.getDiscountPrice())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleOrderStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpSaleOrderDO saleOrder = validateSaleOrderExists(id); + // 1.2 校验状态 + if (saleOrder.getStatus().equals(status)) { + throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL); + } + // 1.3 存在销售出库单,无法反审核 + if (!approve && saleOrder.getOutCount().compareTo(BigDecimal.ZERO) > 0) { + throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_OUT); + } + // 1.4 存在销售退货单,无法反审核 + if (!approve && saleOrder.getReturnCount().compareTo(BigDecimal.ZERO) > 0) { + throw exception(SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN); + } + + // 2. 更新状态 + int updateCount = saleOrderMapper.updateByIdAndStatus(id, saleOrder.getStatus(), + new ErpSaleOrderDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL); + } + } + + private List validateSaleOrderItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpSaleOrderSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpSaleOrderItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOrderItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updateSaleOrderItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = saleOrderItemMapper.selectListByOrderId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setOrderId(id)); + saleOrderItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + saleOrderItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + saleOrderItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOrderItemDO::getId)); + } + } + + @Override + public void updateSaleOrderOutCount(Long id, Map outCountMap) { + List orderItems = saleOrderItemMapper.selectListByOrderId(id); + // 1. 更新每个销售订单项 + orderItems.forEach(item -> { + BigDecimal outCount = outCountMap.getOrDefault(item.getId(), BigDecimal.ZERO); + if (item.getOutCount().equals(outCount)) { + return; + } + if (outCount.compareTo(item.getCount()) > 0) { + throw exception(SALE_ORDER_ITEM_OUT_FAIL_PRODUCT_EXCEED, + productService.getProduct(item.getProductId()).getName(), item.getCount()); + } + saleOrderItemMapper.updateById(new ErpSaleOrderItemDO().setId(item.getId()).setOutCount(outCount)); + }); + // 2. 更新销售订单 + BigDecimal totalOutCount = getSumValue(outCountMap.values(), value -> value, BigDecimal::add, BigDecimal.ZERO); + saleOrderMapper.updateById(new ErpSaleOrderDO().setId(id).setOutCount(totalOutCount)); + } + + @Override + public void updateSaleOrderReturnCount(Long orderId, Map returnCountMap) { + List orderItems = saleOrderItemMapper.selectListByOrderId(orderId); + // 1. 更新每个销售订单项 + orderItems.forEach(item -> { + BigDecimal returnCount = returnCountMap.getOrDefault(item.getId(), BigDecimal.ZERO); + if (item.getReturnCount().equals(returnCount)) { + return; + } + if (returnCount.compareTo(item.getOutCount()) > 0) { + throw exception(SALE_ORDER_ITEM_RETURN_FAIL_OUT_EXCEED, + productService.getProduct(item.getProductId()).getName(), item.getOutCount()); + } + saleOrderItemMapper.updateById(new ErpSaleOrderItemDO().setId(item.getId()).setReturnCount(returnCount)); + }); + // 2. 更新销售订单 + BigDecimal totalReturnCount = getSumValue(returnCountMap.values(), value -> value, BigDecimal::add, BigDecimal.ZERO); + saleOrderMapper.updateById(new ErpSaleOrderDO().setId(orderId).setReturnCount(totalReturnCount)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSaleOrder(List ids) { + // 1. 校验不处于已审批 + List saleOrders = saleOrderMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(saleOrders)) { + return; + } + saleOrders.forEach(saleOrder -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOrder.getStatus())) { + throw exception(SALE_ORDER_DELETE_FAIL_APPROVE, saleOrder.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + saleOrders.forEach(saleOrder -> { + // 2.1 删除订单 + saleOrderMapper.deleteById(saleOrder.getId()); + // 2.2 删除订单项 + saleOrderItemMapper.deleteByOrderId(saleOrder.getId()); + }); + } + + private ErpSaleOrderDO validateSaleOrderExists(Long id) { + ErpSaleOrderDO saleOrder = saleOrderMapper.selectById(id); + if (saleOrder == null) { + throw exception(SALE_ORDER_NOT_EXISTS); + } + return saleOrder; + } + + @Override + public ErpSaleOrderDO getSaleOrder(Long id) { + return saleOrderMapper.selectById(id); + } + + @Override + public ErpSaleOrderDO validateSaleOrder(Long id) { + ErpSaleOrderDO saleOrder = validateSaleOrderExists(id); + if (ObjectUtil.notEqual(saleOrder.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(SALE_ORDER_NOT_APPROVE); + } + return saleOrder; + } + + @Override + public PageResult getSaleOrderPage(ErpSaleOrderPageReqVO pageReqVO) { + return saleOrderMapper.selectPage(pageReqVO); + } + + // ==================== 订单项 ==================== + + @Override + public List getSaleOrderItemListByOrderId(Long orderId) { + return saleOrderItemMapper.selectListByOrderId(orderId); + } + + @Override + public List getSaleOrderItemListByOrderIds(Collection orderIds) { + if (CollUtil.isEmpty(orderIds)) { + return Collections.emptyList(); + } + return saleOrderItemMapper.selectListByOrderIds(orderIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java new file mode 100644 index 0000000..a57f013 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * ERP 销售出库 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSaleOutService { + + /** + * 创建销售出库 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSaleOut(@Valid ErpSaleOutSaveReqVO createReqVO); + + /** + * 更新销售出库 + * + * @param updateReqVO 更新信息 + */ + void updateSaleOut(@Valid ErpSaleOutSaveReqVO updateReqVO); + + /** + * 更新销售出库的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateSaleOutStatus(Long id, Integer status); + + /** + * 更新销售出库的收款金额 + * + * @param id 编号 + * @param receiptPrice 收款金额 + */ + void updateSaleInReceiptPrice(Long id, BigDecimal receiptPrice); + + /** + * 删除销售出库 + * + * @param ids 编号数组 + */ + void deleteSaleOut(List ids); + + /** + * 获得销售出库 + * + * @param id 编号 + * @return 销售出库 + */ + ErpSaleOutDO getSaleOut(Long id); + + /** + * 校验销售出库,已经审核通过 + * + * @param id 编号 + * @return 销售出库 + */ + ErpSaleOutDO validateSaleOut(Long id); + + /** + * 获得销售出库分页 + * + * @param pageReqVO 分页查询 + * @return 销售出库分页 + */ + PageResult getSaleOutPage(ErpSaleOutPageReqVO pageReqVO); + + // ==================== 销售出库项 ==================== + + /** + * 获得销售出库项列表 + * + * @param outId 销售出库编号 + * @return 销售出库项列表 + */ + List getSaleOutItemListByOutId(Long outId); + + /** + * 获得销售出库项 List + * + * @param outIds 销售出库编号数组 + * @return 销售出库项 List + */ + List getSaleOutItemListByOutIds(Collection outIds); + + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java new file mode 100644 index 0000000..16d20dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java @@ -0,0 +1,316 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 销售出库 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpSaleOutServiceImpl implements ErpSaleOutService { + + @Resource + private ErpSaleOutMapper saleOutMapper; + @Resource + private ErpSaleOutItemMapper saleOutItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpSaleOrderService saleOrderService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpStockRecordService stockRecordService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createSaleOut(ErpSaleOutSaveReqVO createReqVO) { + // 1.1 校验销售订单已审核 + ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(createReqVO.getOrderId()); + // 1.2 校验出库项的有效性 + List saleOutItems = validateSaleOutItems(createReqVO.getItems()); + // 1.3 校验结算账户 + accountService.validateAccount(createReqVO.getAccountId()); + // 1.4 校验销售人员 + if (createReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(createReqVO.getSaleUserId()); + } + // 1.5 生成出库单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_OUT_NO_PREFIX); + if (saleOutMapper.selectByNo(no) != null) { + throw exception(SALE_OUT_NO_EXISTS); + } + + // 2.1 插入出库 + ErpSaleOutDO saleOut = BeanUtils.toBean(createReqVO, ErpSaleOutDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) + .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); + calculateTotalPrice(saleOut, saleOutItems); + saleOutMapper.insert(saleOut); + // 2.2 插入出库项 + saleOutItems.forEach(o -> o.setOutId(saleOut.getId())); + saleOutItemMapper.insertBatch(saleOutItems); + + // 3. 更新销售订单的出库数量 + updateSaleOrderOutCount(createReqVO.getOrderId()); + return saleOut.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleOut(ErpSaleOutSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpSaleOutDO saleOut = validateSaleOutExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) { + throw exception(SALE_OUT_UPDATE_FAIL_APPROVE, saleOut.getNo()); + } + // 1.2 校验销售订单已审核 + ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(updateReqVO.getOrderId()); + // 1.3 校验结算账户 + accountService.validateAccount(updateReqVO.getAccountId()); + // 1.4 校验销售人员 + if (updateReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(updateReqVO.getSaleUserId()); + } + // 1.5 校验订单项的有效性 + List saleOutItems = validateSaleOutItems(updateReqVO.getItems()); + + // 2.1 更新出库 + ErpSaleOutDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOutDO.class) + .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); + calculateTotalPrice(updateObj, saleOutItems); + saleOutMapper.updateById(updateObj); + // 2.2 更新出库项 + updateSaleOutItemList(updateReqVO.getId(), saleOutItems); + + // 3.1 更新销售订单的出库数量 + updateSaleOrderOutCount(updateObj.getOrderId()); + // 3.2 注意:如果销售订单编号变更了,需要更新“老”销售订单的出库数量 + if (ObjectUtil.notEqual(saleOut.getOrderId(), updateObj.getOrderId())) { + updateSaleOrderOutCount(saleOut.getOrderId()); + } + } + + private void calculateTotalPrice(ErpSaleOutDO saleOut, List saleOutItems) { + saleOut.setTotalCount(getSumValue(saleOutItems, ErpSaleOutItemDO::getCount, BigDecimal::add)); + saleOut.setTotalProductPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + saleOut.setTotalTaxPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + saleOut.setTotalPrice(saleOut.getTotalProductPrice().add(saleOut.getTotalTaxPrice())); + // 计算优惠价格 + if (saleOut.getDiscountPercent() == null) { + saleOut.setDiscountPercent(BigDecimal.ZERO); + } + saleOut.setDiscountPrice(MoneyUtils.priceMultiplyPercent(saleOut.getTotalPrice(), saleOut.getDiscountPercent())); + saleOut.setTotalPrice(saleOut.getTotalPrice().subtract(saleOut.getDiscountPrice().add(saleOut.getOtherPrice()))); + } + + private void updateSaleOrderOutCount(Long orderId) { + // 1.1 查询销售订单对应的销售出库单列表 + List saleOuts = saleOutMapper.selectListByOrderId(orderId); + // 1.2 查询对应的销售订单项的出库数量 + Map returnCountMap = saleOutItemMapper.selectOrderItemCountSumMapByOutIds( + convertList(saleOuts, ErpSaleOutDO::getId)); + // 2. 更新销售订单的出库数量 + saleOrderService.updateSaleOrderOutCount(orderId, returnCountMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleOutStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpSaleOutDO saleOut = validateSaleOutExists(id); + // 1.2 校验状态 + if (saleOut.getStatus().equals(status)) { + throw exception(approve ? SALE_OUT_APPROVE_FAIL : SALE_OUT_PROCESS_FAIL); + } + // 1.3 校验已退款 + if (!approve && saleOut.getReceiptPrice().compareTo(BigDecimal.ZERO) > 0) { + throw exception(SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT); + } + + // 2. 更新状态 + int updateCount = saleOutMapper.updateByIdAndStatus(id, saleOut.getStatus(), + new ErpSaleOutDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? SALE_OUT_APPROVE_FAIL : SALE_OUT_PROCESS_FAIL); + } + + // 3. 变更库存 + List saleOutItems = saleOutItemMapper.selectListByOutId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.SALE_OUT.getType() + : ErpStockRecordBizTypeEnum.SALE_OUT_CANCEL.getType(); + saleOutItems.forEach(saleOutItem -> { + BigDecimal count = approve ? saleOutItem.getCount().negate() : saleOutItem.getCount(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + saleOutItem.getProductId(), saleOutItem.getWarehouseId(), count, + bizType, saleOutItem.getOutId(), saleOutItem.getId(), saleOut.getNo())); + }); + } + + @Override + public void updateSaleInReceiptPrice(Long id, BigDecimal receiptPrice) { + ErpSaleOutDO saleOut = saleOutMapper.selectById(id); + if (saleOut.getReceiptPrice().equals(receiptPrice)) { + return; + } + if (receiptPrice.compareTo(saleOut.getTotalPrice()) > 0) { + throw exception(SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED, receiptPrice, saleOut.getTotalPrice()); + } + saleOutMapper.updateById(new ErpSaleOutDO().setId(id).setReceiptPrice(receiptPrice)); + } + + private List validateSaleOutItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpSaleOutSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpSaleOutItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOutItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updateSaleOutItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = saleOutItemMapper.selectListByOutId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setOutId(id)); + saleOutItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + saleOutItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + saleOutItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOutItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSaleOut(List ids) { + // 1. 校验不处于已审批 + List saleOuts = saleOutMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(saleOuts)) { + return; + } + saleOuts.forEach(saleOut -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) { + throw exception(SALE_OUT_DELETE_FAIL_APPROVE, saleOut.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + saleOuts.forEach(saleOut -> { + // 2.1 删除订单 + saleOutMapper.deleteById(saleOut.getId()); + // 2.2 删除订单项 + saleOutItemMapper.deleteByOutId(saleOut.getId()); + + // 2.3 更新销售订单的出库数量 + updateSaleOrderOutCount(saleOut.getOrderId()); + }); + + } + + private ErpSaleOutDO validateSaleOutExists(Long id) { + ErpSaleOutDO saleOut = saleOutMapper.selectById(id); + if (saleOut == null) { + throw exception(SALE_OUT_NOT_EXISTS); + } + return saleOut; + } + + @Override + public ErpSaleOutDO getSaleOut(Long id) { + return saleOutMapper.selectById(id); + } + + @Override + public ErpSaleOutDO validateSaleOut(Long id) { + ErpSaleOutDO saleOut = validateSaleOutExists(id); + if (ObjectUtil.notEqual(saleOut.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(SALE_OUT_NOT_APPROVE); + } + return saleOut; + } + + @Override + public PageResult getSaleOutPage(ErpSaleOutPageReqVO pageReqVO) { + return saleOutMapper.selectPage(pageReqVO); + } + + // ==================== 销售出库项 ==================== + + @Override + public List getSaleOutItemListByOutId(Long outId) { + return saleOutItemMapper.selectListByOutId(outId); + } + + @Override + public List getSaleOutItemListByOutIds(Collection outIds) { + if (CollUtil.isEmpty(outIds)) { + return Collections.emptyList(); + } + return saleOutItemMapper.selectListByOutIds(outIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnService.java new file mode 100644 index 0000000..6f18dc0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnService.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * ERP 销售退货 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSaleReturnService { + + /** + * 创建销售退货 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSaleReturn(@Valid ErpSaleReturnSaveReqVO createReqVO); + + /** + * 更新销售退货 + * + * @param updateReqVO 更新信息 + */ + void updateSaleReturn(@Valid ErpSaleReturnSaveReqVO updateReqVO); + + /** + * 更新销售退货的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateSaleReturnStatus(Long id, Integer status); + + /** + * 更新销售退货的退款金额 + * + * @param id 编号 + * @param refundPrice 退款金额 + */ + void updateSaleReturnRefundPrice(Long id, BigDecimal refundPrice); + + /** + * 删除销售退货 + * + * @param ids 编号数组 + */ + void deleteSaleReturn(List ids); + + /** + * 获得销售退货 + * + * @param id 编号 + * @return 销售退货 + */ + ErpSaleReturnDO getSaleReturn(Long id); + + /** + * 校验销售退货,已经审核通过 + * + * @param id 编号 + * @return 销售退货 + */ + ErpSaleReturnDO validateSaleReturn(Long id); + + /** + * 获得销售退货分页 + * + * @param pageReqVO 分页查询 + * @return 销售退货分页 + */ + PageResult getSaleReturnPage(ErpSaleReturnPageReqVO pageReqVO); + + // ==================== 销售退货项 ==================== + + /** + * 获得销售退货项列表 + * + * @param returnId 销售退货编号 + * @return 销售退货项列表 + */ + List getSaleReturnItemListByReturnId(Long returnId); + + /** + * 获得销售退货项 List + * + * @param returnIds 销售退货编号数组 + * @return 销售退货项 List + */ + List getSaleReturnItemListByReturnIds(Collection returnIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java new file mode 100644 index 0000000..209df11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java @@ -0,0 +1,316 @@ +package cn.iocoder.yudao.module.erp.service.sale; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleReturnItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleReturnMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 销售退货 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpSaleReturnServiceImpl implements ErpSaleReturnService { + + @Resource + private ErpSaleReturnMapper saleReturnMapper; + @Resource + private ErpSaleReturnItemMapper saleReturnItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ErpSaleOrderService saleOrderService; + @Resource + private ErpAccountService accountService; + @Resource + private ErpStockRecordService stockRecordService; + + @Resource + private AdminUserApi adminUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createSaleReturn(ErpSaleReturnSaveReqVO createReqVO) { + // 1.1 校验销售订单已审核 + ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(createReqVO.getOrderId()); + // 1.2 校验退货项的有效性 + List saleReturnItems = validateSaleReturnItems(createReqVO.getItems()); + // 1.3 校验结算账户 + accountService.validateAccount(createReqVO.getAccountId()); + // 1.4 校验销售人员 + if (createReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(createReqVO.getSaleUserId()); + } + // 1.5 生成退货单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_RETURN_NO_PREFIX); + if (saleReturnMapper.selectByNo(no) != null) { + throw exception(SALE_RETURN_NO_EXISTS); + } + + // 2.1 插入退货 + ErpSaleReturnDO saleReturn = BeanUtils.toBean(createReqVO, ErpSaleReturnDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) + .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); + calculateTotalPrice(saleReturn, saleReturnItems); + saleReturnMapper.insert(saleReturn); + // 2.2 插入退货项 + saleReturnItems.forEach(o -> o.setReturnId(saleReturn.getId())); + saleReturnItemMapper.insertBatch(saleReturnItems); + + // 3. 更新销售订单的退货数量 + updateSaleOrderReturnCount(createReqVO.getOrderId()); + return saleReturn.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleReturn(ErpSaleReturnSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpSaleReturnDO saleReturn = validateSaleReturnExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(saleReturn.getStatus())) { + throw exception(SALE_RETURN_UPDATE_FAIL_APPROVE, saleReturn.getNo()); + } + // 1.2 校验销售订单已审核 + ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(updateReqVO.getOrderId()); + // 1.3 校验结算账户 + accountService.validateAccount(updateReqVO.getAccountId()); + // 1.4 校验销售人员 + if (updateReqVO.getSaleUserId() != null) { + adminUserApi.validateUser(updateReqVO.getSaleUserId()); + } + // 1.5 校验订单项的有效性 + List saleReturnItems = validateSaleReturnItems(updateReqVO.getItems()); + + // 2.1 更新退货 + ErpSaleReturnDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleReturnDO.class) + .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); + calculateTotalPrice(updateObj, saleReturnItems); + saleReturnMapper.updateById(updateObj); + // 2.2 更新退货项 + updateSaleReturnItemList(updateReqVO.getId(), saleReturnItems); + + // 3.1 更新销售订单的出库数量 + updateSaleOrderReturnCount(updateObj.getOrderId()); + // 3.2 注意:如果销售订单编号变更了,需要更新“老”销售订单的出库数量 + if (ObjectUtil.notEqual(saleReturn.getOrderId(), updateObj.getOrderId())) { + updateSaleOrderReturnCount(saleReturn.getOrderId()); + } + } + + private void calculateTotalPrice(ErpSaleReturnDO saleReturn, List saleReturnItems) { + saleReturn.setTotalCount(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getCount, BigDecimal::add)); + saleReturn.setTotalProductPrice(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + saleReturn.setTotalTaxPrice(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); + saleReturn.setTotalPrice(saleReturn.getTotalProductPrice().add(saleReturn.getTotalTaxPrice())); + // 计算优惠价格 + if (saleReturn.getDiscountPercent() == null) { + saleReturn.setDiscountPercent(BigDecimal.ZERO); + } + saleReturn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(saleReturn.getTotalPrice(), saleReturn.getDiscountPercent())); + saleReturn.setTotalPrice(saleReturn.getTotalPrice().subtract(saleReturn.getDiscountPrice().add(saleReturn.getOtherPrice()))); + } + + private void updateSaleOrderReturnCount(Long orderId) { + // 1.1 查询销售订单对应的销售出库单列表 + List saleReturns = saleReturnMapper.selectListByOrderId(orderId); + // 1.2 查询对应的销售订单项的退货数量 + Map returnCountMap = saleReturnItemMapper.selectOrderItemCountSumMapByReturnIds( + convertList(saleReturns, ErpSaleReturnDO::getId)); + // 2. 更新销售订单的出库数量 + saleOrderService.updateSaleOrderReturnCount(orderId, returnCountMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSaleReturnStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpSaleReturnDO saleReturn = validateSaleReturnExists(id); + // 1.2 校验状态 + if (saleReturn.getStatus().equals(status)) { + throw exception(approve ? SALE_RETURN_APPROVE_FAIL : SALE_RETURN_PROCESS_FAIL); + } + // 1.3 校验已退款 + if (!approve && saleReturn.getRefundPrice().compareTo(BigDecimal.ZERO) > 0) { + throw exception(SALE_RETURN_PROCESS_FAIL_EXISTS_REFUND); + } + + // 2. 更新状态 + int updateCount = saleReturnMapper.updateByIdAndStatus(id, saleReturn.getStatus(), + new ErpSaleReturnDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? SALE_RETURN_APPROVE_FAIL : SALE_RETURN_PROCESS_FAIL); + } + + // 3. 变更库存 + List saleReturnItems = saleReturnItemMapper.selectListByReturnId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.SALE_RETURN.getType() + : ErpStockRecordBizTypeEnum.SALE_RETURN_CANCEL.getType(); + saleReturnItems.forEach(saleReturnItem -> { + BigDecimal count = approve ? saleReturnItem.getCount() : saleReturnItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + saleReturnItem.getProductId(), saleReturnItem.getWarehouseId(), count, + bizType, saleReturnItem.getReturnId(), saleReturnItem.getId(), saleReturn.getNo())); + }); + } + + @Override + public void updateSaleReturnRefundPrice(Long id, BigDecimal refundPrice) { + ErpSaleReturnDO saleReturn = saleReturnMapper.selectById(id); + if (saleReturn.getRefundPrice().equals(refundPrice)) { + return; + } + if (refundPrice.compareTo(saleReturn.getTotalPrice()) > 0) { + throw exception(SALE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, saleReturn.getTotalPrice()); + } + saleReturnMapper.updateById(new ErpSaleReturnDO().setId(id).setRefundPrice(refundPrice)); + } + + private List validateSaleReturnItems(List list) { + // 1. 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpSaleReturnSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 2. 转化为 ErpSaleReturnItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpSaleReturnItemDO.class, item -> { + item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); + item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); + if (item.getTotalPrice() == null) { + return; + } + if (item.getTaxPercent() != null) { + item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); + } + })); + } + + private void updateSaleReturnItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = saleReturnItemMapper.selectListByReturnId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setReturnId(id)); + saleReturnItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + saleReturnItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + saleReturnItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleReturnItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSaleReturn(List ids) { + // 1. 校验不处于已审批 + List saleReturns = saleReturnMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(saleReturns)) { + return; + } + saleReturns.forEach(saleReturn -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(saleReturn.getStatus())) { + throw exception(SALE_RETURN_DELETE_FAIL_APPROVE, saleReturn.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + saleReturns.forEach(saleReturn -> { + // 2.1 删除订单 + saleReturnMapper.deleteById(saleReturn.getId()); + // 2.2 删除订单项 + saleReturnItemMapper.deleteByReturnId(saleReturn.getId()); + + // 2.3 更新销售订单的出库数量 + updateSaleOrderReturnCount(saleReturn.getOrderId()); + }); + + } + + private ErpSaleReturnDO validateSaleReturnExists(Long id) { + ErpSaleReturnDO saleReturn = saleReturnMapper.selectById(id); + if (saleReturn == null) { + throw exception(SALE_RETURN_NOT_EXISTS); + } + return saleReturn; + } + + @Override + public ErpSaleReturnDO getSaleReturn(Long id) { + return saleReturnMapper.selectById(id); + } + + @Override + public ErpSaleReturnDO validateSaleReturn(Long id) { + ErpSaleReturnDO saleReturn = validateSaleReturnExists(id); + if (ObjectUtil.notEqual(saleReturn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { + throw exception(SALE_RETURN_NOT_APPROVE); + } + return saleReturn; + } + + @Override + public PageResult getSaleReturnPage(ErpSaleReturnPageReqVO pageReqVO) { + return saleReturnMapper.selectPage(pageReqVO); + } + + // ==================== 销售退货项 ==================== + + @Override + public List getSaleReturnItemListByReturnId(Long returnId) { + return saleReturnItemMapper.selectListByReturnId(returnId); + } + + @Override + public List getSaleReturnItemListByReturnIds(Collection returnIds) { + if (CollUtil.isEmpty(returnIds)) { + return Collections.emptyList(); + } + return saleReturnItemMapper.selectListByReturnIds(returnIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java new file mode 100644 index 0000000..9134094 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.service.statistics; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购统计 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpPurchaseStatisticsService { + + /** + * 获得采购金额 + * + * 计算逻辑:采购出库的金额 - 采购退货的金额 + * + * @param beginTime >= 开始时间 + * @param endTime < 结束时间 + * @return 采购金额 + */ + BigDecimal getPurchasePrice(LocalDateTime beginTime, LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java new file mode 100644 index 0000000..588ff74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.erp.service.statistics; + +import cn.iocoder.yudao.module.erp.dal.mysql.statistics.ErpPurchaseStatisticsMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 采购统计 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class ErpPurchaseStatisticsServiceImpl implements ErpPurchaseStatisticsService { + + @Resource + private ErpPurchaseStatisticsMapper purchaseStatisticsMapper; + + @Override + public BigDecimal getPurchasePrice(LocalDateTime beginTime, LocalDateTime endTime) { + return purchaseStatisticsMapper.getPurchasePrice(beginTime, endTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java new file mode 100644 index 0000000..3c28bc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.service.statistics; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售统计 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpSaleStatisticsService { + + /** + * 获得销售金额 + * + * 计算逻辑:销售出库的金额 - 销售退货的金额 + * + * @param beginTime >= 开始时间 + * @param endTime < 结束时间 + * @return 销售金额 + */ + BigDecimal getSalePrice(LocalDateTime beginTime, LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java new file mode 100644 index 0000000..a666433 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.erp.service.statistics; + +import cn.iocoder.yudao.module.erp.dal.mysql.statistics.ErpSaleStatisticsMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * ERP 销售统计 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class ErpSaleStatisticsServiceImpl implements ErpSaleStatisticsService { + + @Resource + private ErpSaleStatisticsMapper saleStatisticsMapper; + + @Override + public BigDecimal getSalePrice(LocalDateTime beginTime, LocalDateTime endTime) { + return saleStatisticsMapper.getSalePrice(beginTime, endTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java new file mode 100644 index 0000000..02a1921 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存盘点单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockCheckService { + + /** + * 创建库存盘点单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockCheck(@Valid ErpStockCheckSaveReqVO createReqVO); + + /** + * 更新库存盘点单 + * + * @param updateReqVO 更新信息 + */ + void updateStockCheck(@Valid ErpStockCheckSaveReqVO updateReqVO); + + /** + * 更新库存盘点单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockCheckStatus(Long id, Integer status); + + /** + * 删除库存盘点单 + * + * @param ids 编号数组 + */ + void deleteStockCheck(List ids); + + /** + * 获得库存盘点单 + * + * @param id 编号 + * @return 库存盘点单 + */ + ErpStockCheckDO getStockCheck(Long id); + + /** + * 获得库存盘点单分页 + * + * @param pageReqVO 分页查询 + * @return 库存盘点单分页 + */ + PageResult getStockCheckPage(ErpStockCheckPageReqVO pageReqVO); + + // ==================== 盘点项 ==================== + + /** + * 获得库存盘点单项列表 + * + * @param checkId 盘点编号 + * @return 库存盘点单项列表 + */ + List getStockCheckItemListByCheckId(Long checkId); + + /** + * 获得库存盘点单项 List + * + * @param checkIds 盘点编号数组 + * @return 库存盘点单项 List + */ + List getStockCheckItemListByCheckIds(Collection checkIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java new file mode 100644 index 0000000..16afc71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java @@ -0,0 +1,232 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockCheckItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockCheckMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 库存盘点单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockCheckServiceImpl implements ErpStockCheckService { + + @Resource + private ErpStockCheckMapper stockCheckMapper; + @Resource + private ErpStockCheckItemMapper stockCheckItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) { + // 1.1 校验盘点项的有效性 + List stockCheckItems = validateStockCheckItems(createReqVO.getItems()); + // 1.2 生成盘点单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX); + if (stockCheckMapper.selectByNo(no) != null) { + throw exception(STOCK_CHECK_NO_EXISTS); + } + + // 2.1 插入盘点单 + ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockCheckMapper.insert(stockCheck); + // 2.2 插入盘点单项 + stockCheckItems.forEach(o -> o.setCheckId(stockCheck.getId())); + stockCheckItemMapper.insertBatch(stockCheckItems); + return stockCheck.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockCheck(ErpStockCheckSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockCheckDO stockCheck = validateStockCheckExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { + throw exception(STOCK_CHECK_UPDATE_FAIL_APPROVE, stockCheck.getNo()); + } + // 1.2 校验盘点项的有效性 + List stockCheckItems = validateStockCheckItems(updateReqVO.getItems()); + + // 2.1 更新盘点单 + ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in + .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add))); + stockCheckMapper.updateById(updateObj); + // 2.2 更新盘点单项 + updateStockCheckItemList(updateReqVO.getId(), stockCheckItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockCheckStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockCheckDO stockCheck = validateStockCheckExists(id); + // 1.2 校验状态 + if (stockCheck.getStatus().equals(status)) { + throw exception(approve ? STOCK_CHECK_APPROVE_FAIL : STOCK_CHECK_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockCheckMapper.updateByIdAndStatus(id, stockCheck.getStatus(), + new ErpStockCheckDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_CHECK_APPROVE_FAIL : STOCK_CHECK_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockCheckItems = stockCheckItemMapper.selectListByCheckId(id); + stockCheckItems.forEach(stockCheckItem -> { + // 没有盈亏,不用出入库 + if (stockCheckItem.getCount().compareTo(BigDecimal.ZERO) == 0) { + return; + } + // 10;12;-2() + BigDecimal count = approve ? stockCheckItem.getCount(): stockCheckItem.getCount().negate(); + Integer bizType; + if (approve) { + bizType = count.compareTo(BigDecimal.ZERO) > 0 ? ErpStockRecordBizTypeEnum.CHECK_MORE_IN.getType() + : ErpStockRecordBizTypeEnum.CHECK_LESS_OUT.getType(); + } else { + bizType = count.compareTo(BigDecimal.ZERO) > 0 ? ErpStockRecordBizTypeEnum.CHECK_MORE_IN_CANCEL.getType() + : ErpStockRecordBizTypeEnum.CHECK_LESS_OUT_CANCEL.getType(); + } + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockCheckItem.getProductId(), stockCheckItem.getWarehouseId(), count, + bizType, stockCheckItem.getCheckId(), stockCheckItem.getId(), stockCheck.getNo())); + }); + } + + private List validateStockCheckItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockCheckSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet(list, ErpStockCheckSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockCheckItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockCheckItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockCheckItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockCheckItemMapper.selectListByCheckId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setCheckId(id)); + stockCheckItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockCheckItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockCheckItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockCheckItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockCheck(List ids) { + // 1. 校验不处于已审批 + List stockChecks = stockCheckMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockChecks)) { + return; + } + stockChecks.forEach(stockCheck -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { + throw exception(STOCK_CHECK_DELETE_FAIL_APPROVE, stockCheck.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockChecks.forEach(stockCheck -> { + // 2.1 删除盘点单 + stockCheckMapper.deleteById(stockCheck.getId()); + // 2.2 删除盘点单项 + stockCheckItemMapper.deleteByCheckId(stockCheck.getId()); + }); + } + + private ErpStockCheckDO validateStockCheckExists(Long id) { + ErpStockCheckDO stockCheck = stockCheckMapper.selectById(id); + if (stockCheck == null) { + throw exception(STOCK_CHECK_NOT_EXISTS); + } + return stockCheck; + } + + @Override + public ErpStockCheckDO getStockCheck(Long id) { + return stockCheckMapper.selectById(id); + } + + @Override + public PageResult getStockCheckPage(ErpStockCheckPageReqVO pageReqVO) { + return stockCheckMapper.selectPage(pageReqVO); + } + + // ==================== 盘点项 ==================== + + @Override + public List getStockCheckItemListByCheckId(Long checkId) { + return stockCheckItemMapper.selectListByCheckId(checkId); + } + + @Override + public List getStockCheckItemListByCheckIds(Collection checkIds) { + if (CollUtil.isEmpty(checkIds)) { + return Collections.emptyList(); + } + return stockCheckItemMapper.selectListByCheckIds(checkIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java new file mode 100644 index 0000000..65a5063 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它入库单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockInService { + + /** + * 创建其它入库单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockIn(@Valid ErpStockInSaveReqVO createReqVO); + + /** + * 更新其它入库单 + * + * @param updateReqVO 更新信息 + */ + void updateStockIn(@Valid ErpStockInSaveReqVO updateReqVO); + + /** + * 更新其它入库单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockInStatus(Long id, Integer status); + + /** + * 删除其它入库单 + * + * @param ids 编号数组 + */ + void deleteStockIn(List ids); + + /** + * 获得其它入库单 + * + * @param id 编号 + * @return 其它入库单 + */ + ErpStockInDO getStockIn(Long id); + + /** + * 获得其它入库单分页 + * + * @param pageReqVO 分页查询 + * @return 其它入库单分页 + */ + PageResult getStockInPage(ErpStockInPageReqVO pageReqVO); + + // ==================== 入库项 ==================== + + /** + * 获得其它入库单项列表 + * + * @param inId 入库编号 + * @return 其它入库单项列表 + */ + List getStockInItemListByInId(Long inId); + + /** + * 获得其它入库单项 List + * + * @param inIds 入库编号数组 + * @return 其它入库单项 List + */ + List getStockInItemListByInIds(Collection inIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java new file mode 100644 index 0000000..85d93d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -0,0 +1,228 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 +/** + * ERP 其它入库单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockInServiceImpl implements ErpStockInService { + + @Resource + private ErpStockInMapper stockInMapper; + @Resource + private ErpStockInItemMapper stockInItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpSupplierService supplierService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockIn(ErpStockInSaveReqVO createReqVO) { + // 1.1 校验入库项的有效性 + List stockInItems = validateStockInItems(createReqVO.getItems()); + // 1.2 校验供应商 + supplierService.validateSupplier(createReqVO.getSupplierId()); + // 1.3 生成入库单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_IN_NO_PREFIX); + if (stockInMapper.selectByNo(no) != null) { + throw exception(STOCK_IN_NO_EXISTS); + } + + // 2.1 插入入库单 + ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockInMapper.insert(stockIn); + // 2.2 插入入库单项 + stockInItems.forEach(o -> o.setInId(stockIn.getId())); + stockInItemMapper.insertBatch(stockInItems); + return stockIn.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockIn(ErpStockInSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockInDO stockIn = validateStockInExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { + throw exception(STOCK_IN_UPDATE_FAIL_APPROVE, stockIn.getNo()); + } + // 1.2 校验供应商 + supplierService.validateSupplier(updateReqVO.getSupplierId()); + // 1.3 校验入库项的有效性 + List stockInItems = validateStockInItems(updateReqVO.getItems()); + + // 2.1 更新入库单 + ErpStockInDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockInDO.class, in -> in + .setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add))); + stockInMapper.updateById(updateObj); + // 2.2 更新入库单项 + updateStockInItemList(updateReqVO.getId(), stockInItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockInStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockInDO stockIn = validateStockInExists(id); + // 1.2 校验状态 + if (stockIn.getStatus().equals(status)) { + throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockInMapper.updateByIdAndStatus(id, stockIn.getStatus(), + new ErpStockInDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockInItems = stockInItemMapper.selectListByInId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_IN.getType() + : ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType(); + stockInItems.forEach(stockInItem -> { + BigDecimal count = approve ? stockInItem.getCount() : stockInItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockInItem.getProductId(), stockInItem.getWarehouseId(), count, + bizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo())); + }); + } + + private List validateStockInItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockInSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet( + list, ErpStockInSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockInItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockInItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockInItemMapper.selectListByInId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setInId(id)); + stockInItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockInItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockInItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockInItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockIn(List ids) { + // 1. 校验不处于已审批 + List stockIns = stockInMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockIns)) { + return; + } + stockIns.forEach(stockIn -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { + throw exception(STOCK_IN_DELETE_FAIL_APPROVE, stockIn.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockIns.forEach(stockIn -> { + // 2.1 删除入库单 + stockInMapper.deleteById(stockIn.getId()); + // 2.2 删除入库单项 + stockInItemMapper.deleteByInId(stockIn.getId()); + }); + } + + private ErpStockInDO validateStockInExists(Long id) { + ErpStockInDO stockIn = stockInMapper.selectById(id); + if (stockIn == null) { + throw exception(STOCK_IN_NOT_EXISTS); + } + return stockIn; + } + + @Override + public ErpStockInDO getStockIn(Long id) { + return stockInMapper.selectById(id); + } + + @Override + public PageResult getStockInPage(ErpStockInPageReqVO pageReqVO) { + return stockInMapper.selectPage(pageReqVO); + } + + // ==================== 入库项 ==================== + + @Override + public List getStockInItemListByInId(Long inId) { + return stockInItemMapper.selectListByInId(inId); + } + + @Override + public List getStockInItemListByInIds(Collection inIds) { + if (CollUtil.isEmpty(inIds)) { + return Collections.emptyList(); + } + return stockInItemMapper.selectListByInIds(inIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java new file mode 100644 index 0000000..b7d4ecf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 库存调拨单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockMoveService { + + /** + * 创建库存调拨单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockMove(@Valid ErpStockMoveSaveReqVO createReqVO); + + /** + * 更新库存调拨单 + * + * @param updateReqVO 更新信息 + */ + void updateStockMove(@Valid ErpStockMoveSaveReqVO updateReqVO); + + /** + * 更新库存调拨单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockMoveStatus(Long id, Integer status); + + /** + * 删除库存调拨单 + * + * @param ids 编号数组 + */ + void deleteStockMove(List ids); + + /** + * 获得库存调拨单 + * + * @param id 编号 + * @return 库存调拨单 + */ + ErpStockMoveDO getStockMove(Long id); + + /** + * 获得库存调拨单分页 + * + * @param pageReqVO 分页查询 + * @return 库存调拨单分页 + */ + PageResult getStockMovePage(ErpStockMovePageReqVO pageReqVO); + + // ==================== 调拨项 ==================== + + /** + * 获得库存调拨单项列表 + * + * @param moveId 调拨编号 + * @return 库存调拨单项列表 + */ + List getStockMoveItemListByMoveId(Long moveId); + + /** + * 获得库存调拨单项 List + * + * @param moveIds 调拨编号数组 + * @return 库存调拨单项 List + */ + List getStockMoveItemListByMoveIds(Collection moveIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java new file mode 100644 index 0000000..d99d026 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java @@ -0,0 +1,229 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 库存调拨单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockMoveServiceImpl implements ErpStockMoveService { + + @Resource + private ErpStockMoveMapper stockMoveMapper; + @Resource + private ErpStockMoveItemMapper stockMoveItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockMove(ErpStockMoveSaveReqVO createReqVO) { + // 1.1 校验出库项的有效性 + List stockMoveItems = validateStockMoveItems(createReqVO.getItems()); + // 1.2 生成调拨单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_MOVE_NO_PREFIX); + if (stockMoveMapper.selectByNo(no) != null) { + throw exception(STOCK_MOVE_NO_EXISTS); + } + + // 2.1 插入出库单 + ErpStockMoveDO stockMove = BeanUtils.toBean(createReqVO, ErpStockMoveDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockMoveMapper.insert(stockMove); + // 2.2 插入出库单项 + stockMoveItems.forEach(o -> o.setMoveId(stockMove.getId())); + stockMoveItemMapper.insertBatch(stockMoveItems); + return stockMove.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockMove(ErpStockMoveSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockMoveDO stockMove = validateStockMoveExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, stockMove.getNo()); + } + // 1.2 校验出库项的有效性 + List stockMoveItems = validateStockMoveItems(updateReqVO.getItems()); + + // 2.1 更新出库单 + ErpStockMoveDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockMoveDO.class, in -> in + .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add))); + stockMoveMapper.updateById(updateObj); + // 2.2 更新出库单项 + updateStockMoveItemList(updateReqVO.getId(), stockMoveItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockMoveStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockMoveDO stockMove = validateStockMoveExists(id); + // 1.2 校验状态 + if (stockMove.getStatus().equals(status)) { + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockMoveMapper.updateByIdAndStatus(id, stockMove.getStatus(), + new ErpStockMoveDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockMoveItems = stockMoveItemMapper.selectListByMoveId(id); + Integer fromBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_OUT.getType() + : ErpStockRecordBizTypeEnum.MOVE_OUT_CANCEL.getType(); + Integer toBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_IN.getType() + : ErpStockRecordBizTypeEnum.MOVE_IN_CANCEL.getType(); + stockMoveItems.forEach(stockMoveItem -> { + BigDecimal fromCount = approve ? stockMoveItem.getCount().negate() : stockMoveItem.getCount(); + BigDecimal toCount = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockMoveItem.getProductId(), stockMoveItem.getFromWarehouseId(), fromCount, + fromBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockMoveItem.getProductId(), stockMoveItem.getToWarehouseId(), toCount, + toBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo())); + }); + } + + private List validateStockMoveItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockMoveSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSetByFlatMap(list, + item -> Stream.of(item.getFromWarehouseId(), item.getToWarehouseId()))); + // 2. 转化为 ErpStockMoveItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockMoveItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockMoveItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockMoveItemMapper.selectListByMoveId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setMoveId(id)); + stockMoveItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockMoveItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockMoveItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockMoveItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockMove(List ids) { + // 1. 校验不处于已审批 + List stockMoves = stockMoveMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockMoves)) { + return; + } + stockMoves.forEach(stockMove -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_MOVE_DELETE_FAIL_APPROVE, stockMove.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockMoves.forEach(stockMove -> { + // 2.1 删除出库单 + stockMoveMapper.deleteById(stockMove.getId()); + // 2.2 删除出库单项 + stockMoveItemMapper.deleteByMoveId(stockMove.getId()); + }); + } + + private ErpStockMoveDO validateStockMoveExists(Long id) { + ErpStockMoveDO stockMove = stockMoveMapper.selectById(id); + if (stockMove == null) { + throw exception(STOCK_MOVE_NOT_EXISTS); + } + return stockMove; + } + + @Override + public ErpStockMoveDO getStockMove(Long id) { + return stockMoveMapper.selectById(id); + } + + @Override + public PageResult getStockMovePage(ErpStockMovePageReqVO pageReqVO) { + return stockMoveMapper.selectPage(pageReqVO); + } + + // ==================== 出库项 ==================== + + @Override + public List getStockMoveItemListByMoveId(Long moveId) { + return stockMoveItemMapper.selectListByMoveId(moveId); + } + + @Override + public List getStockMoveItemListByMoveIds(Collection moveIds) { + if (CollUtil.isEmpty(moveIds)) { + return Collections.emptyList(); + } + return stockMoveItemMapper.selectListByMoveIds(moveIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java new file mode 100644 index 0000000..ffd17fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * ERP 其它出库单 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockOutService { + + /** + * 创建其它出库单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStockOut(@Valid ErpStockOutSaveReqVO createReqVO); + + /** + * 更新其它出库单 + * + * @param updateReqVO 更新信息 + */ + void updateStockOut(@Valid ErpStockOutSaveReqVO updateReqVO); + + /** + * 更新其它出库单的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateStockOutStatus(Long id, Integer status); + + /** + * 删除其它出库单 + * + * @param ids 编号数组 + */ + void deleteStockOut(List ids); + + /** + * 获得其它出库单 + * + * @param id 编号 + * @return 其它出库单 + */ + ErpStockOutDO getStockOut(Long id); + + /** + * 获得其它出库单分页 + * + * @param pageReqVO 分页查询 + * @return 其它出库单分页 + */ + PageResult getStockOutPage(ErpStockOutPageReqVO pageReqVO); + + // ==================== 出库项 ==================== + + /** + * 获得其它出库单项列表 + * + * @param outId 出库编号 + * @return 其它出库单项列表 + */ + List getStockOutItemListByOutId(Long outId); + + /** + * 获得其它出库单项 List + * + * @param outIds 出库编号数组 + * @return 其它出库单项 List + */ + List getStockOutItemListByOutIds(Collection outIds); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java new file mode 100644 index 0000000..aa7428c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -0,0 +1,228 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper; +import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; +import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; + +// TODO 芋艿:记录操作日志 + +/** + * ERP 其它出库单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockOutServiceImpl implements ErpStockOutService { + + @Resource + private ErpStockOutMapper stockOutMapper; + @Resource + private ErpStockOutItemMapper stockOutItemMapper; + + @Resource + private ErpNoRedisDAO noRedisDAO; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpCustomerService customerService; + @Resource + private ErpStockRecordService stockRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStockOut(ErpStockOutSaveReqVO createReqVO) { + // 1.1 校验出库项的有效性 + List stockOutItems = validateStockOutItems(createReqVO.getItems()); + // 1.2 校验客户 + customerService.validateCustomer(createReqVO.getCustomerId()); + // 1.3 生成出库单号,并校验唯一性 + String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_OUT_NO_PREFIX); + if (stockOutMapper.selectByNo(no) != null) { + throw exception(STOCK_OUT_NO_EXISTS); + } + + // 2.1 插入出库单 + ErpStockOutDO stockOut = BeanUtils.toBean(createReqVO, ErpStockOutDO.class, in -> in + .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); + stockOutMapper.insert(stockOut); + // 2.2 插入出库单项 + stockOutItems.forEach(o -> o.setOutId(stockOut.getId())); + stockOutItemMapper.insertBatch(stockOutItems); + return stockOut.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockOut(ErpStockOutSaveReqVO updateReqVO) { + // 1.1 校验存在 + ErpStockOutDO stockOut = validateStockOutExists(updateReqVO.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { + throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockOut.getNo()); + } + // 1.2 校验客户 + customerService.validateCustomer(updateReqVO.getCustomerId()); + // 1.3 校验出库项的有效性 + List stockOutItems = validateStockOutItems(updateReqVO.getItems()); + + // 2.1 更新出库单 + ErpStockOutDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockOutDO.class, in -> in + .setTotalCount(getSumValue(stockOutItems, ErpStockOutItemDO::getCount, BigDecimal::add)) + .setTotalPrice(getSumValue(stockOutItems, ErpStockOutItemDO::getTotalPrice, BigDecimal::add))); + stockOutMapper.updateById(updateObj); + // 2.2 更新出库单项 + updateStockOutItemList(updateReqVO.getId(), stockOutItems); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStockOutStatus(Long id, Integer status) { + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + // 1.1 校验存在 + ErpStockOutDO stockOut = validateStockOutExists(id); + // 1.2 校验状态 + if (stockOut.getStatus().equals(status)) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 2. 更新状态 + int updateCount = stockOutMapper.updateByIdAndStatus(id, stockOut.getStatus(), + new ErpStockOutDO().setStatus(status)); + if (updateCount == 0) { + throw exception(approve ? STOCK_OUT_APPROVE_FAIL : STOCK_OUT_PROCESS_FAIL); + } + + // 3. 变更库存 + List stockOutItems = stockOutItemMapper.selectListByOutId(id); + Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_OUT.getType() + : ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType(); + stockOutItems.forEach(stockOutItem -> { + BigDecimal count = approve ? stockOutItem.getCount().negate() : stockOutItem.getCount(); + stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( + stockOutItem.getProductId(), stockOutItem.getWarehouseId(), count, + bizType, stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo())); + }); + } + + private List validateStockOutItems(List list) { + // 1.1 校验产品存在 + List productList = productService.validProductList( + convertSet(list, ErpStockOutSaveReqVO.Item::getProductId)); + Map productMap = convertMap(productList, ErpProductDO::getId); + // 1.2 校验仓库存在 + warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVO.Item::getWarehouseId)); + // 2. 转化为 ErpStockOutItemDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, ErpStockOutItemDO.class, item -> item + .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); + } + + private void updateStockOutItemList(Long id, List newList) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = stockOutItemMapper.selectListByOutId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setOutId(id)); + stockOutItemMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + stockOutItemMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + stockOutItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockOutItemDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStockOut(List ids) { + // 1. 校验不处于已审批 + List stockOuts = stockOutMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(stockOuts)) { + return; + } + stockOuts.forEach(stockOut -> { + if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { + throw exception(STOCK_OUT_DELETE_FAIL_APPROVE, stockOut.getNo()); + } + }); + + // 2. 遍历删除,并记录操作日志 + stockOuts.forEach(stockOut -> { + // 2.1 删除出库单 + stockOutMapper.deleteById(stockOut.getId()); + // 2.2 删除出库单项 + stockOutItemMapper.deleteByOutId(stockOut.getId()); + }); + } + + private ErpStockOutDO validateStockOutExists(Long id) { + ErpStockOutDO stockOut = stockOutMapper.selectById(id); + if (stockOut == null) { + throw exception(STOCK_OUT_NOT_EXISTS); + } + return stockOut; + } + + @Override + public ErpStockOutDO getStockOut(Long id) { + return stockOutMapper.selectById(id); + } + + @Override + public PageResult getStockOutPage(ErpStockOutPageReqVO pageReqVO) { + return stockOutMapper.selectPage(pageReqVO); + } + + // ==================== 出库项 ==================== + + @Override + public List getStockOutItemListByOutId(Long outId) { + return stockOutItemMapper.selectListByOutId(outId); + } + + @Override + public List getStockOutItemListByOutIds(Collection outIds) { + if (CollUtil.isEmpty(outIds)) { + return Collections.emptyList(); + } + return stockOutItemMapper.selectListByOutIds(outIds); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java new file mode 100644 index 0000000..aa9072e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordService.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; + +import javax.validation.Valid; + +/** + * ERP 产品库存明细 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockRecordService { + + /** + * 获得产品库存明细 + * + * @param id 编号 + * @return 产品库存明细 + */ + ErpStockRecordDO getStockRecord(Long id); + + /** + * 获得产品库存明细分页 + * + * @param pageReqVO 分页查询 + * @return 产品库存明细分页 + */ + PageResult getStockRecordPage(ErpStockRecordPageReqVO pageReqVO); + + /** + * 创建库存明细 + * + * @param createReqBO 创建库存明细 BO + */ + void createStockRecord(@Valid ErpStockRecordCreateReqBO createReqBO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java new file mode 100644 index 0000000..b4b3875 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper; +import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; + +/** + * ERP 产品库存明细 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockRecordServiceImpl implements ErpStockRecordService { + + @Resource + private ErpStockRecordMapper stockRecordMapper; + + @Resource + private ErpStockService stockService; + + @Override + public ErpStockRecordDO getStockRecord(Long id) { + return stockRecordMapper.selectById(id); + } + + @Override + public PageResult getStockRecordPage(ErpStockRecordPageReqVO pageReqVO) { + return stockRecordMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createStockRecord(ErpStockRecordCreateReqBO createReqBO) { + // 1. 更新库存 + BigDecimal totalCount = stockService.updateStockCountIncrement( + createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount()); + // 2. 创建库存明细 + ErpStockRecordDO stockRecord = BeanUtils.toBean(createReqBO, ErpStockRecordDO.class) + .setTotalCount(totalCount); + stockRecordMapper.insert(stockRecord); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java new file mode 100644 index 0000000..63ad5fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockService.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; + +import java.math.BigDecimal; + +/** + * ERP 产品库存 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpStockService { + + /** + * 获得产品库存 + * + * @param id 编号 + * @return 库存 + */ + ErpStockDO getStock(Long id); + + /** + * 基于产品 + 仓库,获得产品库存 + * + * @param productId 产品编号 + * @param warehouseId 仓库编号 + * @return 产品库存 + */ + ErpStockDO getStock(Long productId, Long warehouseId); + + /** + * 获得产品库存数量 + * + * 如果不存在库存记录,则返回 0 + * + * @param productId 产品编号 + * @return 产品库存数量 + */ + BigDecimal getStockCount(Long productId); + + /** + * 获得产品库存分页 + * + * @param pageReqVO 分页查询 + * @return 库存分页 + */ + PageResult getStockPage(ErpStockPageReqVO pageReqVO); + + /** + * 增量更新产品库存数量 + * + * @param productId 产品编号 + * @param warehouseId 仓库编号 + * @param count 增量数量:正数,表示增加;负数,表示减少 + * @return 更新后的库存 + */ + BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java new file mode 100644 index 0000000..dabe36f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2; + +/** + * ERP 产品库存 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpStockServiceImpl implements ErpStockService { + + /** + * 允许库存为负数 + * + * TODO 芋艿:后续做成 db 配置 + */ + private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false; + + @Resource + private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + + @Resource + private ErpStockMapper stockMapper; + + @Override + public ErpStockDO getStock(Long id) { + return stockMapper.selectById(id); + } + + @Override + public ErpStockDO getStock(Long productId, Long warehouseId) { + return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); + } + + @Override + public BigDecimal getStockCount(Long productId) { + BigDecimal count = stockMapper.selectSumByProductId(productId); + return count != null ? count : BigDecimal.ZERO; + } + + @Override + public PageResult getStockPage(ErpStockPageReqVO pageReqVO) { + return stockMapper.selectPage(pageReqVO); + } + + @Override + public BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count) { + // 1.1 查询当前库存 + ErpStockDO stock = stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); + if (stock == null) { + stock = new ErpStockDO().setProductId(productId).setWarehouseId(warehouseId).setCount(BigDecimal.ZERO); + stockMapper.insert(stock); + } + // 1.2 校验库存是否充足 + if (!NEGATIVE_STOCK_COUNT_ENABLE && stock.getCount().add(count).compareTo(BigDecimal.ZERO) < 0) { + throw exception(STOCK_COUNT_NEGATIVE, productService.getProduct(productId).getName(), + warehouseService.getWarehouse(warehouseId).getName(), stock.getCount(), count); + } + + // 2. 库存变更 + int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE); + if (updateCount == 0) { + // 此时不好去查询最新库存,所以直接抛出该提示,不提供具体库存数字 + throw exception(STOCK_COUNT_NEGATIVE2, productService.getProduct(productId).getName(), + warehouseService.getWarehouse(warehouseId).getName()); + } + + // 3. 返回最新库存 + return stock.getCount().add(count); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java new file mode 100644 index 0000000..2d6f96f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * ERP 仓库 Service 接口 + * + * @author 芋道源码 + */ +public interface ErpWarehouseService { + + /** + * 创建仓库 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWarehouse(@Valid ErpWarehouseSaveReqVO createReqVO); + + /** + * 更新ERP 仓库 + * + * @param updateReqVO 更新信息 + */ + void updateWarehouse(@Valid ErpWarehouseSaveReqVO updateReqVO); + + /** + * 更新仓库默认状态 + * + * @param id 编号 + * @param defaultStatus 默认状态 + */ + void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus); + + /** + * 删除仓库 + * + * @param id 编号 + */ + void deleteWarehouse(Long id); + + /** + * 获得仓库 + * + * @param id 编号 + * @return 仓库 + */ + ErpWarehouseDO getWarehouse(Long id); + + /** + * 校验仓库列表的有效性 + * + * @param ids 编号数组 + * @return 仓库列表 + */ + List validWarehouseList(Collection ids); + + /** + * 获得指定状态的仓库列表 + * + * @param status 状态 + * @return 仓库列表 + */ + List getWarehouseListByStatus(Integer status); + + /** + * 获得仓库列表 + * + * @param ids 编号数组 + * @return 仓库列表 + */ + List getWarehouseList(Collection ids); + + /** + * 获得仓库 Map + * + * @param ids 编号数组 + * @return 仓库 Map + */ + default Map getWarehouseMap(Collection ids) { + return convertMap(getWarehouseList(ids), ErpWarehouseDO::getId); + } + + /** + * 获得仓库分页 + * + * @param pageReqVO 分页查询 + * @return 仓库分页 + */ + PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java new file mode 100644 index 0000000..9e80128 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_ENABLE; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; + +/** + * ERP 仓库 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ErpWarehouseServiceImpl implements ErpWarehouseService { + + @Resource + private ErpWarehouseMapper warehouseMapper; + + @Override + public Long createWarehouse(ErpWarehouseSaveReqVO createReqVO) { + // 插入 + ErpWarehouseDO warehouse = BeanUtils.toBean(createReqVO, ErpWarehouseDO.class); + warehouseMapper.insert(warehouse); + // 返回 + return warehouse.getId(); + } + + @Override + public void updateWarehouse(ErpWarehouseSaveReqVO updateReqVO) { + // 校验存在 + validateWarehouseExists(updateReqVO.getId()); + // 更新 + ErpWarehouseDO updateObj = BeanUtils.toBean(updateReqVO, ErpWarehouseDO.class); + warehouseMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus) { + // 1. 校验存在 + validateWarehouseExists(id); + + // 2.1 如果开启,则需要关闭所有其它的默认 + if (defaultStatus) { + ErpWarehouseDO warehouse = warehouseMapper.selectByDefaultStatus(); + if (warehouse != null) { + warehouseMapper.updateById(new ErpWarehouseDO().setId(warehouse.getId()).setDefaultStatus(false)); + } + } + // 2.2 更新对应的默认状态 + warehouseMapper.updateById(new ErpWarehouseDO().setId(id).setDefaultStatus(defaultStatus)); + } + + @Override + public void deleteWarehouse(Long id) { + // 校验存在 + validateWarehouseExists(id); + // 删除 + warehouseMapper.deleteById(id); + } + + private void validateWarehouseExists(Long id) { + if (warehouseMapper.selectById(id) == null) { + throw exception(WAREHOUSE_NOT_EXISTS); + } + } + + @Override + public ErpWarehouseDO getWarehouse(Long id) { + return warehouseMapper.selectById(id); + } + + @Override + public List validWarehouseList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + List list = warehouseMapper.selectBatchIds(ids); + Map warehouseMap = convertMap(list, ErpWarehouseDO::getId); + for (Long id : ids) { + ErpWarehouseDO warehouse = warehouseMap.get(id); + if (warehouseMap.get(id) == null) { + throw exception(WAREHOUSE_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(warehouse.getStatus())) { + throw exception(WAREHOUSE_NOT_ENABLE, warehouse.getName()); + } + } + return list; + } + + @Override + public List getWarehouseListByStatus(Integer status) { + return warehouseMapper.selectListByStatus(status); + } + + @Override + public List getWarehouseList(Collection ids) { + return warehouseMapper.selectBatchIds(ids); + } + + @Override + public PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO) { + return warehouseMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java new file mode 100644 index 0000000..40c62a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.erp.service.stock.bo; + +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 库存明细的创建 Request BO + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockRecordCreateReqBO { + + /** + * 产品编号 + */ + @NotNull(message = "产品编号不能为空") + private Long productId; + /** + * 仓库编号 + */ + @NotNull(message = "仓库编号不能为空") + private Long warehouseId; + /** + * 出入库数量 + * + * 正数,表示入库;负数,表示出库 + */ + @NotNull(message = "出入库数量不能为空") + private BigDecimal count; + + /** + * 业务类型 + */ + @NotNull(message = "业务类型不能为空") + private Integer bizType; + /** + * 业务编号 + */ + @NotNull(message = "业务编号不能为空") + private Long bizId; + /** + * 业务项编号 + */ + @NotNull(message = "业务项编号不能为空") + private Long bizItemId; + /** + * 业务单号 + */ + @NotNull(message = "业务单号不能为空") + private String bizNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml new file mode 100644 index 0000000..e2b2599 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml new file mode 100644 index 0000000..8e74606 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/pom.xml b/ruoyi-vue-pro-master/yudao-module-infra/pom.xml new file mode 100644 index 0000000..c517e88 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/pom.xml @@ -0,0 +1,25 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + + yudao-module-infra-api + yudao-module-infra-biz + + yudao-module-infra + pom + + ${project.artifactId} + + infra 模块,主要提供两块能力: + 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/pom.xml new file mode 100644 index 0000000..168ea64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-infra + ${revision} + + 4.0.0 + yudao-module-infra-api + jar + + ${project.artifactId} + + infra 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java new file mode 100644 index 0000000..c41c6e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.api.file; + +/** + * 文件 API 接口 + * + * @author 芋道源码 + */ +public interface FileApi { + + /** + * 保存文件,并返回文件的访问路径 + * + * @param content 文件内容 + * @return 文件路径 + */ + default String createFile(byte[] content) { + return createFile(null, null, content); + } + + /** + * 保存文件,并返回文件的访问路径 + * + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + default String createFile(String path, byte[] content) { + return createFile(null, path, content); + } + + /** + * 保存文件,并返回文件的访问路径 + * + * @param name 文件名称 + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + String createFile(String name, String path, byte[] content); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApi.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApi.java new file mode 100644 index 0000000..ed3f3ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApi.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.infra.api.logger; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; + +import javax.validation.Valid; + +/** + * API 访问日志的 API 接口 + * + * @author 芋道源码 + */ +public interface ApiAccessLogApi { + + /** + * 创建 API 访问日志 + * + * @param createDTO 创建信息 + */ + void createApiAccessLog(@Valid ApiAccessLogCreateReqDTO createDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApi.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApi.java new file mode 100644 index 0000000..9b53c66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApi.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.infra.api.logger; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; + +import javax.validation.Valid; + +/** + * API 错误日志的 API 接口 + * + * @author 芋道源码 + */ +public interface ApiErrorLogApi { + + /** + * 创建 API 错误日志 + * + * @param createDTO 创建信息 + */ + void createApiErrorLog(@Valid ApiErrorLogCreateReqDTO createDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiAccessLogCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiAccessLogCreateReqDTO.java new file mode 100644 index 0000000..78b55ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiAccessLogCreateReqDTO.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.infra.api.logger.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + * API 访问日志 + * + * @author 芋道源码 + */ +@Data +public class ApiAccessLogCreateReqDTO { + + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 应用名 + */ + @NotNull(message = "应用名不能为空") + private String applicationName; + + /** + * 请求方法名 + */ + @NotNull(message = "http 请求方法不能为空") + private String requestMethod; + /** + * 访问地址 + */ + @NotNull(message = "访问地址不能为空") + private String requestUrl; + /** + * 请求参数 + */ + private String requestParams; + /** + * 响应结果 + */ + private String responseBody; + /** + * 用户 IP + */ + @NotNull(message = "ip 不能为空") + private String userIp; + /** + * 浏览器 UA + */ + @NotNull(message = "User-Agent 不能为空") + private String userAgent; + + /** + * 操作模块 + */ + private String operateModule; + /** + * 操作名 + */ + private String operateName; + /** + * 操作分类 + * + * 枚举,参见 OperateTypeEnum 类 + */ + private Integer operateType; + + /** + * 开始请求时间 + */ + @NotNull(message = "开始请求时间不能为空") + private LocalDateTime beginTime; + /** + * 结束请求时间 + */ + @NotNull(message = "结束请求时间不能为空") + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + @NotNull(message = "执行时长不能为空") + private Integer duration; + /** + * 结果码 + */ + @NotNull(message = "错误码不能为空") + private Integer resultCode; + /** + * 结果提示 + */ + private String resultMsg; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiErrorLogCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiErrorLogCreateReqDTO.java new file mode 100644 index 0000000..6b1cc8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/logger/dto/ApiErrorLogCreateReqDTO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.infra.api.logger.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + * API 错误日志 + * + * @author 芋道源码 + */ +@Data +public class ApiErrorLogCreateReqDTO { + + /** + * 链路编号 + */ + private String traceId; + /** + * 账号编号 + */ + private Long userId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 应用名 + */ + @NotNull(message = "应用名不能为空") + private String applicationName; + + /** + * 请求方法名 + */ + @NotNull(message = "http 请求方法不能为空") + private String requestMethod; + /** + * 访问地址 + */ + @NotNull(message = "访问地址不能为空") + private String requestUrl; + /** + * 请求参数 + */ + @NotNull(message = "请求参数不能为空") + private String requestParams; + /** + * 用户 IP + */ + @NotNull(message = "ip 不能为空") + private String userIp; + /** + * 浏览器 UA + */ + @NotNull(message = "User-Agent 不能为空") + private String userAgent; + + /** + * 异常时间 + */ + @NotNull(message = "异常时间不能为空") + private LocalDateTime exceptionTime; + /** + * 异常名 + */ + @NotNull(message = "异常名不能为空") + private String exceptionName; + /** + * 异常发生的类全名 + */ + @NotNull(message = "异常发生的类全名不能为空") + private String exceptionClassName; + /** + * 异常发生的类文件 + */ + @NotNull(message = "异常发生的类文件不能为空") + private String exceptionFileName; + /** + * 异常发生的方法名 + */ + @NotNull(message = "异常发生的方法名不能为空") + private String exceptionMethodName; + /** + * 异常发生的方法所在行 + */ + @NotNull(message = "异常发生的方法所在行不能为空") + private Integer exceptionLineNumber; + /** + * 异常的栈轨迹异常的栈轨迹 + */ + @NotNull(message = "异常的栈轨迹不能为空") + private String exceptionStackTrace; + /** + * 异常导致的根消息 + */ + @NotNull(message = "异常导致的根消息不能为空") + private String exceptionRootCauseMessage; + /** + * 异常导致的消息 + */ + @NotNull(message = "异常导致的消息不能为空") + private String exceptionMessage; + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java new file mode 100644 index 0000000..9ed9a77 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java @@ -0,0 +1,4 @@ +/** + * infra API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.infra.api; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApi.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApi.java new file mode 100644 index 0000000..38582c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApi.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.infra.api.websocket; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; + +/** + * WebSocket 发送器的 API 接口 + * + * 对 WebSocketMessageSender 进行封装,提供给其它模块使用 + * + * @author 芋道源码 + */ +public interface WebSocketSenderApi { + + /** + * 发送消息给指定用户 + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(Integer userType, Long userId, String messageType, String messageContent); + + /** + * 发送消息给指定用户类型 + * + * @param userType 用户类型 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(Integer userType, String messageType, String messageContent); + + /** + * 发送消息给指定 Session + * + * @param sessionId Session 编号 + * @param messageType 消息类型 + * @param messageContent 消息内容,JSON 格式 + */ + void send(String sessionId, String messageType, String messageContent); + + default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) { + send(userType, userId, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(Integer userType, String messageType, Object messageContent) { + send(userType, messageType, JsonUtils.toJsonString(messageContent)); + } + + default void sendObject(String sessionId, String messageType, Object messageContent) { + send(sessionId, messageType, JsonUtils.toJsonString(messageContent)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/DictTypeConstants.java new file mode 100644 index 0000000..36ad63d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/DictTypeConstants.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.infra.enums; + +/** + * Infra 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String JOB_STATUS = "infra_job_status"; // 定时任务状态的枚举 + String JOB_LOG_STATUS = "infra_job_log_status"; // 定时任务日志状态的枚举 + + String API_ERROR_LOG_PROCESS_STATUS = "infra_api_error_log_process_status"; // API 错误日志的处理状态的枚举 + + String CONFIG_TYPE = "infra_config_type"; // 参数配置类型 + String BOOLEAN_STRING = "infra_boolean_string"; // Boolean 是否类型 + + String OPERATE_TYPE = "infra_operate_type"; // 操作类型 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..e9f39a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Infra 错误码枚举类 + * + * infra 系统,使用 1-001-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 参数配置 1-001-000-000 ========== + ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1_001_000_001, "参数配置不存在"); + ErrorCode CONFIG_KEY_DUPLICATE = new ErrorCode(1_001_000_002, "参数配置 key 重复"); + ErrorCode CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE = new ErrorCode(1_001_000_003, "不能删除类型为系统内置的参数配置"); + ErrorCode CONFIG_GET_VALUE_ERROR_IF_VISIBLE = new ErrorCode(1_001_000_004, "获取参数配置失败,原因:不允许获取不可见配置"); + + // ========== 定时任务 1-001-001-000 ========== + ErrorCode JOB_NOT_EXISTS = new ErrorCode(1_001_001_000, "定时任务不存在"); + ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1_001_001_001, "定时任务的处理器已经存在"); + ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1_001_001_002, "只允许修改为开启或者关闭状态"); + ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改"); + ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改"); + ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确"); + ErrorCode JOB_HANDLER_BEAN_NOT_EXISTS = new ErrorCode(1_001_001_006, "定时任务的处理器 Bean 不存在"); + ErrorCode JOB_HANDLER_BEAN_TYPE_ERROR = new ErrorCode(1_001_001_007, "定时任务的处理器 Bean 类型不正确,未实现 JobHandler 接口"); + + // ========== API 错误日志 1-001-002-000 ========== + ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在"); + ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1_001_002_001, "API 错误日志已处理"); + + // ========= 文件相关 1-001-003-000 ================= + ErrorCode FILE_PATH_EXISTS = new ErrorCode(1_001_003_000, "文件路径已存在"); + ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "文件不存在"); + ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "文件为空"); + + // ========== 代码生成器 1-001-004-000 ========== + ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_001_004_002, "表定义已经存在"); + ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1_001_004_001, "导入的表不存在"); + ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1_001_004_002, "导入的字段不存在"); + ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_004, "表定义不存在"); + ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_005, "字段义不存在"); + ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1_001_004_006, "同步的字段不存在"); + ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_001_004_007, "同步失败,不存在改变"); + ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_001_004_008, "数据库的表注释未填写"); + ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_001_004_009, "数据库的表字段({})注释未填写"); + ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_010, "主表(id={})定义不存在,请检查"); + ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_011, "子表的字段(id={})不存在,请检查"); + ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_001_004_012, "主表生成代码失败,原因:它没有子表"); + + // ========== 文件配置 1-001-006-000 ========== + ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在"); + ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1_001_006_001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件"); + + // ========== 数据源配置 1-001-007-000 ========== + ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在"); + ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接"); + + // ========== 学生 1-001-201-000 ========== + ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在"); + ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在"); + ErrorCode DEMO02_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_001_201_002, "存在存在子示例分类,无法删除"); + ErrorCode DEMO02_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_001_201_003,"父级示例分类不存在"); + ErrorCode DEMO02_CATEGORY_PARENT_ERROR = new ErrorCode(1_001_201_004, "不能设置自己为父示例分类"); + ErrorCode DEMO02_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_001_201_005, "已经存在该名字的示例分类"); + ErrorCode DEMO02_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_001_201_006, "不能设置自己的子示例分类为父示例分类"); + ErrorCode DEMO03_STUDENT_NOT_EXISTS = new ErrorCode(1_001_201_007, "学生不存在"); + ErrorCode DEMO03_GRADE_NOT_EXISTS = new ErrorCode(1_001_201_008, "学生班级不存在"); + ErrorCode DEMO03_GRADE_EXISTS = new ErrorCode(1_001_201_009, "学生班级已存在"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml new file mode 100644 index 0000000..f2840cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/pom.xml @@ -0,0 +1,130 @@ + + + + cn.iocoder.boot + yudao-module-infra + ${revision} + + 4.0.0 + yudao-module-infra-biz + jar + + ${project.artifactId} + + infra 模块,主要提供两块能力: + 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-infra-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + cn.iocoder.boot + yudao-spring-boot-starter-websocket + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + com.baomidou + mybatis-plus-generator + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-job + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + org.apache.velocity + velocity-engine-core + + + + + cn.iocoder.boot + yudao-spring-boot-starter-monitor + + + + de.codecentric + spring-boot-admin-starter-server + + + + + commons-net + commons-net + + + com.jcraft + jsch + + + io.minio + minio + + + + org.apache.tika + tika-core + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java new file mode 100644 index 0000000..05fb946 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.api.file; + +import cn.iocoder.yudao.module.infra.service.file.FileService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 文件 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class FileApiImpl implements FileApi { + + @Resource + private FileService fileService; + + @Override + public String createFile(String name, String path, byte[] content) { + return fileService.createFile(name, path, content); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApiImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApiImpl.java new file mode 100644 index 0000000..2daa4a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiAccessLogApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.api.logger; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * API 访问日志的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ApiAccessLogApiImpl implements ApiAccessLogApi { + + @Resource + private ApiAccessLogService apiAccessLogService; + + @Override + public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { + apiAccessLogService.createApiAccessLog(createDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApiImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApiImpl.java new file mode 100644 index 0000000..cdb0ec2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/logger/ApiErrorLogApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.api.logger; + +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.service.logger.ApiErrorLogService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * API 访问日志的 API 接口 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ApiErrorLogApiImpl implements ApiErrorLogApi { + + @Resource + private ApiErrorLogService apiErrorLogService; + + @Override + public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { + apiErrorLogService.createApiErrorLog(createDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java new file mode 100644 index 0000000..af01680 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.infra.api; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApiImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApiImpl.java new file mode 100644 index 0000000..046cd2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/websocket/WebSocketSenderApiImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.api.websocket; + +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * WebSocket 发送器的 API 实现类 + * + * @author 芋道源码 + */ +@Component +public class WebSocketSenderApiImpl implements WebSocketSenderApi { + + @Resource + private WebSocketMessageSender webSocketMessageSender; + + @Override + public void send(Integer userType, Long userId, String messageType, String messageContent) { + webSocketMessageSender.send(userType, userId, messageType, messageContent); + } + + @Override + public void send(Integer userType, String messageType, String messageContent) { + webSocketMessageSender.send(userType, messageType, messageContent); + } + + @Override + public void send(String sessionId, String messageType, String messageContent) { + webSocketMessageSender.send(sessionId, messageType, messageContent); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java new file mode 100644 index 0000000..6889d03 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java @@ -0,0 +1,151 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ZipUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.service.codegen.CodegenService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; + +@Tag(name = "管理后台 - 代码生成器") +@RestController +@RequestMapping("/infra/codegen") +@Validated +public class CodegenController { + + @Resource + private CodegenService codegenService; + + @GetMapping("/db/table/list") + @Operation(summary = "获得数据库自带的表定义列表", description = "会过滤掉已经导入 Codegen 的表") + @Parameters({ + @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1"), + @Parameter(name = "name", description = "表名,模糊匹配", example = "yudao"), + @Parameter(name = "comment", description = "描述,模糊匹配", example = "芋道") + }) + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getDatabaseTableList( + @RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "comment", required = false) String comment) { + return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment)); + } + + @GetMapping("/table/list") + @Operation(summary = "获得表定义列表") + @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) { + List list = codegenService.getCodegenTableList(dataSourceConfigId); + return success(BeanUtils.toBean(list, CodegenTableRespVO.class)); + } + + @GetMapping("/table/page") + @Operation(summary = "获得表定义分页") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) { + PageResult pageResult = codegenService.getCodegenTablePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class)); + } + + @GetMapping("/detail") + @Operation(summary = "获得表和字段的明细") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:query')") + public CommonResult getCodegenDetail(@RequestParam("tableId") Long tableId) { + CodegenTableDO table = codegenService.getCodegenTable(tableId); + List columns = codegenService.getCodegenColumnListByTableId(tableId); + // 拼装返回 + return success(CodegenConvert.INSTANCE.convert(table, columns)); + } + + @Operation(summary = "基于数据库的表结构,创建代码生成器的表和字段定义") + @PostMapping("/create-list") + @PreAuthorize("@ss.hasPermission('infra:codegen:create')") + public CommonResult> createCodegenList(@Valid @RequestBody CodegenCreateListReqVO reqVO) { + return success(codegenService.createCodegenList(getLoginUserId(), reqVO)); + } + + @Operation(summary = "更新数据库的表和字段定义") + @PutMapping("/update") + @PreAuthorize("@ss.hasPermission('infra:codegen:update')") + public CommonResult updateCodegen(@Valid @RequestBody CodegenUpdateReqVO updateReqVO) { + codegenService.updateCodegen(updateReqVO); + return success(true); + } + + @Operation(summary = "基于数据库的表结构,同步数据库的表和字段定义") + @PutMapping("/sync-from-db") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:update')") + public CommonResult syncCodegenFromDB(@RequestParam("tableId") Long tableId) { + codegenService.syncCodegenFromDB(tableId); + return success(true); + } + + @Operation(summary = "删除数据库的表和字段定义") + @DeleteMapping("/delete") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:delete')") + public CommonResult deleteCodegen(@RequestParam("tableId") Long tableId) { + codegenService.deleteCodegen(tableId); + return success(true); + } + + @Operation(summary = "预览生成代码") + @GetMapping("/preview") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:preview')") + public CommonResult> previewCodegen(@RequestParam("tableId") Long tableId) { + Map codes = codegenService.generationCodes(tableId); + return success(CodegenConvert.INSTANCE.convert(codes)); + } + + @Operation(summary = "下载生成代码") + @GetMapping("/download") + @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:codegen:download')") + public void downloadCodegen(@RequestParam("tableId") Long tableId, + HttpServletResponse response) throws IOException { + // 生成代码 + Map codes = codegenService.generationCodes(tableId); + // 构建 zip 包 + String[] paths = codes.keySet().toArray(new String[0]); + ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipUtil.zip(outputStream, paths, ins); + // 输出 + writeAttachment(response, "codegen.zip", outputStream.toByteArray()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java new file mode 100644 index 0000000..efce9ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenCreateListReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO") +@Data +public class CodegenCreateListReqVO { + + @Schema(description = "数据源配置的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据源配置的编号不能为空") + private Long dataSourceConfigId; + + @Schema(description = "表名数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]") + @NotNull(message = "表名数组不能为空") + private List tableNames; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java new file mode 100644 index 0000000..f7d8a62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenDetailRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; + +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 代码生成表和字段的明细 Response VO") +@Data +public class CodegenDetailRespVO { + + @Schema(description = "表定义") + private CodegenTableRespVO table; + + @Schema(description = "字段定义") + private List columns; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java new file mode 100644 index 0000000..ffd924a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 代码生成预览 Response VO,注意,每个文件都是一个该对象") +@Data +public class CodegenPreviewRespVO { + + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "java/cn/iocoder/yudao/adminserver/modules/system/controller/test/SysTestDemoController.java") + private String filePath; + + @Schema(description = "代码", requiredMode = Schema.RequiredMode.REQUIRED, example = "Hello World") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java new file mode 100644 index 0000000..78db9fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; + +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 代码生成表和字段的修改 Request VO") +@Data +public class CodegenUpdateReqVO { + + @Valid // 校验内嵌的字段 + @NotNull(message = "表定义不能为空") + private CodegenTableSaveReqVO table; + + @Valid // 校验内嵌的字段 + @NotNull(message = "字段定义不能为空") + private List columns; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java new file mode 100644 index 0000000..29a8c74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 代码生成字段定义 Response VO") +@Data +public class CodegenColumnRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long tableId; + + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age") + private String columnName; + + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)") + private String dataType; + + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄") + private String columnComment; + + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean nullable; + + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean primaryKey; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer ordinalPosition; + + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge") + private String javaType; + + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer") + private String javaField; + + @Schema(description = "字典类型", example = "sys_gender") + private String dictType; + + @Schema(description = "数据示例", example = "1024") + private String example; + + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean createOperation; + + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean updateOperation; + + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean listOperation; + + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE") + private String listOperationCondition; + + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean listOperationResult; + + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input") + private String htmlType; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java new file mode 100644 index 0000000..a236174 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO") +@Data +public class CodegenColumnSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表编号不能为空") + private Long tableId; + + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age") + @NotNull(message = "字段名不能为空") + private String columnName; + + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)") + @NotNull(message = "字段类型不能为空") + private String dataType; + + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄") + @NotNull(message = "字段描述不能为空") + private String columnComment; + + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否允许为空不能为空") + private Boolean nullable; + + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "是否主键不能为空") + private Boolean primaryKey; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "排序不能为空") + private Integer ordinalPosition; + + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge") + @NotNull(message = "Java 属性类型不能为空") + private String javaType; + + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer") + @NotNull(message = "Java 属性名不能为空") + private String javaField; + + @Schema(description = "字典类型", example = "sys_gender") + private String dictType; + + @Schema(description = "数据示例", example = "1024") + private String example; + + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 Create 创建操作的字段不能为空") + private Boolean createOperation; + + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "是否为 Update 更新操作的字段不能为空") + private Boolean updateOperation; + + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 List 查询操作的字段不能为空") + private Boolean listOperation; + + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE") + @NotNull(message = "List 查询操作的条件类型不能为空") + private String listOperationCondition; + + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否为 List 查询操作的返回字段不能为空") + private Boolean listOperationResult; + + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input") + @NotNull(message = "显示类型不能为空") + private String htmlType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java new file mode 100644 index 0000000..032a9d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 表定义分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CodegenTablePageReqVO extends PageParam { + + @Schema(description = "表名称,模糊匹配", example = "yudao") + private String tableName; + + @Schema(description = "表描述,模糊匹配", example = "芋道") + private String tableComment; + + @Schema(description = "实体,模糊匹配", example = "Yudao") + private String className; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java new file mode 100644 index 0000000..8b438b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 代码生成表定义 Response VO") +@Data +public class CodegenTableRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer scene; + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String tableName; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String tableComment; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system") + private String moduleName; + + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen") + private String businessName; + + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable") + private String className; + + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义") + private String classComment; + + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String author; + + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer templateType; + + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer frontType; + + @Schema(description = "父菜单编号", example = "1024") + private Long parentMenuId; + + @Schema(description = "主表的编号", example = "2048") + private Long masterTableId; + @Schema(description = "子表关联主表的字段编号", example = "4096") + private Long subJoinColumnId; + @Schema(description = "主表与子表是否一对多", example = "4096") + private Boolean subJoinMany; + + @Schema(description = "树表的父字段编号", example = "8192") + private Long treeParentColumnId; + @Schema(description = "树表的名字字段编号", example = "16384") + private Long treeNameColumnId; + + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer dataSourceConfigId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java new file mode 100644 index 0000000..19c75b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO") +@Data +public class CodegenTableSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "导入类型不能为空") + private Integer scene; + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "表名称不能为空") + private String tableName; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表描述不能为空") + private String tableComment; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system") + @NotNull(message = "模块名不能为空") + private String moduleName; + + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen") + @NotNull(message = "业务名不能为空") + private String businessName; + + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable") + @NotNull(message = "类名称不能为空") + private String className; + + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义") + @NotNull(message = "类描述不能为空") + private String classComment; + + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "作者不能为空") + private String author; + + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "模板类型不能为空") + private Integer templateType; + + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @NotNull(message = "前端类型不能为空") + private Integer frontType; + + @Schema(description = "父菜单编号", example = "1024") + private Long parentMenuId; + + @Schema(description = "主表的编号", example = "2048") + private Long masterTableId; + @Schema(description = "子表关联主表的字段编号", example = "4096") + private Long subJoinColumnId; + @Schema(description = "主表与子表是否一对多", example = "4096") + private Boolean subJoinMany; + + @Schema(description = "树表的父字段编号", example = "8192") + private Long treeParentColumnId; + @Schema(description = "树表的名字字段编号", example = "16384") + private Long treeNameColumnId; + + @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段") + @JsonIgnore + public boolean isParentMenuIdValid() { + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的 + return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene()) + || getParentMenuId() != null; + } + + @AssertTrue(message = "关联的父表信息不全") + @JsonIgnore + public boolean isSubValid() { + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB) + || (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany)); + } + + @AssertTrue(message = "关联的树表信息不全") + @JsonIgnore + public boolean isTreeValid() { + return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE) + || (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java new file mode 100644 index 0000000..a1f683c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/DatabaseTableRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 数据库的表定义 Response VO") +@Data +public class DatabaseTableRespVO { + + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yuanma") + private String name; + + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String comment; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java new file mode 100644 index 0000000..6c8da46 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.infra.controller.admin.config; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.*; +import cn.iocoder.yudao.module.infra.convert.config.ConfigConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; +import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.infra.service.config.ConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 参数配置") +@RestController +@RequestMapping("/infra/config") +@Validated +public class ConfigController { + + @Resource + private ConfigService configService; + + @PostMapping("/create") + @Operation(summary = "创建参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:create')") + public CommonResult createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) { + return success(configService.createConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:update')") + public CommonResult updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) { + configService.updateConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除参数配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:config:delete')") + public CommonResult deleteConfig(@RequestParam("id") Long id) { + configService.deleteConfig(id); + return success(true); + } + + @GetMapping(value = "/get") + @Operation(summary = "获得参数配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:config:query')") + public CommonResult getConfig(@RequestParam("id") Long id) { + return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id))); + } + + @GetMapping(value = "/get-value-by-key") + @Operation(summary = "根据参数键名查询参数值", description = "不可见的配置,不允许返回给前端") + @Parameter(name = "key", description = "参数键", required = true, example = "yunai.biz.username") + public CommonResult getConfigKey(@RequestParam("key") String key) { + ConfigDO config = configService.getConfigByKey(key); + if (config == null) { + return success(null); + } + if (!config.getVisible()) { + throw exception(ErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_VISIBLE); + } + return success(config.getValue()); + } + + @GetMapping("/page") + @Operation(summary = "获取参数配置分页") + @PreAuthorize("@ss.hasPermission('infra:config:query')") + public CommonResult> getConfigPage(@Valid ConfigPageReqVO pageReqVO) { + PageResult page = configService.getConfigPage(pageReqVO); + return success(ConfigConvert.INSTANCE.convertPage(page)); + } + + @GetMapping("/export") + @Operation(summary = "导出参数配置") + @PreAuthorize("@ss.hasPermission('infra:config:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportConfig(@Valid ConfigPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = configService.getConfigPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "参数配置.xls", "数据", ConfigRespVO.class, + ConfigConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java new file mode 100644 index 0000000..8caec39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.infra.controller.admin.config.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 参数配置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ConfigPageReqVO extends PageParam { + + @Schema(description = "数据源名称,模糊匹配", example = "名称") + private String name; + + @Schema(description = "参数键名,模糊匹配", example = "yunai.db.username") + private String key; + + @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1") + private Integer type; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java new file mode 100644 index 0000000..b4f642f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.infra.controller.admin.config.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 参数配置信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ConfigRespVO { + + @Schema(description = "参数配置序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("参数配置序号") + private Long id; + + @Schema(description = "参数分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz") + @ExcelProperty("参数分类") + private String category; + + @Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名") + @ExcelProperty("参数名称") + private String name; + + @Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username") + @ExcelProperty("参数键名") + private String key; + + @Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("参数键值") + private String value; + + @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "参数类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CONFIG_TYPE) + private Integer type; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否可见", converter = DictConvert.class) + @DictFormat(DictTypeConstants.BOOLEAN_STRING) + private Boolean visible; + + @Schema(description = "备注", example = "备注一下很帅气!") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigSaveReqVO.java new file mode 100644 index 0000000..59aaa48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigSaveReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.infra.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 参数配置创建/修改 Request VO") +@Data +public class ConfigSaveReqVO { + + @Schema(description = "参数配置序号", example = "1024") + private Long id; + + @Schema(description = "参数分组", requiredMode = Schema.RequiredMode.REQUIRED, example = "biz") + @NotEmpty(message = "参数分组不能为空") + @Size(max = 50, message = "参数名称不能超过 50 个字符") + private String category; + + @Schema(description = "参数名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "数据库名") + @NotBlank(message = "参数名称不能为空") + @Size(max = 100, message = "参数名称不能超过 100 个字符") + private String name; + + @Schema(description = "参数键名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yunai.db.username") + @NotBlank(message = "参数键名长度不能为空") + @Size(max = 100, message = "参数键名长度不能超过 100 个字符") + private String key; + + @Schema(description = "参数键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotBlank(message = "参数键值不能为空") + @Size(max = 500, message = "参数键值长度不能超过 500 个字符") + private String value; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否可见不能为空") + private Boolean visible; + + @Schema(description = "备注", example = "备注一下很帅气!") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java new file mode 100644 index 0000000..85a1227 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DataSourceConfigController.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 数据源配置") +@RestController +@RequestMapping("/infra/data-source-config") +@Validated +public class DataSourceConfigController { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @PostMapping("/create") + @Operation(summary = "创建数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:create')") + public CommonResult createDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO createReqVO) { + return success(dataSourceConfigService.createDataSourceConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新数据源配置") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:update')") + public CommonResult updateDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO updateReqVO) { + dataSourceConfigService.updateDataSourceConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除数据源配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')") + public CommonResult deleteDataSourceConfig(@RequestParam("id") Long id) { + dataSourceConfigService.deleteDataSourceConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得数据源配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult getDataSourceConfig(@RequestParam("id") Long id) { + DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(id); + return success(BeanUtils.toBean(config, DataSourceConfigRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得数据源配置列表") + @PreAuthorize("@ss.hasPermission('infra:data-source-config:query')") + public CommonResult> getDataSourceConfigList() { + List list = dataSourceConfigService.getDataSourceConfigList(); + return success(BeanUtils.toBean(list, DataSourceConfigRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java new file mode 100644 index 0000000..f979528 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 数据源配置 Response VO") +@Data +public class DataSourceConfigRespVO { + + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer id; + + @Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + private String name; + + @Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") + private String url; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root") + private String username; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java new file mode 100644 index 0000000..54d231f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/vo/DataSourceConfigSaveReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.controller.admin.db.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 数据源配置创建/修改 Request VO") +@Data +public class DataSourceConfigSaveReqVO { + + @Schema(description = "主键编号", example = "1024") + private Long id; + + @Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @NotNull(message = "数据源名称不能为空") + private String name; + + @Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro") + @NotNull(message = "数据源连接不能为空") + private String url; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root") + @NotNull(message = "用户名不能为空") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "密码不能为空") + private String password; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java new file mode 100644 index 0000000..0492ee5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import cn.iocoder.yudao.module.infra.service.demo.demo01.Demo01ContactService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 示例联系人") +@RestController +@RequestMapping("/infra/demo01-contact") +@Validated +public class Demo01ContactController { + + @Resource + private Demo01ContactService demo01ContactService; + + @PostMapping("/create") + @Operation(summary = "创建示例联系人") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:create')") + public CommonResult createDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO createReqVO) { + return success(demo01ContactService.createDemo01Contact(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新示例联系人") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:update')") + public CommonResult updateDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO updateReqVO) { + demo01ContactService.updateDemo01Contact(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除示例联系人") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:delete')") + public CommonResult deleteDemo01Contact(@RequestParam("id") Long id) { + demo01ContactService.deleteDemo01Contact(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得示例联系人") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')") + public CommonResult getDemo01Contact(@RequestParam("id") Long id) { + Demo01ContactDO demo01Contact = demo01ContactService.getDemo01Contact(id); + return success(BeanUtils.toBean(demo01Contact, Demo01ContactRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得示例联系人分页") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')") + public CommonResult> getDemo01ContactPage(@Valid Demo01ContactPageReqVO pageReqVO) { + PageResult pageResult = demo01ContactService.getDemo01ContactPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, Demo01ContactRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出示例联系人 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo01ContactExcel(@Valid Demo01ContactPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = demo01ContactService.getDemo01ContactPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "示例联系人.xls", "数据", Demo01ContactRespVO.class, + BeanUtils.toBean(list, Demo01ContactRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java new file mode 100644 index 0000000..d337d2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 示例联系人分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Demo01ContactPageReqVO extends PageParam { + + @Schema(description = "名字", example = "张三") + private String name; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java new file mode 100644 index 0000000..5d176c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 示例联系人 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo01ContactRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @ExcelProperty("名字") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生年") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") + @ExcelProperty("简介") + private String description; + + @Schema(description = "头像") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java new file mode 100644 index 0000000..94157ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 示例联系人新增/修改 Request VO") +@Data +public class Demo01ContactSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生年不能为空") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "头像") + private String avatar; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java new file mode 100644 index 0000000..7cc35b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import cn.iocoder.yudao.module.infra.service.demo.demo02.Demo02CategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 示例分类") +@RestController +@RequestMapping("/infra/demo02-category") +@Validated +public class Demo02CategoryController { + + @Resource + private Demo02CategoryService demo02CategoryService; + + @PostMapping("/create") + @Operation(summary = "创建示例分类") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:create')") + public CommonResult createDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO createReqVO) { + return success(demo02CategoryService.createDemo02Category(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新示例分类") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:update')") + public CommonResult updateDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO updateReqVO) { + demo02CategoryService.updateDemo02Category(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除示例分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo02-category:delete')") + public CommonResult deleteDemo02Category(@RequestParam("id") Long id) { + demo02CategoryService.deleteDemo02Category(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得示例分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')") + public CommonResult getDemo02Category(@RequestParam("id") Long id) { + Demo02CategoryDO demo02Category = demo02CategoryService.getDemo02Category(id); + return success(BeanUtils.toBean(demo02Category, Demo02CategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得示例分类列表") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')") + public CommonResult> getDemo02CategoryList(@Valid Demo02CategoryListReqVO listReqVO) { + List list = demo02CategoryService.getDemo02CategoryList(listReqVO); + return success(BeanUtils.toBean(list, Demo02CategoryRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出示例分类 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo02-category:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo02CategoryExcel(@Valid Demo02CategoryListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = demo02CategoryService.getDemo02CategoryList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "示例分类.xls", "数据", Demo02CategoryRespVO.class, + BeanUtils.toBean(list, Demo02CategoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java new file mode 100644 index 0000000..69fcfd9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 示例分类列表 Request VO") +@Data +public class Demo02CategoryListReqVO { + + @Schema(description = "名字", example = "芋艿") + private String name; + + @Schema(description = "父级编号", example = "6080") + private Long parentId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java new file mode 100644 index 0000000..1f2efd4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 示例分类 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo02CategoryRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("名字") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080") + @ExcelProperty("父级编号") + private Long parentId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java new file mode 100644 index 0000000..3cc5012 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 示例分类新增/修改 Request VO") +@Data +public class Demo02CategorySaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080") + @NotNull(message = "父级编号不能为空") + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java new file mode 100644 index 0000000..1a7375f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java @@ -0,0 +1,197 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import cn.iocoder.yudao.module.infra.service.demo.demo03.Demo03StudentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/demo03-student") +@Validated +public class Demo03StudentController { + + @Resource + private Demo03StudentService demo03StudentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO createReqVO) { + return success(demo03StudentService.createDemo03Student(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO updateReqVO) { + demo03StudentService.updateDemo03Student(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Student(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Student(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Student(@RequestParam("id") Long id) { + Demo03StudentDO demo03Student = demo03StudentService.getDemo03Student(id); + return success(BeanUtils.toBean(demo03Student, Demo03StudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03StudentPage(@Valid Demo03StudentPageReqVO pageReqVO) { + PageResult pageResult = demo03StudentService.getDemo03StudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, Demo03StudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDemo03StudentExcel(@Valid Demo03StudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = demo03StudentService.getDemo03StudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", Demo03StudentRespVO.class, + BeanUtils.toBean(list, Demo03StudentRespVO.class)); + } + + // ==================== 子表(学生课程) ==================== + + @GetMapping("/demo03-course/page") + @Operation(summary = "获得学生课程分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03CoursePage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03CoursePage(pageReqVO, studentId)); + } + + @PostMapping("/demo03-course/create") + @Operation(summary = "创建学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) { + return success(demo03StudentService.createDemo03Course(demo03Course)); + } + + @PutMapping("/demo03-course/update") + @Operation(summary = "更新学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) { + demo03StudentService.updateDemo03Course(demo03Course); + return success(true); + } + + @DeleteMapping("/demo03-course/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生课程") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Course(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Course(id); + return success(true); + } + + @GetMapping("/demo03-course/get") + @Operation(summary = "获得学生课程") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Course(@RequestParam("id") Long id) { + return success(demo03StudentService.getDemo03Course(id)); + } + + @GetMapping("/demo03-course/list-by-student-id") + @Operation(summary = "获得学生课程列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03CourseListByStudentId(@RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03CourseListByStudentId(studentId)); + } + + // ==================== 子表(学生班级) ==================== + + @GetMapping("/demo03-grade/page") + @Operation(summary = "获得学生班级分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult> getDemo03GradePage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03GradePage(pageReqVO, studentId)); + } + + @PostMapping("/demo03-grade/create") + @Operation(summary = "创建学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')") + public CommonResult createDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) { + return success(demo03StudentService.createDemo03Grade(demo03Grade)); + } + + @PutMapping("/demo03-grade/update") + @Operation(summary = "更新学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')") + public CommonResult updateDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) { + demo03StudentService.updateDemo03Grade(demo03Grade); + return success(true); + } + + @DeleteMapping("/demo03-grade/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生班级") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')") + public CommonResult deleteDemo03Grade(@RequestParam("id") Long id) { + demo03StudentService.deleteDemo03Grade(id); + return success(true); + } + + @GetMapping("/demo03-grade/get") + @Operation(summary = "获得学生班级") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03Grade(@RequestParam("id") Long id) { + return success(demo03StudentService.getDemo03Grade(id)); + } + + @GetMapping("/demo03-grade/get-by-student-id") + @Operation(summary = "获得学生班级") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')") + public CommonResult getDemo03GradeByStudentId(@RequestParam("studentId") Long studentId) { + return success(demo03StudentService.getDemo03GradeByStudentId(studentId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/package-info.java new file mode 100644 index 0000000..79682e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java new file mode 100644 index 0000000..6834991 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Demo03StudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋艿") + private String name; + + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "简介", example = "随便") + private String description; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java new file mode 100644 index 0000000..5ae784f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class Demo03StudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("名字") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便") + @ExcelProperty("简介") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java new file mode 100644 index 0000000..d3393a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class Demo03StudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便") + @NotEmpty(message = "简介不能为空") + private String description; + + + private List demo03Courses; + + private Demo03GradeDO demo03Grade; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/package-info.java new file mode 100644 index 0000000..c448646 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/package-info.java @@ -0,0 +1,8 @@ +/** + * 代码生成示例 + * + * 1. demo01:单表(增删改查) + * 2. demo02:单表(树形结构) + * 3. demo03:主子表(标准模式)+ 主子表(ERP 模式)+ 主子表(内嵌模式) + */ +package cn.iocoder.yudao.module.infra.controller.admin.demo; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.http b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.http new file mode 100644 index 0000000..499f64d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.http @@ -0,0 +1,45 @@ +### 请求 /infra/file-config/create 接口 => 成功 +POST {{baseUrl}}/infra/file-config/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "name": "S3 - 七牛云", + "remark": "", + "storage": 20, + "config": { + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", + "bucket": "ruoyi-vue-pro", + "endpoint": "s3-cn-south-1.qiniucs.com", + "domain": "http://test.yudao.iocoder.cn", + "region": "oss-cn-beijing" + } +} + +### 请求 /infra/file-config/update 接口 => 成功 +PUT {{baseUrl}}/infra/file-config/update +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 2, + "name": "S3 - 七牛云", + "remark": "", + "config": { + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", + "bucket": "ruoyi-vue-pro", + "endpoint": "s3-cn-south-1.qiniucs.com", + "domain": "http://test.yudao.iocoder.cn", + "region": "oss-cn-beijing" + } +} + +### 请求 /infra/file-config/test 接口 => 成功 +GET {{baseUrl}}/infra/file-config/test?id=2 +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.java new file mode 100644 index 0000000..eb51f08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; +import cn.iocoder.yudao.module.infra.service.file.FileConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 文件配置") +@RestController +@RequestMapping("/infra/file-config") +@Validated +public class FileConfigController { + + @Resource + private FileConfigService fileConfigService; + + @PostMapping("/create") + @Operation(summary = "创建文件配置") + @PreAuthorize("@ss.hasPermission('infra:file-config:create')") + public CommonResult createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) { + return success(fileConfigService.createFileConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新文件配置") + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") + public CommonResult updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) { + fileConfigService.updateFileConfig(updateReqVO); + return success(true); + } + + @PutMapping("/update-master") + @Operation(summary = "更新文件配置为 Master") + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") + public CommonResult updateFileConfigMaster(@RequestParam("id") Long id) { + fileConfigService.updateFileConfigMaster(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文件配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:file-config:delete')") + public CommonResult deleteFileConfig(@RequestParam("id") Long id) { + fileConfigService.deleteFileConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得文件配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult getFileConfig(@RequestParam("id") Long id) { + FileConfigDO config = fileConfigService.getFileConfig(id); + return success(BeanUtils.toBean(config, FileConfigRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得文件配置分页") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) { + PageResult pageResult = fileConfigService.getFileConfigPage(pageVO); + return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class)); + } + + @GetMapping("/test") + @Operation(summary = "测试文件配置是否正确") + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") + public CommonResult testFileConfig(@RequestParam("id") Long id) throws Exception { + String url = fileConfigService.testFileConfig(id); + return success(url); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java new file mode 100644 index 0000000..8b2ce4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; +import cn.iocoder.yudao.module.infra.service.file.FileService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; + +@Tag(name = "管理后台 - 文件存储") +@RestController +@RequestMapping("/infra/file") +@Validated +@Slf4j +public class FileController { + + @Resource + private FileService fileService; + + @PostMapping("/upload") + @Operation(summary = "上传文件", description = "模式一:后端上传文件") + public CommonResult uploadFile(FileUploadReqVO uploadReqVO) throws Exception { + MultipartFile file = uploadReqVO.getFile(); + String path = uploadReqVO.getPath(); + return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); + } + + @GetMapping("/presigned-url") + @Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器") + public CommonResult getFilePresignedUrl(@RequestParam("path") String path) throws Exception { + return success(fileService.getFilePresignedUrl(path)); + } + + @PostMapping("/create") + @Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件") + public CommonResult createFile(@Valid @RequestBody FileCreateReqVO createReqVO) { + return success(fileService.createFile(createReqVO)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文件") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:file:delete')") + public CommonResult deleteFile(@RequestParam("id") Long id) throws Exception { + fileService.deleteFile(id); + return success(true); + } + + @GetMapping("/{configId}/get/**") + @PermitAll + @Operation(summary = "下载文件") + @Parameter(name = "configId", description = "配置编号", required = true) + public void getFileContent(HttpServletRequest request, + HttpServletResponse response, + @PathVariable("configId") Long configId) throws Exception { + // 获取请求的路径 + String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false); + if (StrUtil.isEmpty(path)) { + throw new IllegalArgumentException("结尾的 path 路径必须传递"); + } + // 解码,解决中文路径的问题 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/ + path = URLUtil.decode(path); + + // 读取内容 + byte[] content = fileService.getFileContent(configId, path); + if (content == null) { + log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path); + response.setStatus(HttpStatus.NOT_FOUND.value()); + return; + } + writeAttachment(response, path, content); + } + + @GetMapping("/page") + @Operation(summary = "获得文件分页") + @PreAuthorize("@ss.hasPermission('infra:file:query')") + public CommonResult> getFilePage(@Valid FilePageReqVO pageVO) { + PageResult pageResult = fileService.getFilePage(pageVO); + return success(BeanUtils.toBean(pageResult, FileRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java new file mode 100644 index 0000000..481fa2a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文件配置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class FileConfigPageReqVO extends PageParam { + + @Schema(description = "配置名", example = "S3 - 阿里云") + private String name; + + @Schema(description = "存储器", example = "1") + private Integer storage; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java new file mode 100644 index 0000000..e344f82 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文件配置 Response VO") +@Data +public class FileConfigRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云") + private String name; + + @Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer storage; + + @Schema(description = "是否为主配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean master; + + @Schema(description = "存储配置", requiredMode = Schema.RequiredMode.REQUIRED) + private FileClientConfig config; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java new file mode 100644 index 0000000..b346ee6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigSaveReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 文件配置创建/修改 Request VO") +@Data +public class FileConfigSaveReqVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云") + @NotNull(message = "配置名不能为空") + private String name; + + @Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "存储器不能为空") + private Integer storage; + + @Schema(description = "存储配置,配置是动态参数,所以使用 Map 接收", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "存储配置不能为空") + private Map config; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java new file mode 100644 index 0000000..2497618 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 文件创建 Request VO") +@Data +public class FileCreateReqVO { + + @NotNull(message = "文件配置编号不能为空") + @Schema(description = "文件配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @NotNull(message = "文件路径不能为空") + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String path; + + @NotNull(message = "原文件名不能为空") + @Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String name; + + @NotNull(message = "文件 URL不能为空") + @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String url; + + @Schema(description = "文件 MIME 类型", example = "application/octet-stream") + private String type; + + @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer size; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java new file mode 100644 index 0000000..21c1178 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文件分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class FilePageReqVO extends PageParam { + + @Schema(description = "文件路径,模糊匹配", example = "yudao") + private String path; + + @Schema(description = "文件类型,模糊匹配", example = "jpg") + private String type; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java new file mode 100644 index 0000000..926133e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePresignedUrlRespVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "管理后台 - 文件预签名地址 Response VO") +@Data +public class FilePresignedUrlRespVO { + + @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @Schema(description = "文件上传 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://s3.cn-south-1.qiniucs.com/ruoyi-vue-pro/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS%2F20240217%2Fcn-south-1%2Fs3%2Faws4_request&X-Amz-Date=20240217T123222Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=a29f33770ab79bf523ccd4034d0752ac545f3c2a3b17baa1eb4e280cfdccfda5") + private String uploadUrl; + + /** + * 为什么要返回 url 字段? + * + * 前端上传完文件后,需要使用该 URL 进行访问 + */ + @Schema(description = "文件访问 URL", requiredMode = Schema.RequiredMode.REQUIRED, + example = "https://test.yudao.iocoder.cn/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png") + private String url; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java new file mode 100644 index 0000000..a0357da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文件 Response VO,不返回 content 字段,太大") +@Data +public class FileRespVO { + + @Schema(description = "文件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11") + private Long configId; + + @Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String path; + + @Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg") + private String name; + + @Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String url; + + @Schema(description = "文件MIME类型", example = "application/octet-stream") + private String type; + + @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer size; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java new file mode 100644 index 0000000..b60b9a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 上传文件 Request VO") +@Data +public class FileUploadReqVO { + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件附件不能为空") + private MultipartFile file; + + @Schema(description = "文件附件", example = "yudaoyuanma.png") + private String path; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.http b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.http new file mode 100644 index 0000000..62f8dd6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.http @@ -0,0 +1,5 @@ +### 请求 /infra/job/sync 接口 => 成功 +POST {{baseUrl}}/infra/job/sync +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java new file mode 100644 index 0000000..9b01ce7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.quartz.core.util.CronUtils; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; +import cn.iocoder.yudao.module.infra.service.job.JobService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.quartz.SchedulerException; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 定时任务") +@RestController +@RequestMapping("/infra/job") +@Validated +public class JobController { + + @Resource + private JobService jobService; + + @PostMapping("/create") + @Operation(summary = "创建定时任务") + @PreAuthorize("@ss.hasPermission('infra:job:create')") + public CommonResult createJob(@Valid @RequestBody JobSaveReqVO createReqVO) + throws SchedulerException { + return success(jobService.createJob(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新定时任务") + @PreAuthorize("@ss.hasPermission('infra:job:update')") + public CommonResult updateJob(@Valid @RequestBody JobSaveReqVO updateReqVO) + throws SchedulerException { + jobService.updateJob(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新定时任务的状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true, example = "1024"), + @Parameter(name = "status", description = "状态", required = true, example = "1"), + }) + @PreAuthorize("@ss.hasPermission('infra:job:update')") + public CommonResult updateJobStatus(@RequestParam(value = "id") Long id, @RequestParam("status") Integer status) + throws SchedulerException { + jobService.updateJobStatus(id, status); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除定时任务") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:job:delete')") + public CommonResult deleteJob(@RequestParam("id") Long id) + throws SchedulerException { + jobService.deleteJob(id); + return success(true); + } + + @PutMapping("/trigger") + @Operation(summary = "触发定时任务") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:job:trigger')") + public CommonResult triggerJob(@RequestParam("id") Long id) throws SchedulerException { + jobService.triggerJob(id); + return success(true); + } + + @PostMapping("/sync") + @Operation(summary = "同步定时任务") + @PreAuthorize("@ss.hasPermission('infra:job:create')") + public CommonResult syncJob() throws SchedulerException { + jobService.syncJob(); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得定时任务") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult getJob(@RequestParam("id") Long id) { + JobDO job = jobService.getJob(id); + return success(BeanUtils.toBean(job, JobRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得定时任务分页") + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult> getJobPage(@Valid JobPageReqVO pageVO) { + PageResult pageResult = jobService.getJobPage(pageVO); + return success(BeanUtils.toBean(pageResult, JobRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出定时任务 Excel") + @PreAuthorize("@ss.hasPermission('infra:job:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportJobExcel(@Valid JobPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = jobService.getJobPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "定时任务.xls", "数据", JobRespVO.class, + BeanUtils.toBean(list, JobRespVO.class)); + } + + @GetMapping("/get_next_times") + @Operation(summary = "获得定时任务的下 n 次执行时间") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true, example = "1024"), + @Parameter(name = "count", description = "数量", example = "5") + }) + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult> getJobNextTimes( + @RequestParam("id") Long id, + @RequestParam(value = "count", required = false, defaultValue = "5") Integer count) { + JobDO job = jobService.getJob(id); + if (job == null) { + return success(Collections.emptyList()); + } + return success(CronUtils.getNextTimes(job.getCronExpression(), count)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java new file mode 100644 index 0000000..afe513a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO; +import cn.iocoder.yudao.module.infra.service.job.JobLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 定时任务日志") +@RestController +@RequestMapping("/infra/job-log") +@Validated +public class JobLogController { + + @Resource + private JobLogService jobLogService; + + @GetMapping("/get") + @Operation(summary = "获得定时任务日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult getJobLog(@RequestParam("id") Long id) { + JobLogDO jobLog = jobLogService.getJobLog(id); + return success(BeanUtils.toBean(jobLog, JobLogRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得定时任务日志分页") + @PreAuthorize("@ss.hasPermission('infra:job:query')") + public CommonResult> getJobLogPage(@Valid JobLogPageReqVO pageVO) { + PageResult pageResult = jobLogService.getJobLogPage(pageVO); + return success(BeanUtils.toBean(pageResult, JobLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出定时任务日志 Excel") + @PreAuthorize("@ss.hasPermission('infra:job:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportJobLogExcel(@Valid JobLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = jobLogService.getJobLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "任务日志.xls", "数据", JobLogRespVO.class, + BeanUtils.toBean(list, JobLogRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobPageReqVO.java new file mode 100644 index 0000000..3328335 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job.vo.job; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 定时任务分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class JobPageReqVO extends PageParam { + + @Schema(description = "任务名称,模糊匹配", example = "测试任务") + private String name; + + @Schema(description = "任务状态,参见 JobStatusEnum 枚举", example = "1") + private Integer status; + + @Schema(description = "处理器的名字,模糊匹配", example = "sysUserSessionTimeoutJob") + private String handlerName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobRespVO.java new file mode 100644 index 0000000..25683f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobRespVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job.vo.job; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 定时任务 Response VO") +@Data +@ExcelIgnoreUnannotated +public class JobRespVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("任务编号") + private Long id; + + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试任务") + @ExcelProperty("任务名称") + private String name; + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "任务状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.JOB_STATUS) + private Integer status; + + @Schema(description = "处理器的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "sysUserSessionTimeoutJob") + @ExcelProperty("处理器的名字") + private String handlerName; + + @Schema(description = "处理器的参数", example = "yudao") + @ExcelProperty("处理器的参数") + private String handlerParam; + + @Schema(description = "CRON 表达式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0/10 * * * * ? *") + @ExcelProperty("CRON 表达式") + private String cronExpression; + + @Schema(description = "重试次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + @NotNull(message = "重试次数不能为空") + private Integer retryCount; + + @Schema(description = "重试间隔", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer retryInterval; + + @Schema(description = "监控超时时间", example = "1000") + @ExcelProperty("监控超时时间") + private Integer monitorTimeout; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobSaveReqVO.java new file mode 100644 index 0000000..0fb986e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobSaveReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job.vo.job; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 定时任务创建/修改 Request VO") +@Data +public class JobSaveReqVO { + + @Schema(description = "任务编号", example = "1024") + private Long id; + + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试任务") + @NotEmpty(message = "任务名称不能为空") + private String name; + + @Schema(description = "处理器的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "sysUserSessionTimeoutJob") + @NotEmpty(message = "处理器的名字不能为空") + private String handlerName; + + @Schema(description = "处理器的参数", example = "yudao") + private String handlerParam; + + @Schema(description = "CRON 表达式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0/10 * * * * ? *") + @NotEmpty(message = "CRON 表达式不能为空") + private String cronExpression; + + @Schema(description = "重试次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + @NotNull(message = "重试次数不能为空") + private Integer retryCount; + + @Schema(description = "重试间隔", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "重试间隔不能为空") + private Integer retryInterval; + + @Schema(description = "监控超时时间", example = "1000") + private Integer monitorTimeout; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogPageReqVO.java new file mode 100644 index 0000000..1d3d496 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogPageReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job.vo.log; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 定时任务日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class JobLogPageReqVO extends PageParam { + + @Schema(description = "任务编号", example = "10") + private Long jobId; + + @Schema(description = "处理器的名字,模糊匹配") + private String handlerName; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "开始执行时间") + private LocalDateTime beginTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "结束执行时间") + private LocalDateTime endTime; + + @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java new file mode 100644 index 0000000..543339d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.infra.controller.admin.job.vo.log; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 定时任务日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class JobLogRespVO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志编号") + private Long id; + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("任务编号") + private Long jobId; + + @Schema(description = "处理器的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "sysUserSessionTimeoutJob") + @ExcelProperty("处理器的名字") + private String handlerName; + + @Schema(description = "处理器的参数", example = "yudao") + @ExcelProperty("处理器的参数") + private String handlerParam; + + @Schema(description = "第几次执行", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("第几次执行") + private Integer executeIndex; + + @Schema(description = "开始执行时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("开始执行时间") + private LocalDateTime beginTime; + + @Schema(description = "结束执行时间") + @ExcelProperty("结束执行时间") + private LocalDateTime endTime; + + @Schema(description = "执行时长", example = "123") + @ExcelProperty("执行时长") + private Integer duration; + + @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "任务状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.JOB_STATUS) + private Integer status; + + @Schema(description = "结果数据", example = "执行成功") + @ExcelProperty("结果数据") + private String result; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java new file mode 100644 index 0000000..81b0ee9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; +import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - API 访问日志") +@RestController +@RequestMapping("/infra/api-access-log") +@Validated +public class ApiAccessLogController { + + @Resource + private ApiAccessLogService apiAccessLogService; + + @GetMapping("/page") + @Operation(summary = "获得API 访问日志分页") + @PreAuthorize("@ss.hasPermission('infra:api-access-log:query')") + public CommonResult> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) { + PageResult pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出API 访问日志 Excel") + @PreAuthorize("@ss.hasPermission('infra:api-access-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = apiAccessLogService.getApiAccessLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "API 访问日志.xls", "数据", ApiAccessLogRespVO.class, + BeanUtils.toBean(list, ApiAccessLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java new file mode 100644 index 0000000..726215a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; +import cn.iocoder.yudao.module.infra.service.logger.ApiErrorLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - API 错误日志") +@RestController +@RequestMapping("/infra/api-error-log") +@Validated +public class ApiErrorLogController { + + @Resource + private ApiErrorLogService apiErrorLogService; + + @PutMapping("/update-status") + @Operation(summary = "更新 API 错误日志的状态") + @Parameters({ + @Parameter(name = "id", description = "编号", required = true, example = "1024"), + @Parameter(name = "processStatus", description = "处理状态", required = true, example = "1") + }) + @PreAuthorize("@ss.hasPermission('infra:api-error-log:update-status')") + public CommonResult updateApiErrorLogProcess(@RequestParam("id") Long id, + @RequestParam("processStatus") Integer processStatus) { + apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId()); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得 API 错误日志分页") + @PreAuthorize("@ss.hasPermission('infra:api-error-log:query')") + public CommonResult> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) { + PageResult pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出 API 错误日志 Excel") + @PreAuthorize("@ss.hasPermission('infra:api-error-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = apiErrorLogService.getApiErrorLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "API 错误日志.xls", "数据", ApiErrorLogRespVO.class, + BeanUtils.toBean(list, ApiErrorLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java new file mode 100644 index 0000000..c17c111 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - API 访问日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ApiAccessLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型", example = "2") + private Integer userType; + + @Schema(description = "应用名", example = "dashboard") + private String applicationName; + + @Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy") + private String requestUrl; + + @Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] beginTime; + + @Schema(description = "执行时长,大于等于,单位:毫秒", example = "100") + private Integer duration; + + @Schema(description = "结果码", example = "0") + private Integer resultCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java new file mode 100644 index 0000000..e991450 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogRespVO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - API 访问日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ApiAccessLogRespVO { + + @Schema(description = "日志主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志主键") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002") + @ExcelProperty("链路追踪编号") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") + @ExcelProperty("应用名") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @ExcelProperty("请求方法名") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + @ExcelProperty("请求地址") + private String requestUrl; + + @Schema(description = "请求参数") + @ExcelProperty("请求参数") + private String requestParams; + + @Schema(description = "响应结果") + @ExcelProperty("响应结果") + private String responseBody; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("用户 IP") + private String userIp; + + @Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "操作模块", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品模块") + @ExcelProperty("操作模块") + private String operateModule; + + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建商品") + @ExcelProperty("操作名") + private String operateName; + + @Schema(description = "操作分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "操作分类", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.infra.enums.DictTypeConstants.OPERATE_TYPE) + private Integer operateType; + + @Schema(description = "开始请求时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("开始请求时间") + private LocalDateTime beginTime; + + @Schema(description = "结束请求时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("结束请求时间") + private LocalDateTime endTime; + + @Schema(description = "执行时长", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @ExcelProperty("执行时长") + private Integer duration; + + @Schema(description = "结果码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("结果码") + private Integer resultCode; + + @Schema(description = "结果提示", example = "芋道源码,牛逼!") + @ExcelProperty("结果提示") + private String resultMsg; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java new file mode 100644 index 0000000..2ceb0d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - API 错误日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ApiErrorLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型", example = "1") + private Integer userType; + + @Schema(description = "应用名", example = "dashboard") + private String applicationName; + + @Schema(description = "请求地址", example = "/xx/yy") + private String requestUrl; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "异常发生时间") + private LocalDateTime[] exceptionTime; + + @Schema(description = "处理状态", example = "0") + private Integer processStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java new file mode 100644 index 0000000..53f52f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogRespVO.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - API 错误日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ApiErrorLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Integer id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "66600cb6-7852-11eb-9439-0242ac130002") + @ExcelProperty("链路追踪编号") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @ExcelProperty("用户编号") + private Integer userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") + @ExcelProperty("应用名") + private String applicationName; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @ExcelProperty("请求方法名") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xx/yy") + @ExcelProperty("请求地址") + private String requestUrl; + + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("请求参数") + private String requestParams; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("用户 IP") + private String userIp; + + @Schema(description = "浏览器 UA", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "异常发生时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生时间") + private LocalDateTime exceptionTime; + + @Schema(description = "异常名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常名") + private String exceptionName; + + @Schema(description = "异常导致的消息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常导致的消息") + private String exceptionMessage; + + @Schema(description = "异常导致的根消息", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常导致的根消息") + private String exceptionRootCauseMessage; + + @Schema(description = "异常的栈轨迹", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常的栈轨迹") + private String exceptionStackTrace; + + @Schema(description = "异常发生的类全名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的类全名") + private String exceptionClassName; + + @Schema(description = "异常发生的类文件", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的类文件") + private String exceptionFileName; + + @Schema(description = "异常发生的方法名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的方法名") + private String exceptionMethodName; + + @Schema(description = "异常发生的方法所在行", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("异常发生的方法所在行") + private Integer exceptionLineNumber; + + @Schema(description = "处理状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty(value = "处理状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.API_ERROR_LOG_PROCESS_STATUS) + private Integer processStatus; + + @Schema(description = "处理时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("处理时间") + private LocalDateTime processTime; + + @Schema(description = "处理用户编号", example = "233") + @ExcelProperty("处理用户编号") + private Integer processUserId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http new file mode 100644 index 0000000..8a0e70f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http @@ -0,0 +1,4 @@ +### 请求 /infra/redis/get-monitor-info 接口 => 成功 +GET {{baseUrl}}/infra/redis/get-monitor-info +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java new file mode 100644 index 0000000..57a3d6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.infra.controller.admin.redis; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Properties; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - Redis 监控") +@RestController +@RequestMapping("/infra/redis") +public class RedisController { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @GetMapping("/get-monitor-info") + @Operation(summary = "获得 Redis 监控信息") + @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") + public CommonResult getRedisMonitorInfo() { + // 获得 Redis 统计信息 + Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); + Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); + Properties commandStats = stringRedisTemplate.execute(( + RedisCallback) connection -> connection.info("commandstats")); + assert commandStats != null; // 断言,避免警告 + // 拼接结果返回 + return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisMonitorRespVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisMonitorRespVO.java new file mode 100644 index 0000000..cc0aa27 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisMonitorRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.infra.controller.admin.redis.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Properties; + +@Schema(description = "管理后台 - Redis 监控信息 Response VO") +@Data +@Builder +@AllArgsConstructor +public class RedisMonitorRespVO { + + @Schema(description = "Redis info 指令结果,具体字段,查看 Redis 文档", requiredMode = Schema.RequiredMode.REQUIRED) + private Properties info; + + @Schema(description = "Redis key 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long dbSize; + + @Schema(description = "CommandStat 数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List commandStats; + + @Schema(description = "Redis 命令统计结果") + @Data + @Builder + @AllArgsConstructor + public static class CommandStat { + + @Schema(description = "Redis 命令", requiredMode = Schema.RequiredMode.REQUIRED, example = "get") + private String command; + + @Schema(description = "调用次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long calls; + + @Schema(description = "消耗 CPU 秒数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long usec; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java new file mode 100644 index 0000000..62755fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.infra.controller.app.file; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO; +import cn.iocoder.yudao.module.infra.service.file.FileService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +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 org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 文件存储") +@RestController +@RequestMapping("/infra/file") +@Validated +@Slf4j +public class AppFileController { + + @Resource + private FileService fileService; + + @PostMapping("/upload") + @Operation(summary = "上传文件") + public CommonResult uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception { + MultipartFile file = uploadReqVO.getFile(); + String path = uploadReqVO.getPath(); + return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream()))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java new file mode 100644 index 0000000..04666c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.infra.controller.app.file.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 上传文件 Request VO") +@Data +public class AppFileUploadReqVO { + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件附件不能为空") + private MultipartFile file; + + @Schema(description = "文件附件", example = "yudaoyuanma.png") + private String path; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/package-info.java new file mode 100644 index 0000000..d0f921f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.infra.controller.app; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/package-info.java new file mode 100644 index 0000000..04fde2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.infra.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java new file mode 100644 index 0000000..6b97613 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.infra.convert.codegen; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import org.apache.ibatis.type.JdbcType; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface CodegenConvert { + + CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class); + + // ========== TableInfo 相关 ========== + + @Mappings({ + @Mapping(source = "name", target = "tableName"), + @Mapping(source = "comment", target = "tableComment"), + }) + CodegenTableDO convert(TableInfo bean); + + List convertList(List list); + + @Mappings({ + @Mapping(source = "name", target = "columnName"), + @Mapping(source = "metaInfo.jdbcType", target = "dataType", qualifiedByName = "getDataType"), + @Mapping(source = "comment", target = "columnComment"), + @Mapping(source = "metaInfo.nullable", target = "nullable"), + @Mapping(source = "keyFlag", target = "primaryKey"), + @Mapping(source = "columnType.type", target = "javaType"), + @Mapping(source = "propertyName", target = "javaField"), + }) + CodegenColumnDO convert(TableField bean); + + @Named("getDataType") + default String getDataType(JdbcType jdbcType) { + return jdbcType.name(); + } + + // ========== 其它 ========== + + default CodegenDetailRespVO convert(CodegenTableDO table, List columns) { + CodegenDetailRespVO respVO = new CodegenDetailRespVO(); + respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class)); + respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class)); + return respVO; + } + + default List convert(Map codes) { + return CollectionUtils.convertList(codes.entrySet(), + entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java new file mode 100644 index 0000000..92094b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/config/ConfigConvert.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.convert.config; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface ConfigConvert { + + ConfigConvert INSTANCE = Mappers.getMapper(ConfigConvert.class); + + PageResult convertPage(PageResult page); + + List convertList(List list); + + @Mapping(source = "configKey", target = "key") + ConfigRespVO convert(ConfigDO bean); + + @Mapping(source = "key", target = "configKey") + ConfigDO convert(ConfigSaveReqVO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/file/FileConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/file/FileConfigConvert.java new file mode 100644 index 0000000..7df2b57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/file/FileConfigConvert.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.infra.convert.file; + +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * 文件配置 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface FileConfigConvert { + + FileConfigConvert INSTANCE = Mappers.getMapper(FileConfigConvert.class); + + @Mapping(target = "config", ignore = true) + FileConfigDO convert(FileConfigSaveReqVO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/package-info.java new file mode 100644 index 0000000..8e27593 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.infra.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java new file mode 100644 index 0000000..0c8ca98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.infra.convert.redis; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.Properties; + +@Mapper +public interface RedisConvert { + + RedisConvert INSTANCE = Mappers.getMapper(RedisConvert.class); + + default RedisMonitorRespVO build(Properties info, Long dbSize, Properties commandStats) { + RedisMonitorRespVO respVO = RedisMonitorRespVO.builder().info(info).dbSize(dbSize) + .commandStats(new ArrayList<>(commandStats.size())).build(); + commandStats.forEach((key, value) -> { + respVO.getCommandStats().add(RedisMonitorRespVO.CommandStat.builder() + .command(StrUtil.subAfter((String) key, "cmdstat_", false)) + .calls(Long.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) + .usec(Long.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) + .build()); + }); + return respVO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java new file mode 100644 index 0000000..f90a364 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.codegen; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 代码生成 column 字段定义 + * + * @author 芋道源码 + */ +@TableName(value = "infra_codegen_column", autoResultMap = true) +@KeySequence("infra_codegen_column_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class CodegenColumnDO extends BaseDO { + + /** + * ID 编号 + */ + @TableId + private Long id; + /** + * 表编号 + *

+ * 关联 {@link CodegenTableDO#getId()} + */ + private Long tableId; + + // ========== 表相关字段 ========== + + /** + * 字段名 + * + * 关联 {@link TableField#getName()} + */ + private String columnName; + /** + * 数据库字段类型 + * + * 关联 {@link TableField.MetaInfo#getJdbcType()} + */ + private String dataType; + /** + * 字段描述 + * + * 关联 {@link TableField#getComment()} + */ + private String columnComment; + /** + * 是否允许为空 + * + * 关联 {@link TableField.MetaInfo#isNullable()} + */ + private Boolean nullable; + /** + * 是否主键 + * + * 关联 {@link TableField#isKeyFlag()} + */ + private Boolean primaryKey; + /** + * 排序 + */ + private Integer ordinalPosition; + + // ========== Java 相关字段 ========== + + /** + * Java 属性类型 + * + * 例如说 String、Boolean 等等 + * + * 关联 {@link TableField#getColumnType()} + */ + private String javaType; + /** + * Java 属性名 + * + * 关联 {@link TableField#getPropertyName()} + */ + private String javaField; + /** + * 字典类型 + *

+ * 关联 DictTypeDO 的 type 属性 + */ + private String dictType; + /** + * 数据示例,主要用于生成 Swagger 注解的 example 字段 + */ + private String example; + + // ========== CRUD 相关字段 ========== + + /** + * 是否为 Create 创建操作的字段 + */ + private Boolean createOperation; + /** + * 是否为 Update 更新操作的字段 + */ + private Boolean updateOperation; + /** + * 是否为 List 查询操作的字段 + */ + private Boolean listOperation; + /** + * List 查询操作的条件类型 + *

+ * 枚举 {@link CodegenColumnListConditionEnum} + */ + private String listOperationCondition; + /** + * 是否为 List 查询操作的返回字段 + */ + private Boolean listOperationResult; + + // ========== UI 相关字段 ========== + + /** + * 显示类型 + *

+ * 枚举 {@link CodegenColumnHtmlTypeEnum} + */ + private String htmlType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java new file mode 100644 index 0000000..faee817 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.codegen; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 代码生成 table 表定义 + * + * @author 芋道源码 + */ +@TableName(value = "infra_codegen_table", autoResultMap = true) +@KeySequence("infra_codegen_table_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class CodegenTableDO extends BaseDO { + + /** + * ID 编号 + */ + @TableId + private Long id; + + /** + * 数据源编号 + * + * 关联 {@link DataSourceConfigDO#getId()} + */ + private Long dataSourceConfigId; + /** + * 生成场景 + * + * 枚举 {@link CodegenSceneEnum} + */ + private Integer scene; + + // ========== 表相关字段 ========== + + /** + * 表名称 + * + * 关联 {@link TableInfo#getName()} + */ + private String tableName; + /** + * 表描述 + * + * 关联 {@link TableInfo#getComment()} + */ + private String tableComment; + /** + * 备注 + */ + private String remark; + + // ========== 类相关字段 ========== + + /** + * 模块名,即一级目录 + * + * 例如说,system、infra、tool 等等 + */ + private String moduleName; + /** + * 业务名,即二级目录 + * + * 例如说,user、permission、dict 等等 + */ + private String businessName; + /** + * 类名称(首字母大写) + * + * 例如说,SysUser、SysMenu、SysDictData 等等 + */ + private String className; + /** + * 类描述 + */ + private String classComment; + /** + * 作者 + */ + private String author; + + // ========== 生成相关字段 ========== + + /** + * 模板类型 + * + * 枚举 {@link CodegenTemplateTypeEnum} + */ + private Integer templateType; + /** + * 代码生成的前端类型 + * + * 枚举 {@link CodegenFrontTypeEnum} + */ + private Integer frontType; + + // ========== 菜单相关字段 ========== + + /** + * 父菜单编号 + * + * 关联 MenuDO 的 id 属性 + */ + private Long parentMenuId; + + // ========== 主子表相关字段 ========== + + /** + * 主表的编号 + * + * 关联 {@link CodegenTableDO#getId()} + */ + private Long masterTableId; + /** + * 【自己】子表关联主表的字段编号 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long subJoinColumnId; + /** + * 主表与子表是否一对多 + * + * true:一对多 + * false:一对一 + */ + private Boolean subJoinMany; + + // ========== 树表相关字段 ========== + + /** + * 树表的父字段编号 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long treeParentColumnId; + /** + * 树表的名字字段编号 + * + * 名字的用途:新增或修改时,select 框展示的字段 + * + * 关联 {@link CodegenColumnDO#getId()} + */ + private Long treeNameColumnId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java new file mode 100644 index 0000000..03b6770 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/config/ConfigDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.config; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 参数配置表 + * + * @author 芋道源码 + */ +@TableName("infra_config") +@KeySequence("infra_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ConfigDO extends BaseDO { + + /** + * 参数主键 + */ + @TableId + private Long id; + /** + * 参数分类 + */ + private String category; + /** + * 参数名称 + */ + private String name; + /** + * 参数键名 + * + * 支持多 DB 类型时,无法直接使用 key + @TableField("config_key") 来实现转换,原因是 "config_key" AS key 而存在报错 + */ + private String configKey; + /** + * 参数键值 + */ + private String value; + /** + * 参数类型 + * + * 枚举 {@link ConfigTypeEnum} + */ + private Integer type; + /** + * 是否可见 + * + * 不可见的参数,一般是敏感参数,前端不可获取 + */ + private Boolean visible; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java new file mode 100644 index 0000000..138babe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.db; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 数据源配置 + * + * @author 芋道源码 + */ +@TableName(value = "infra_data_source_config", autoResultMap = true) +@KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DataSourceConfigDO extends BaseDO { + + /** + * 主键编号 - Master 数据源 + */ + public static final Long ID_MASTER = 0L; + + /** + * 主键编号 + */ + private Long id; + /** + * 连接名 + */ + private String name; + + /** + * 数据源连接 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + @TableField(typeHandler = EncryptTypeHandler.class) + private String password; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java new file mode 100644 index 0000000..de9c6d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 示例联系人 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo01_contact") +@KeySequence("yudao_demo01_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo01ContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 出生年 + */ + private LocalDateTime birthday; + /** + * 简介 + */ + private String description; + /** + * 头像 + */ + private String avatar; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java new file mode 100644 index 0000000..55005dc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 示例分类 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo02_category") +@KeySequence("yudao_demo02_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo02CategoryDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 父级编号 + */ + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java new file mode 100644 index 0000000..6f7f3f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 学生课程 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_course") +@KeySequence("yudao_demo03_course_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03CourseDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 分数 + */ + private Integer score; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java new file mode 100644 index 0000000..afb7090 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 学生班级 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_grade") +@KeySequence("yudao_demo03_grade_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03GradeDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 班主任 + */ + private String teacher; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java new file mode 100644 index 0000000..99995c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("yudao_demo03_student") +@KeySequence("yudao_demo03_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Demo03StudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 简介 + */ + private String description; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileConfigDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileConfigDO.java new file mode 100644 index 0000000..5d2d75c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileConfigDO.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.file; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.*; + +/** + * 文件配置表 + * + * @author 芋道源码 + */ +@TableName(value = "infra_file_config", autoResultMap = true) +@KeySequence("infra_file_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileConfigDO extends BaseDO { + + /** + * 配置编号,数据库自增 + */ + private Long id; + /** + * 配置名 + */ + private String name; + /** + * 存储器 + * + * 枚举 {@link FileStorageEnum} + */ + private Integer storage; + /** + * 备注 + */ + private String remark; + /** + * 是否为主配置 + * + * 由于我们可以配置多个文件配置,默认情况下,使用主配置进行文件的上传 + */ + private Boolean master; + + /** + * 支付渠道配置 + */ + @TableField(typeHandler = FileClientConfigTypeHandler.class) + private FileClientConfig config; + + public static class FileClientConfigTypeHandler extends AbstractJsonTypeHandler { + + @Override + protected Object parse(String json) { + FileClientConfig config = JsonUtils.parseObjectQuietly(json, new TypeReference() {}); + if (config != null) { + return config; + } + + // 兼容老版本的包路径 + String className = JsonUtils.parseObject(json, "@class", String.class); + className = StrUtil.subAfter(className, ".", true); + switch (className) { + case "DBFileClientConfig": + return JsonUtils.parseObject2(json, DBFileClientConfig.class); + case "FtpFileClientConfig": + return JsonUtils.parseObject2(json, FtpFileClientConfig.class); + case "LocalFileClientConfig": + return JsonUtils.parseObject2(json, LocalFileClientConfig.class); + case "SftpFileClientConfig": + return JsonUtils.parseObject2(json, SftpFileClientConfig.class); + case "S3FileClientConfig": + return JsonUtils.parseObject2(json, S3FileClientConfig.class); + default: + throw new IllegalArgumentException("未知的 FileClientConfig 类型:" + json); + } + } + + @Override + protected String toJson(Object obj) { + return JsonUtils.toJsonString(obj); + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileContentDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileContentDO.java new file mode 100644 index 0000000..80e18fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileContentDO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.file; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClient; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文件内容表 + * + * 专门用于存储 {@link DBFileClient} 的文件内容 + * + * @author 芋道源码 + */ +@TableName("infra_file_content") +@KeySequence("infra_file_content_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileContentDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + @TableId + private Long id; + /** + * 配置编号 + * + * 关联 {@link FileConfigDO#getId()} + */ + private Long configId; + /** + * 路径,即文件名 + */ + private String path; + /** + * 文件内容 + */ + private byte[] content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java new file mode 100644 index 0000000..c0fb007 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.file; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文件表 + * 每次文件上传,都会记录一条记录到该表中 + * + * @author 芋道源码 + */ +@TableName("infra_file") +@KeySequence("infra_file_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FileDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + private Long id; + /** + * 配置编号 + * + * 关联 {@link FileConfigDO#getId()} + */ + private Long configId; + /** + * 原文件名 + */ + private String name; + /** + * 路径,即文件名 + */ + private String path; + /** + * 访问地址 + */ + private String url; + /** + * 文件的 MIME 类型,例如 "application/octet-stream" + */ + private String type; + /** + * 文件大小 + */ + private Integer size; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobDO.java new file mode 100644 index 0000000..18b245a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobDO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.job; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 定时任务 DO + * + * @author 芋道源码 + */ +@TableName("infra_job") +@KeySequence("infra_job_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class JobDO extends BaseDO { + + /** + * 任务编号 + */ + @TableId + private Long id; + /** + * 任务名称 + */ + private String name; + /** + * 任务状态 + * + * 枚举 {@link JobStatusEnum} + */ + private Integer status; + /** + * 处理器的名字 + */ + private String handlerName; + /** + * 处理器的参数 + */ + private String handlerParam; + /** + * CRON 表达式 + */ + private String cronExpression; + + // ========== 重试相关字段 ========== + /** + * 重试次数 + * 如果不重试,则设置为 0 + */ + private Integer retryCount; + /** + * 重试间隔,单位:毫秒 + * 如果没有间隔,则设置为 0 + */ + private Integer retryInterval; + + // ========== 监控相关字段 ========== + /** + * 监控超时时间,单位:毫秒 + * 为空时,表示不监控 + * + * 注意,这里的超时的目的,不是进行任务的取消,而是告警任务的执行时间过长 + */ + private Integer monitorTimeout; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobLogDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobLogDO.java new file mode 100644 index 0000000..2d4cbaf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/job/JobLogDO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.job; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.module.infra.enums.job.JobLogStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 定时任务的执行日志 + * + * @author 芋道源码 + */ +@TableName("infra_job_log") +@KeySequence("infra_job_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class JobLogDO extends BaseDO { + + /** + * 日志编号 + */ + private Long id; + /** + * 任务编号 + * + * 关联 {@link JobDO#getId()} + */ + private Long jobId; + /** + * 处理器的名字 + * + * 冗余字段 {@link JobDO#getHandlerName()} + */ + private String handlerName; + /** + * 处理器的参数 + * + * 冗余字段 {@link JobDO#getHandlerParam()} + */ + private String handlerParam; + /** + * 第几次执行 + * + * 用于区分是不是重试执行。如果是重试执行,则 index 大于 1 + */ + private Integer executeIndex; + + /** + * 开始执行时间 + */ + private LocalDateTime beginTime; + /** + * 结束执行时间 + */ + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + /** + * 状态 + * + * 枚举 {@link JobLogStatusEnum} + */ + private Integer status; + /** + * 结果数据 + * + * 成功时,使用 {@link JobHandler#execute(String)} 的结果 + * 失败时,使用 {@link JobHandler#execute(String)} 的异常堆栈 + */ + private String result; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiAccessLogDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiAccessLogDO.java new file mode 100644 index 0000000..4f671c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiAccessLogDO.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.logger; + +import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * API 访问日志 + * + * @author 芋道源码 + */ +@TableName("infra_api_access_log") +@KeySequence(value = "infra_api_access_log_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ApiAccessLogDO extends BaseDO { + + /** + * {@link #requestParams} 的最大长度 + */ + public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000; + + /** + * {@link #resultMsg} 的最大长度 + */ + public static final Integer RESULT_MSG_MAX_LENGTH = 512; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 应用名 + * + * 目前读取 `spring.application.name` 配置项 + */ + private String applicationName; + + // ========== 请求相关字段 ========== + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 请求参数 + * + * query: Query String + * body: Quest Body + */ + private String requestParams; + /** + * 响应结果 + */ + private String responseBody; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + + // ========== 执行相关字段 ========== + + /** + * 操作模块 + */ + private String operateModule; + /** + * 操作名 + */ + private String operateName; + /** + * 操作分类 + * + * 枚举 {@link OperateTypeEnum} + */ + private Integer operateType; + + /** + * 开始请求时间 + */ + private LocalDateTime beginTime; + /** + * 结束请求时间 + */ + private LocalDateTime endTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + + /** + * 结果码 + * + * 目前使用的 {@link CommonResult#getCode()} 属性 + */ + private Integer resultCode; + /** + * 结果提示 + * + * 目前使用的 {@link CommonResult#getMsg()} 属性 + */ + private String resultMsg; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java new file mode 100644 index 0000000..87d6974 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/logger/ApiErrorLogDO.java @@ -0,0 +1,161 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.logger; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * API 异常数据 + * + * @author 芋道源码 + */ +@TableName("infra_api_error_log") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@KeySequence(value = "infra_api_error_log_seq") +public class ApiErrorLogDO extends BaseDO { + + /** + * {@link #requestParams} 的最大长度 + */ + public static final Integer REQUEST_PARAMS_MAX_LENGTH = 8000; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 应用名 + * + * 目前读取 spring.application.name + */ + private String applicationName; + + // ========== 请求相关字段 ========== + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 访问地址 + */ + private String requestUrl; + /** + * 请求参数 + * + * query: Query String + * body: Quest Body + */ + private String requestParams; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + + // ========== 异常相关字段 ========== + + /** + * 异常发生时间 + */ + private LocalDateTime exceptionTime; + /** + * 异常名 + * + * {@link Throwable#getClass()} 的类全名 + */ + private String exceptionName; + /** + * 异常导致的消息 + * + * {@link cn.hutool.core.exceptions.ExceptionUtil#getMessage(Throwable)} + */ + private String exceptionMessage; + /** + * 异常导致的根消息 + * + * {@link cn.hutool.core.exceptions.ExceptionUtil#getRootCauseMessage(Throwable)} + */ + private String exceptionRootCauseMessage; + /** + * 异常的栈轨迹 + * + * {@link org.apache.commons.lang3.exception.ExceptionUtils#getStackTrace(Throwable)} + */ + private String exceptionStackTrace; + /** + * 异常发生的类全名 + * + * {@link StackTraceElement#getClassName()} + */ + private String exceptionClassName; + /** + * 异常发生的类文件 + * + * {@link StackTraceElement#getFileName()} + */ + private String exceptionFileName; + /** + * 异常发生的方法名 + * + * {@link StackTraceElement#getMethodName()} + */ + private String exceptionMethodName; + /** + * 异常发生的方法所在行 + * + * {@link StackTraceElement#getLineNumber()} + */ + private Integer exceptionLineNumber; + + // ========== 处理相关字段 ========== + + /** + * 处理状态 + * + * 枚举 {@link ApiErrorLogProcessStatusEnum} + */ + private Integer processStatus; + /** + * 处理时间 + */ + private LocalDateTime processTime; + /** + * 处理用户编号 + * + * 关联 cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO.SysUserDO#getId() + */ + private Long processUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenColumnMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenColumnMapper.java new file mode 100644 index 0000000..3f1aedb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenColumnMapper.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.codegen; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface CodegenColumnMapper extends BaseMapperX { + + default List selectListByTableId(Long tableId) { + return selectList(new LambdaQueryWrapperX() + .eq(CodegenColumnDO::getTableId, tableId) + .orderByAsc(CodegenColumnDO::getId)); + } + + default void deleteListByTableId(Long tableId) { + delete(new LambdaQueryWrapperX() + .eq(CodegenColumnDO::getTableId, tableId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java new file mode 100644 index 0000000..f196700 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.codegen; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface CodegenTableMapper extends BaseMapperX { + + default CodegenTableDO selectByTableNameAndDataSourceConfigId(String tableName, Long dataSourceConfigId) { + return selectOne(CodegenTableDO::getTableName, tableName, + CodegenTableDO::getDataSourceConfigId, dataSourceConfigId); + } + + default PageResult selectPage(CodegenTablePageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(CodegenTableDO::getTableName, pageReqVO.getTableName()) + .likeIfPresent(CodegenTableDO::getTableComment, pageReqVO.getTableComment()) + .likeIfPresent(CodegenTableDO::getClassName, pageReqVO.getClassName()) + .betweenIfPresent(CodegenTableDO::getCreateTime, pageReqVO.getCreateTime()) + .orderByDesc(CodegenTableDO::getUpdateTime) + ); + } + + default List selectListByDataSourceConfigId(Long dataSourceConfigId) { + return selectList(CodegenTableDO::getDataSourceConfigId, dataSourceConfigId); + } + + default List selectListByTemplateTypeAndMasterTableId(Integer templateType, Long masterTableId) { + return selectList(CodegenTableDO::getTemplateType, templateType, + CodegenTableDO::getMasterTableId, masterTableId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java new file mode 100644 index 0000000..466403c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/config/ConfigMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.config; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ConfigMapper extends BaseMapperX { + + default ConfigDO selectByKey(String key) { + return selectOne(ConfigDO::getConfigKey, key); + } + + default PageResult selectPage(ConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ConfigDO::getName, reqVO.getName()) + .likeIfPresent(ConfigDO::getConfigKey, reqVO.getKey()) + .eqIfPresent(ConfigDO::getType, reqVO.getType()) + .betweenIfPresent(ConfigDO::getCreateTime, reqVO.getCreateTime())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java new file mode 100644 index 0000000..5ad8be4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/db/DataSourceConfigMapper.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.db; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 数据源配置 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DataSourceConfigMapper extends BaseMapperX { +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java new file mode 100644 index 0000000..f5f3cdb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo01; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 示例联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo01ContactMapper extends BaseMapperX { + + default PageResult selectPage(Demo01ContactPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(Demo01ContactDO::getName, reqVO.getName()) + .eqIfPresent(Demo01ContactDO::getSex, reqVO.getSex()) + .betweenIfPresent(Demo01ContactDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo01ContactDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java new file mode 100644 index 0000000..b16e18f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo02; + +import java.util.*; + +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 示例分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo02CategoryMapper extends BaseMapperX { + + default List selectList(Demo02CategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(Demo02CategoryDO::getName, reqVO.getName()) + .eqIfPresent(Demo02CategoryDO::getParentId, reqVO.getParentId()) + .betweenIfPresent(Demo02CategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo02CategoryDO::getId)); + } + + default Demo02CategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(Demo02CategoryDO::getParentId, parentId, Demo02CategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(Demo02CategoryDO::getParentId, parentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java new file mode 100644 index 0000000..3cb3aa5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 学生课程 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03CourseMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(Demo03CourseDO::getStudentId, studentId) + .orderByDesc(Demo03CourseDO::getId)); + } + + default List selectListByStudentId(Long studentId) { + return selectList(Demo03CourseDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(Demo03CourseDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java new file mode 100644 index 0000000..0440cc4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班级 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03GradeMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(Demo03GradeDO::getStudentId, studentId) + .orderByDesc(Demo03GradeDO::getId)); + } + + default Demo03GradeDO selectByStudentId(Long studentId) { + return selectOne(Demo03GradeDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(Demo03GradeDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java new file mode 100644 index 0000000..00659d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface Demo03StudentMapper extends BaseMapperX { + + default PageResult selectPage(Demo03StudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(Demo03StudentDO::getName, reqVO.getName()) + .eqIfPresent(Demo03StudentDO::getSex, reqVO.getSex()) + .eqIfPresent(Demo03StudentDO::getDescription, reqVO.getDescription()) + .betweenIfPresent(Demo03StudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(Demo03StudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java new file mode 100644 index 0000000..c0e2af3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.file; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface FileConfigMapper extends BaseMapperX { + + default PageResult selectPage(FileConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(FileConfigDO::getName, reqVO.getName()) + .eqIfPresent(FileConfigDO::getStorage, reqVO.getStorage()) + .betweenIfPresent(FileConfigDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(FileConfigDO::getId)); + } + + default FileConfigDO selectByMaster() { + return selectOne(FileConfigDO::getMaster, true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java new file mode 100644 index 0000000..3d6ec51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.file; + +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface FileContentMapper extends BaseMapper { + + default void deleteByConfigIdAndPath(Long configId, String path) { + this.delete(new LambdaQueryWrapper() + .eq(FileContentDO::getConfigId, configId) + .eq(FileContentDO::getPath, path)); + } + + default List selectListByConfigIdAndPath(Long configId, String path) { + return selectList(new LambdaQueryWrapper() + .eq(FileContentDO::getConfigId, configId) + .eq(FileContentDO::getPath, path)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java new file mode 100644 index 0000000..11233a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.file; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 文件操作 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface FileMapper extends BaseMapperX { + + default PageResult selectPage(FilePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(FileDO::getPath, reqVO.getPath()) + .likeIfPresent(FileDO::getType, reqVO.getType()) + .betweenIfPresent(FileDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(FileDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobLogMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobLogMapper.java new file mode 100644 index 0000000..58ac6da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobLogMapper.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * 任务日志 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface JobLogMapper extends BaseMapperX { + + default PageResult selectPage(JobLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(JobLogDO::getJobId, reqVO.getJobId()) + .likeIfPresent(JobLogDO::getHandlerName, reqVO.getHandlerName()) + .geIfPresent(JobLogDO::getBeginTime, reqVO.getBeginTime()) + .leIfPresent(JobLogDO::getEndTime, reqVO.getEndTime()) + .eqIfPresent(JobLogDO::getStatus, reqVO.getStatus()) + .orderByDesc(JobLogDO::getId) // ID 倒序 + ); + } + + /** + * 物理删除指定时间之前的日志 + * + * @param createTime 最大时间 + * @param limit 删除条数,防止一次删除太多 + * @return 删除条数 + */ + @Delete("DELETE FROM infra_job_log WHERE create_time < #{createTime} LIMIT #{limit}") + Integer deleteByCreateTimeLt(@Param("createTime") LocalDateTime createTime, @Param("limit") Integer limit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobMapper.java new file mode 100644 index 0000000..c585dbb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/job/JobMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 定时任务 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface JobMapper extends BaseMapperX { + + default JobDO selectByHandlerName(String handlerName) { + return selectOne(JobDO::getHandlerName, handlerName); + } + + default PageResult selectPage(JobPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(JobDO::getName, reqVO.getName()) + .eqIfPresent(JobDO::getStatus, reqVO.getStatus()) + .likeIfPresent(JobDO::getHandlerName, reqVO.getHandlerName()) + ); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java new file mode 100644 index 0000000..dce3082 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * API 访问日志 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ApiAccessLogMapper extends BaseMapperX { + + default PageResult selectPage(ApiAccessLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiAccessLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiAccessLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiAccessLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiAccessLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiAccessLogDO::getBeginTime, reqVO.getBeginTime()) + .geIfPresent(ApiAccessLogDO::getDuration, reqVO.getDuration()) + .eqIfPresent(ApiAccessLogDO::getResultCode, reqVO.getResultCode()) + .orderByDesc(ApiAccessLogDO::getId) + ); + } + + /** + * 物理删除指定时间之前的日志 + * + * @param createTime 最大时间 + * @param limit 删除条数,防止一次删除太多 + * @return 删除条数 + */ + @Delete("DELETE FROM infra_api_access_log WHERE create_time < #{createTime} LIMIT #{limit}") + Integer deleteByCreateTimeLt(@Param("createTime") LocalDateTime createTime, @Param("limit") Integer limit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java new file mode 100644 index 0000000..b597d79 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * API 错误日志 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ApiErrorLogMapper extends BaseMapperX { + + default PageResult selectPage(ApiErrorLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiErrorLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiErrorLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiErrorLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiErrorLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiErrorLogDO::getExceptionTime, reqVO.getExceptionTime()) + .eqIfPresent(ApiErrorLogDO::getProcessStatus, reqVO.getProcessStatus()) + .orderByDesc(ApiErrorLogDO::getId) + ); + } + + /** + * 物理删除指定时间之前的日志 + * + * @param createTime 最大时间 + * @param limit 删除条数,防止一次删除太多 + * @return 删除条数 + */ + @Delete("DELETE FROM infra_api_error_log WHERE create_time < #{createTime} LIMIT #{limit}") + Integer deleteByCreateTimeLt(@Param("createTime") LocalDateTime createTime, @Param("limit")Integer limit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java new file mode 100644 index 0000000..2c0cdbb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成器的字段 HTML 展示枚举 + */ +@AllArgsConstructor +@Getter +public enum CodegenColumnHtmlTypeEnum { + + INPUT("input"), // 文本框 + TEXTAREA("textarea"), // 文本域 + SELECT("select"), // 下拉框 + RADIO("radio"), // 单选框 + CHECKBOX("checkbox"), // 复选框 + DATETIME("datetime"), // 日期控件 + IMAGE_UPLOAD("imageUpload"), // 上传图片 + FILE_UPLOAD("fileUpload"), // 上传文件 + EDITOR("editor"), // 富文本控件 + ; + + /** + * 条件 + */ + private final String type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnListConditionEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnListConditionEnum.java new file mode 100644 index 0000000..7098700 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnListConditionEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成器的字段过滤条件枚举 + */ +@AllArgsConstructor +@Getter +public enum CodegenColumnListConditionEnum { + + EQ("="), + NE("!="), + GT(">"), + GTE(">="), + LT("<"), + LTE("<="), + LIKE("LIKE"), + BETWEEN("BETWEEN"); + + /** + * 条件 + */ + private final String condition; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java new file mode 100644 index 0000000..b7d2403 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 代码生成的前端类型枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenFrontTypeEnum { + + VUE2(10), // Vue2 Element UI 标准模版 + VUE3(20), // Vue3 Element Plus 标准模版 + VUE3_SCHEMA(21), // Vue3 Element Plus Schema 模版 + VUE3_VBEN(30), // Vue3 VBEN 模版 + ; + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenSceneEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenSceneEnum.java new file mode 100644 index 0000000..f1fdea0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenSceneEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.enums.codegen; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import static cn.hutool.core.util.ArrayUtil.*; + +/** + * 代码生成的场景枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenSceneEnum { + + ADMIN(1, "管理后台", "admin", ""), + APP(2, "用户 APP", "app", "App"); + + /** + * 场景 + */ + private final Integer scene; + /** + * 场景名 + */ + private final String name; + /** + * 基础包名 + */ + private final String basePackage; + /** + * Controller 和 VO 类的前缀 + */ + private final String prefixClass; + + public static CodegenSceneEnum valueOf(Integer scene) { + return firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenTemplateTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenTemplateTypeEnum.java new file mode 100644 index 0000000..9a21833 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenTemplateTypeEnum.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.infra.enums.codegen; + +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 代码生成模板类型 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CodegenTemplateTypeEnum { + + ONE(1), // 单表(增删改查) + TREE(2), // 树表(增删改查) + + MASTER_NORMAL(10), // 主子表 - 主表 - 普通模式 + MASTER_ERP(11), // 主子表 - 主表 - ERP 模式 + MASTER_INNER(12), // 主子表 - 主表 - 内嵌模式 + SUB(15), // 主子表 - 子表 + ; + + /** + * 类型 + */ + private final Integer type; + + /** + * 是否为主表 + * + * @param type 类型 + * @return 是否主表 + */ + public static boolean isMaster(Integer type) { + return ObjectUtils.equalsAny(type, + MASTER_NORMAL.type, MASTER_ERP.type, MASTER_INNER.type); + } + + /** + * 是否为树表 + * + * @param type 类型 + * @return 是否树表 + */ + public static boolean isTree(Integer type) { + return Objects.equals(type, TREE.type); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java new file mode 100644 index 0000000..15c2015 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/config/ConfigTypeEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.infra.enums.config; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ConfigTypeEnum { + + /** + * 系统配置 + */ + SYSTEM(1), + /** + * 自定义配置 + */ + CUSTOM(2); + + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobLogStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobLogStatusEnum.java new file mode 100644 index 0000000..9567053 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobLogStatusEnum.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.enums.job; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 任务日志的状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum JobLogStatusEnum { + + RUNNING(0), // 运行中 + SUCCESS(1), // 成功 + FAILURE(2); // 失败 + + /** + * 状态 + */ + private final Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobStatusEnum.java new file mode 100644 index 0000000..3d9ec3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/job/JobStatusEnum.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.infra.enums.job; + +import com.google.common.collect.Sets; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.quartz.impl.jdbcjobstore.Constants; + +import java.util.Collections; +import java.util.Set; + +/** + * 任务状态的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum JobStatusEnum { + + /** + * 初始化中 + */ + INIT(0, Collections.emptySet()), + /** + * 开启 + */ + NORMAL(1, Sets.newHashSet(Constants.STATE_WAITING, Constants.STATE_ACQUIRED, Constants.STATE_BLOCKED)), + /** + * 暂停 + */ + STOP(2, Sets.newHashSet(Constants.STATE_PAUSED, Constants.STATE_PAUSED_BLOCKED)); + + /** + * 状态 + */ + private final Integer status; + /** + * 对应的 Quartz 触发器的状态集合 + */ + private final Set quartzStates; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/logger/ApiErrorLogProcessStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/logger/ApiErrorLogProcessStatusEnum.java new file mode 100644 index 0000000..b309753 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/logger/ApiErrorLogProcessStatusEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * API 异常数据的处理状态 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum ApiErrorLogProcessStatusEnum { + + INIT(0, "未处理"), + DONE(1, "已处理"), + IGNORE(2, "已忽略"); + + /** + * 状态 + */ + private final Integer status; + /** + * 资源类型名 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/package-info.java new file mode 100644 index 0000000..0749e8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.infra.enums; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenConfiguration.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenConfiguration.java new file mode 100644 index 0000000..d49723d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenConfiguration.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.infra.framework.codegen.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(CodegenProperties.class) +public class CodegenConfiguration { +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenProperties.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenProperties.java new file mode 100644 index 0000000..4039a70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/config/CodegenProperties.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.infra.framework.codegen.config; + +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Collection; + +@ConfigurationProperties(prefix = "yudao.codegen") +@Validated +@Data +public class CodegenProperties { + + /** + * 生成的 Java 代码的基础包 + */ + @NotNull(message = "Java 代码的基础包不能为空") + private String basePackage; + + /** + * 数据库名数组 + */ + @NotEmpty(message = "数据库不能为空") + private Collection dbSchemas; + + /** + * 代码生成的前端类型(默认) + * + * 枚举 {@link CodegenFrontTypeEnum#getType()} + */ + @NotNull(message = "代码生成的前端类型不能为空") + private Integer frontType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/package-info.java new file mode 100644 index 0000000..cf1d22c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/codegen/package-info.java @@ -0,0 +1,4 @@ +/** + * 代码生成器 + */ +package cn.iocoder.yudao.module.infra.framework.codegen; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/config/YudaoFileAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/config/YudaoFileAutoConfiguration.java new file mode 100644 index 0000000..e0d3f8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/config/YudaoFileAutoConfiguration.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.infra.framework.file.config; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientFactory; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 文件配置类 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class YudaoFileAutoConfiguration { + + @Bean + public FileClientFactory fileClientFactory() { + return new FileClientFactoryImpl(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java new file mode 100644 index 0000000..3c7883b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * 文件客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author 芋道源码 + */ +@Slf4j +public abstract class AbstractFileClient implements FileClient { + + /** + * 配置编号 + */ + private final Long id; + /** + * 文件配置 + */ + protected Config config; + + public AbstractFileClient(Long id, Config config) { + this.id = id; + this.config = config; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.debug("[init][配置({}) 初始化完成]", config); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + public final void refresh(Config config) { + // 判断是否更新 + if (config.equals(this.config)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", config); + this.config = config; + // 初始化 + this.init(); + } + + @Override + public Long getId() { + return id; + } + + /** + * 格式化文件的 URL 访问地址 + * 使用场景:local、ftp、db,通过 FileController 的 getFile 来获取文件内容 + * + * @param domain 自定义域名 + * @param path 文件路径 + * @return URL 访问地址 + */ + protected String formatFileUrl(String domain, String path) { + return StrUtil.format("{}/admin-api/infra/file/{}/get/{}", domain, getId(), path); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClient.java new file mode 100644 index 0000000..053b3c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClient.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; + +/** + * 文件客户端 + * + * @author 芋道源码 + */ +public interface FileClient { + + /** + * 获得客户端编号 + * + * @return 客户端编号 + */ + Long getId(); + + /** + * 上传文件 + * + * @param content 文件流 + * @param path 相对路径 + * @return 完整路径,即 HTTP 访问地址 + * @throws Exception 上传文件时,抛出 Exception 异常 + */ + String upload(byte[] content, String path, String type) throws Exception; + + /** + * 删除文件 + * + * @param path 相对路径 + * @throws Exception 删除文件时,抛出 Exception 异常 + */ + void delete(String path) throws Exception; + + /** + * 获得文件的内容 + * + * @param path 相对路径 + * @return 文件的内容 + */ + byte[] getContent(String path) throws Exception; + + /** + * 获得文件预签名地址 + * + * @param path 相对路径 + * @return 文件预签名地址 + */ + default FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { + throw new UnsupportedOperationException("不支持的操作"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientConfig.java new file mode 100644 index 0000000..ed09275 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientConfig.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +/** + * 文件客户端的配置 + * 不同实现的客户端,需要不同的配置,通过子类来定义 + * + * @author 芋道源码 + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +// @JsonTypeInfo 注解的作用,Jackson 多态 +// 1. 序列化到时数据库时,增加 @class 属性。 +// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 +public interface FileClientConfig { +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactory.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactory.java new file mode 100644 index 0000000..e4c84ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactory.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client; + +import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; + +public interface FileClientFactory { + + /** + * 获得文件客户端 + * + * @param configId 配置编号 + * @return 文件客户端 + */ + FileClient getFileClient(Long configId); + + /** + * 创建文件客户端 + * + * @param configId 配置编号 + * @param storage 存储器的枚举 {@link FileStorageEnum} + * @param config 文件配置 + */ + void createOrUpdateFileClient(Long configId, Integer storage, Config config); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactoryImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactoryImpl.java new file mode 100644 index 0000000..2bd5464 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/FileClientFactoryImpl.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 文件客户端的工厂实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class FileClientFactoryImpl implements FileClientFactory { + + /** + * 文件客户端 Map + * key:配置编号 + */ + private final ConcurrentMap> clients = new ConcurrentHashMap<>(); + + @Override + public FileClient getFileClient(Long configId) { + AbstractFileClient client = clients.get(configId); + if (client == null) { + log.error("[getFileClient][配置编号({}) 找不到客户端]", configId); + } + return client; + } + + @Override + @SuppressWarnings("unchecked") + public void createOrUpdateFileClient(Long configId, Integer storage, Config config) { + AbstractFileClient client = (AbstractFileClient) clients.get(configId); + if (client == null) { + client = this.createFileClient(configId, storage, config); + client.init(); + clients.put(client.getId(), client); + } else { + client.refresh(config); + } + } + + @SuppressWarnings("unchecked") + private AbstractFileClient createFileClient( + Long configId, Integer storage, Config config) { + FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage); + Assert.notNull(storageEnum, String.format("文件配置(%s) 为空", storageEnum)); + // 创建客户端 + return (AbstractFileClient) ReflectUtil.newInstance(storageEnum.getClientClass(), configId, config); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClient.java new file mode 100644 index 0000000..0a050d3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClient.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.db; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileContentMapper; +import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; + +import java.util.Comparator; +import java.util.List; + +/** + * 基于 DB 存储的文件客户端的配置类 + * + * @author 芋道源码 + */ +public class DBFileClient extends AbstractFileClient { + + private FileContentMapper fileContentMapper; + + public DBFileClient(Long id, DBFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + fileContentMapper = SpringUtil.getBean(FileContentMapper.class); + } + + @Override + public String upload(byte[] content, String path, String type) { + FileContentDO contentDO = new FileContentDO().setConfigId(getId()) + .setPath(path).setContent(content); + fileContentMapper.insert(contentDO); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + fileContentMapper.deleteByConfigIdAndPath(getId(), path); + } + + @Override + public byte[] getContent(String path) { + List list = fileContentMapper.selectListByConfigIdAndPath(getId(), path); + if (CollUtil.isEmpty(list)) { + return null; + } + // 排序后,拿 id 最大的,即最后上传的 + list.sort(Comparator.comparing(FileContentDO::getId)); + return CollUtil.getLast(list).getContent(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClientConfig.java new file mode 100644 index 0000000..11830e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/db/DBFileClientConfig.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.db; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; + +/** + * 基于 DB 存储的文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class DBFileClientConfig implements FileClientConfig { + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClient.java new file mode 100644 index 0000000..062d838 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClient.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.ftp; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.ftp.Ftp; +import cn.hutool.extra.ftp.FtpException; +import cn.hutool.extra.ftp.FtpMode; +import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +/** + * Ftp 文件客户端 + * + * @author 芋道源码 + */ +public class FtpFileClient extends AbstractFileClient { + + private Ftp ftp; + + public FtpFileClient(Long id, FtpFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 把配置的 \ 替换成 /, 如果路径配置 \a\test, 替换成 /a/test, 替换方法已经处理 null 情况 + config.setBasePath(StrUtil.replace(config.getBasePath(), StrUtil.BACKSLASH, StrUtil.SLASH)); + // ftp的路径是 / 结尾 + if (!config.getBasePath().endsWith(StrUtil.SLASH)) { + config.setBasePath(config.getBasePath() + StrUtil.SLASH); + } + // 初始化 Ftp 对象 + this.ftp = new Ftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword(), + CharsetUtil.CHARSET_UTF_8, null, null, FtpMode.valueOf(config.getMode())); + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + String fileName = FileUtil.getName(filePath); + String dir = StrUtil.removeSuffix(filePath, fileName); + ftp.reconnectIfTimeout(); + boolean success = ftp.upload(dir, fileName, new ByteArrayInputStream(content)); + if (!success) { + throw new FtpException(StrUtil.format("上传文件到目标目录 ({}) 失败", filePath)); + } + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + ftp.reconnectIfTimeout(); + ftp.delFile(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + String fileName = FileUtil.getName(filePath); + String dir = StrUtil.removeSuffix(filePath, fileName); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ftp.reconnectIfTimeout(); + ftp.download(dir, fileName, out); + return out.toByteArray(); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClientConfig.java new file mode 100644 index 0000000..d3ba00c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/ftp/FtpFileClientConfig.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.ftp; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * Ftp 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class FtpFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + + /** + * 主机地址 + */ + @NotEmpty(message = "host 不能为空") + private String host; + /** + * 主机端口 + */ + @NotNull(message = "port 不能为空") + private Integer port; + /** + * 用户名 + */ + @NotEmpty(message = "用户名不能为空") + private String username; + /** + * 密码 + */ + @NotEmpty(message = "密码不能为空") + private String password; + /** + * 连接模式 + * + * 使用 {@link cn.hutool.extra.ftp.FtpMode} 对应的字符串 + */ + @NotEmpty(message = "连接模式不能为空") + private String mode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java new file mode 100644 index 0000000..a919690 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.local; + +import cn.hutool.core.io.FileUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; + +import java.io.File; + +/** + * 本地文件客户端 + * + * @author 芋道源码 + */ +public class LocalFileClient extends AbstractFileClient { + + public LocalFileClient(Long id, LocalFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全风格。例如说 Linux 是 /,Windows 是 \ + if (!config.getBasePath().endsWith(File.separator)) { + config.setBasePath(config.getBasePath() + File.separator); + } + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + FileUtil.writeBytes(content, filePath); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + FileUtil.del(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + return FileUtil.readBytes(filePath); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClientConfig.java new file mode 100644 index 0000000..b432013 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClientConfig.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.local; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; + +/** + * 本地文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class LocalFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java new file mode 100644 index 0000000..6a1258e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/FilePresignedUrlRespDTO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.s3; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 文件预签名地址 Response DTO + * + * @author owen + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FilePresignedUrlRespDTO { + + /** + * 文件上传 URL(用于上传) + * + * 例如说: + */ + private String uploadUrl; + + /** + * 文件 URL(用于读取、下载等) + */ + private String url; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java new file mode 100644 index 0000000..67995ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.s3; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; +import io.minio.*; +import io.minio.http.Method; + +import java.io.ByteArrayInputStream; +import java.util.concurrent.TimeUnit; + +/** + * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 + *

+ * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 + * + * @author 芋道源码 + */ +public class S3FileClient extends AbstractFileClient { + + private MinioClient client; + + public S3FileClient(Long id, S3FileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全 domain + if (StrUtil.isEmpty(config.getDomain())) { + config.setDomain(buildDomain()); + } + // 初始化客户端 + client = MinioClient.builder() + .endpoint(buildEndpointURL()) // Endpoint URL + .region(buildRegion()) // Region + .credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥 + .build(); + } + + /** + * 基于 endpoint 构建调用云服务的 URL 地址 + * + * @return URI 地址 + */ + private String buildEndpointURL() { + // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO + if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { + return config.getEndpoint(); + } + return StrUtil.format("https://{}", config.getEndpoint()); + } + + /** + * 基于 bucket + endpoint 构建访问的 Domain 地址 + * + * @return Domain 地址 + */ + private String buildDomain() { + // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO + if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { + return StrUtil.format("{}/{}", config.getEndpoint(), config.getBucket()); + } + // 阿里云、腾讯云、华为云都适合。七牛云比较特殊,必须有自定义域名 + return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); + } + + /** + * 基于 bucket 构建 region 地区 + * + * @return region 地区 + */ + private String buildRegion() { + // 阿里云必须有 region,否则会报错 + if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_ALIYUN)) { + return StrUtil.subBefore(config.getEndpoint(), '.', false) + .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀 + .replaceAll("https://", ""); + } + // 腾讯云必须有 region,否则会报错 + if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_TENCENT)) { + return StrUtil.subAfter(config.getEndpoint(), "cos.", false) + .replaceAll("." + S3FileClientConfig.ENDPOINT_TENCENT, ""); // 去除 Endpoint + } + return null; + } + + @Override + public String upload(byte[] content, String path, String type) throws Exception { + // 执行上传 + client.putObject(PutObjectArgs.builder() + .bucket(config.getBucket()) // bucket 必须传递 + .contentType(type) + .object(path) // 相对路径作为 key + .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容 + .build()); + // 拼接返回路径 + return config.getDomain() + "/" + path; + } + + @Override + public void delete(String path) throws Exception { + client.removeObject(RemoveObjectArgs.builder() + .bucket(config.getBucket()) // bucket 必须传递 + .object(path) // 相对路径作为 key + .build()); + } + + @Override + public byte[] getContent(String path) throws Exception { + GetObjectResponse response = client.getObject(GetObjectArgs.builder() + .bucket(config.getBucket()) // bucket 必须传递 + .object(path) // 相对路径作为 key + .build()); + return IoUtil.readBytes(response); + } + + @Override + public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { + String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() + .method(Method.PUT) + .bucket(config.getBucket()) + .object(path) + .expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天 + .build() + ); + return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java new file mode 100644 index 0000000..fccfa38 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.s3; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + +/** + * S3 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class S3FileClientConfig implements FileClientConfig { + + public static final String ENDPOINT_QINIU = "qiniucs.com"; + public static final String ENDPOINT_ALIYUN = "aliyuncs.com"; + public static final String ENDPOINT_TENCENT = "myqcloud.com"; + + /** + * 节点地址 + * 1. MinIO:https://www.iocoder.cn/Spring-Boot/MinIO 。例如说,http://127.0.0.1:9000 + * 2. 阿里云:https://help.aliyun.com/document_detail/31837.html + * 3. 腾讯云:https://cloud.tencent.com/document/product/436/6224 + * 4. 七牛云:https://developer.qiniu.com/kodo/4088/s3-access-domainname + * 5. 华为云:https://developer.huaweicloud.com/endpoint?OBS + */ + @NotNull(message = "endpoint 不能为空") + private String endpoint; + /** + * 自定义域名 + * 1. MinIO:通过 Nginx 配置 + * 2. 阿里云:https://help.aliyun.com/document_detail/31836.html + * 3. 腾讯云:https://cloud.tencent.com/document/product/436/11142 + * 4. 七牛云:https://developer.qiniu.com/kodo/8556/set-the-custom-source-domain-name + * 5. 华为云:https://support.huaweicloud.com/usermanual-obs/obs_03_0032.html + */ + @URL(message = "domain 必须是 URL 格式") + private String domain; + /** + * 存储 Bucket + */ + @NotNull(message = "bucket 不能为空") + private String bucket; + + /** + * 访问 Key + * 1. MinIO:https://www.iocoder.cn/Spring-Boot/MinIO + * 2. 阿里云:https://ram.console.aliyun.com/manage/ak + * 3. 腾讯云:https://console.cloud.tencent.com/cam/capi + * 4. 七牛云:https://portal.qiniu.com/user/key + * 5. 华为云:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html + */ + @NotNull(message = "accessKey 不能为空") + private String accessKey; + /** + * 访问 Secret + */ + @NotNull(message = "accessSecret 不能为空") + private String accessSecret; + + @SuppressWarnings("RedundantIfStatement") + @AssertTrue(message = "domain 不能为空") + @JsonIgnore + public boolean isDomainValid() { + // 如果是七牛,必须带有 domain + if (StrUtil.contains(endpoint, ENDPOINT_QINIU) && StrUtil.isEmpty(domain)) { + return false; + } + return true; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClient.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClient.java new file mode 100644 index 0000000..3ebe782 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClient.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.sftp; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.extra.ssh.Sftp; +import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; + +import java.io.File; + +/** + * Sftp 文件客户端 + * + * @author 芋道源码 + */ +public class SftpFileClient extends AbstractFileClient { + + private Sftp sftp; + + public SftpFileClient(Long id, SftpFileClientConfig config) { + super(id, config); + } + + @Override + protected void doInit() { + // 补全风格。例如说 Linux 是 /,Windows 是 \ + if (!config.getBasePath().endsWith(File.separator)) { + config.setBasePath(config.getBasePath() + File.separator); + } + // 初始化 Ftp 对象 + this.sftp = new Sftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword()); + } + + @Override + public String upload(byte[] content, String path, String type) { + // 执行写入 + String filePath = getFilePath(path); + File file = FileUtils.createTempFile(content); + sftp.upload(filePath, file); + // 拼接返回路径 + return super.formatFileUrl(config.getDomain(), path); + } + + @Override + public void delete(String path) { + String filePath = getFilePath(path); + sftp.delFile(filePath); + } + + @Override + public byte[] getContent(String path) { + String filePath = getFilePath(path); + File destFile = FileUtils.createTempFile(); + sftp.download(filePath, destFile); + return FileUtil.readBytes(destFile); + } + + private String getFilePath(String path) { + return config.getBasePath() + path; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClientConfig.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClientConfig.java new file mode 100644 index 0000000..5af3961 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/sftp/SftpFileClientConfig.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.client.sftp; + +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * Sftp 文件客户端的配置类 + * + * @author 芋道源码 + */ +@Data +public class SftpFileClientConfig implements FileClientConfig { + + /** + * 基础路径 + */ + @NotEmpty(message = "基础路径不能为空") + private String basePath; + + /** + * 自定义域名 + */ + @NotEmpty(message = "domain 不能为空") + @URL(message = "domain 必须是 URL 格式") + private String domain; + + /** + * 主机地址 + */ + @NotEmpty(message = "host 不能为空") + private String host; + /** + * 主机端口 + */ + @NotNull(message = "port 不能为空") + private Integer port; + /** + * 用户名 + */ + @NotEmpty(message = "用户名不能为空") + private String username; + /** + * 密码 + */ + @NotEmpty(message = "密码不能为空") + private String password; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/enums/FileStorageEnum.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/enums/FileStorageEnum.java new file mode 100644 index 0000000..866c43b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/enums/FileStorageEnum.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 文件存储器枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum FileStorageEnum { + + DB(1, DBFileClientConfig.class, DBFileClient.class), + + LOCAL(10, LocalFileClientConfig.class, LocalFileClient.class), + FTP(11, FtpFileClientConfig.class, FtpFileClient.class), + SFTP(12, SftpFileClientConfig.class, SftpFileClient.class), + + S3(20, S3FileClientConfig.class, S3FileClient.class), + ; + + /** + * 存储器 + */ + private final Integer storage; + + /** + * 配置类 + */ + private final Class configClass; + /** + * 客户端类 + */ + private final Class clientClass; + + public static FileStorageEnum getByStorage(Integer storage) { + return ArrayUtil.firstMatch(o -> o.getStorage().equals(storage), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java new file mode 100644 index 0000000..a4147af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.ttl.TransmittableThreadLocal; +import lombok.SneakyThrows; +import org.apache.tika.Tika; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; + +/** + * 文件类型 Utils + * + * @author 芋道源码 + */ +public class FileTypeUtils { + + private static final ThreadLocal TIKA = TransmittableThreadLocal.withInitial(Tika::new); + + /** + * 获得文件的 mineType,对于doc,jar等文件会有误差 + * + * @param data 文件内容 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + @SneakyThrows + public static String getMineType(byte[] data) { + return TIKA.get().detect(data); + } + + /** + * 已知文件名,获取文件类型,在某些情况下比通过字节数组准确,例如使用jar文件时,通过名字更为准确 + * + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(String name) { + return TIKA.get().detect(name); + } + + /** + * 在拥有文件和数据的情况下,最好使用此方法,最为准确 + * + * @param data 文件内容 + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(byte[] data, String name) { + return TIKA.get().detect(data, name); + } + + /** + * 返回附件 + * + * @param response 响应 + * @param filename 文件名 + * @param content 附件内容 + */ + public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { + // 设置 header 和 contentType + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + String contentType = getMineType(content, filename); + response.setContentType(contentType); + // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 + if (StrUtil.containsIgnoreCase(contentType, "video")) { + response.setHeader("Content-Length", String.valueOf(content.length - 1)); + response.setHeader("Content-Range", String.valueOf(content.length - 1)); + response.setHeader("Accept-Ranges", "bytes"); + } + // 输出附件 + IoUtil.write(response.getOutputStream(), false, content); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/package-info.java new file mode 100644 index 0000000..04b6867 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/package-info.java @@ -0,0 +1,12 @@ +/** + * 文件客户端,支持多种存储器 + * + * 1. local:本地磁盘 + * 2. ftp:FTP 服务器 + * 3. sftp:SFTP 服务器 + * 4. db:数据库 + * 5. s3:支持 S3 协议的云存储服务,例如说 MinIO、阿里云、华为云、腾讯云、七牛云等等 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.infra.framework.file; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/config/AdminServerConfiguration.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/config/AdminServerConfiguration.java new file mode 100644 index 0000000..0c29865 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/config/AdminServerConfiguration.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.infra.framework.monitor.config; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableAdminServer +public class AdminServerConfiguration { +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/package-info.java new file mode 100644 index 0000000..f52e72c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/package-info.java @@ -0,0 +1,4 @@ +/** + * 使用 Spring Boot Admin 实现简单的监控平台 + */ +package cn.iocoder.yudao.module.infra.framework.monitor; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md new file mode 100644 index 0000000..a1e3676 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/package-info.java new file mode 100644 index 0000000..77a646a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 infra 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.infra.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java new file mode 100644 index 0000000..2f22f4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.infra.framework.security.config; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; + +/** + * Infra 模块的 Security 配置 + */ +@Configuration(proxyBeanMethods = false, value = "infraSecurityConfiguration") +public class SecurityConfiguration { + + @Value("${spring.boot.admin.context-path:''}") + private String adminSeverContextPath; + + @Bean("infraAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) { + // Swagger 接口文档 + registry.antMatchers("/v3/api-docs/**").permitAll() + .antMatchers("/swagger-ui.html").permitAll() + .antMatchers("/swagger-ui/**").permitAll() + .antMatchers("/swagger-resources/**").anonymous() + .antMatchers("/webjars/**").anonymous() + .antMatchers("/*/api-docs").anonymous(); + // Spring Boot Actuator 的安全配置 + registry.antMatchers("/actuator").anonymous() + .antMatchers("/actuator/**").anonymous(); + // Druid 监控 + registry.antMatchers("/druid/**").anonymous(); + // Spring Boot Admin Server 的安全配置 + registry.antMatchers(adminSeverContextPath).anonymous() + .antMatchers(adminSeverContextPath + "/**").anonymous(); + // 文件读取 + registry.antMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll(); + } + + }; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/core/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/core/package-info.java new file mode 100644 index 0000000..7762626 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.infra.framework.security.core; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/config/InfraWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/config/InfraWebConfiguration.java new file mode 100644 index 0000000..09f2c2b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/config/InfraWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * infra 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class InfraWebConfiguration { + + /** + * infra 模块的 API 分组 + */ + @Bean + public GroupedOpenApi infraGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("infra"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/package-info.java new file mode 100644 index 0000000..6fb49bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * infra 模块的 web 配置 + */ +package cn.iocoder.yudao.module.infra.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java new file mode 100644 index 0000000..3f9d293 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.infra.job.job; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.infra.service.job.JobLogService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import javax.annotation.Resource; + +/** + * 物理删除 N 天前的任务日志的 Job + * + * @author j-sentinel + */ +@Slf4j +@Component +public class JobLogCleanJob implements JobHandler { + + @Resource + private JobLogService jobLogService; + + /** + * 清理超过(14)天的日志 + */ + private static final Integer JOB_CLEAN_RETAIN_DAY = 14; + + /** + * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 + */ + private static final Integer DELETE_LIMIT = 100; + + @Override + @TenantIgnore + public String execute(String param) { + Integer count = jobLogService.cleanJobLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); + log.info("[execute][定时执行清理定时任务日志数量 ({}) 个]", count); + return String.format("定时执行清理定时任务日志数量 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java new file mode 100644 index 0000000..6b8b87c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.job.logger; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 物理删除 N 天前的访问日志的 Job + * + * @author j-sentinel + */ +@Component +@Slf4j +public class AccessLogCleanJob implements JobHandler { + + @Resource + private ApiAccessLogService apiAccessLogService; + + /** + * 清理超过(14)天的日志 + */ + private static final Integer JOB_CLEAN_RETAIN_DAY = 14; + + /** + * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 + */ + private static final Integer DELETE_LIMIT = 100; + + @Override + @TenantIgnore + public String execute(String param) { + Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT); + log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count); + return String.format("定时执行清理访问日志数量 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java new file mode 100644 index 0000000..9b50aaf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.job.logger; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.infra.service.logger.ApiErrorLogService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 物理删除 N 天前的错误日志的 Job + * + * @author j-sentinel + */ +@Slf4j +@Component +public class ErrorLogCleanJob implements JobHandler { + + @Resource + private ApiErrorLogService apiErrorLogService; + + /** + * 清理超过(14)天的日志 + */ + private static final Integer JOB_CLEAN_RETAIN_DAY = 14; + + /** + * 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大 + */ + private static final Integer DELETE_LIMIT = 100; + + @Override + @TenantIgnore + public String execute(String param) { + Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT); + log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count); + return String.format("定时执行清理错误日志数量 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java new file mode 100644 index 0000000..5ba5264 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消费者 + */ +package cn.iocoder.yudao.module.infra.mq.consumer; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java new file mode 100644 index 0000000..19edb02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package cn.iocoder.yudao.module.infra.mq.message; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java new file mode 100644 index 0000000..343179c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的生产者 + */ +package cn.iocoder.yudao.module.infra.mq.producer; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/package-info.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/package-info.java new file mode 100644 index 0000000..b45e7a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/package-info.java @@ -0,0 +1,9 @@ +/** + * infra 模块,主要提供两块能力: + * 1. 我们放基础设施的运维与管理,支撑上层的通用与核心业务。 例如说:定时任务的管理、服务器的信息等等 + * 2. 研发工具,提升研发效率与质量。 例如说:代码生成器、接口文档等等 + * + * 1. Controller URL:以 /infra/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 infra_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.infra; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java new file mode 100644 index 0000000..00e36af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.infra.service.codegen; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; + +import java.util.List; +import java.util.Map; + +/** + * 代码生成 Service 接口 + * + * @author 芋道源码 + */ +public interface CodegenService { + + /** + * 基于数据库的表结构,创建代码生成器的表定义 + * + * @param userId 用户编号 + * @param reqVO 表信息 + * @return 创建的表定义的编号数组 + */ + List createCodegenList(Long userId, CodegenCreateListReqVO reqVO); + + /** + * 更新数据库的表和字段定义 + * + * @param updateReqVO 更新信息 + */ + void updateCodegen(CodegenUpdateReqVO updateReqVO); + + /** + * 基于数据库的表结构,同步数据库的表和字段定义 + * + * @param tableId 表编号 + */ + void syncCodegenFromDB(Long tableId); + + /** + * 删除数据库的表和字段定义 + * + * @param tableId 数据编号 + */ + void deleteCodegen(Long tableId); + + /** + * 获得表定义列表 + * + * @param dataSourceConfigId 数据源配置的编号 + * @return 表定义列表 + */ + List getCodegenTableList(Long dataSourceConfigId); + + /** + * 获得表定义分页 + * + * @param pageReqVO 分页条件 + * @return 表定义分页 + */ + PageResult getCodegenTablePage(CodegenTablePageReqVO pageReqVO); + + /** + * 获得表定义 + * + * @param id 表编号 + * @return 表定义 + */ + CodegenTableDO getCodegenTable(Long id); + + /** + * 获得指定表的字段定义数组 + * + * @param tableId 表编号 + * @return 字段定义数组 + */ + List getCodegenColumnListByTableId(Long tableId); + + /** + * 执行指定表的代码生成 + * + * @param tableId 表编号 + * @return 生成结果。key 为文件路径,value 为对应的代码内容 + */ + Map generationCodes(Long tableId); + + /** + * 获得数据库自带的表定义列表 + * + * @param dataSourceConfigId 数据源的配置编号 + * @param name 表名称 + * @param comment 表描述 + * @return 表定义列表 + */ + List getDatabaseTableList(Long dataSourceConfigId, String name, String comment); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java new file mode 100644 index 0000000..34f83cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java @@ -0,0 +1,288 @@ +package cn.iocoder.yudao.module.infra.service.codegen; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder; +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine; +import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 代码生成 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class CodegenServiceImpl implements CodegenService { + + @Resource + private DatabaseTableService databaseTableService; + + @Resource + private CodegenTableMapper codegenTableMapper; + @Resource + private CodegenColumnMapper codegenColumnMapper; + + @Resource + private AdminUserApi userApi; + + @Resource + private CodegenBuilder codegenBuilder; + @Resource + private CodegenEngine codegenEngine; + + @Resource + private CodegenProperties codegenProperties; + + @Override + @Transactional(rollbackFor = Exception.class) + public List createCodegenList(Long userId, CodegenCreateListReqVO reqVO) { + List ids = new ArrayList<>(reqVO.getTableNames().size()); + // 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量 + reqVO.getTableNames().forEach(tableName -> ids.add(createCodegen(userId, reqVO.getDataSourceConfigId(), tableName))); + return ids; + } + + private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) { + // 从数据库中,获得数据库表结构 + TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName); + // 导入 + return createCodegen0(userId, dataSourceConfigId, tableInfo); + } + + private Long createCodegen0(Long userId, Long dataSourceConfigId, TableInfo tableInfo) { + // 校验导入的表和字段非空 + validateTableInfo(tableInfo); + // 校验是否已经存在 + if (codegenTableMapper.selectByTableNameAndDataSourceConfigId(tableInfo.getName(), + dataSourceConfigId) != null) { + throw exception(CODEGEN_TABLE_EXISTS); + } + + // 构建 CodegenTableDO 对象,插入到 DB 中 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo); + table.setDataSourceConfigId(dataSourceConfigId); + table.setScene(CodegenSceneEnum.ADMIN.getScene()); // 默认配置下,使用管理后台的模板 + table.setFrontType(codegenProperties.getFrontType()); + table.setAuthor(userApi.getUser(userId).getNickname()); + codegenTableMapper.insert(table); + + // 构建 CodegenColumnDO 数组,插入到 DB 中 + List columns = codegenBuilder.buildColumns(table.getId(), tableInfo.getFields()); + // 如果没有主键,则使用第一个字段作为主键 + if (!tableInfo.isHavePrimaryKey()) { + columns.get(0).setPrimaryKey(true); + } + codegenColumnMapper.insertBatch(columns); + return table.getId(); + } + + @VisibleForTesting + void validateTableInfo(TableInfo tableInfo) { + if (tableInfo == null) { + throw exception(CODEGEN_IMPORT_TABLE_NULL); + } + if (StrUtil.isEmpty(tableInfo.getComment())) { + throw exception(CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL); + } + if (CollUtil.isEmpty(tableInfo.getFields())) { + throw exception(CODEGEN_IMPORT_COLUMNS_NULL); + } + tableInfo.getFields().forEach(field -> { + if (StrUtil.isEmpty(field.getComment())) { + throw exception(CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName()); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCodegen(CodegenUpdateReqVO updateReqVO) { + // 校验是否已经存在 + if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) { + throw exception(CODEGEN_TABLE_NOT_EXISTS); + } + // 校验主表字段存在 + if (Objects.equals(updateReqVO.getTable().getTemplateType(), CodegenTemplateTypeEnum.SUB.getType())) { + if (codegenTableMapper.selectById(updateReqVO.getTable().getMasterTableId()) == null) { + throw exception(CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId()); + } + if (CollUtil.findOne(updateReqVO.getColumns(), // 关联主表的字段不存在 + column -> column.getId().equals(updateReqVO.getTable().getSubJoinColumnId())) == null) { + throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId()); + } + } + + // 更新 table 表定义 + CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class); + codegenTableMapper.updateById(updateTableObj); + // 更新 column 字段定义 + List updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class); + updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncCodegenFromDB(Long tableId) { + // 校验是否已经存在 + CodegenTableDO table = codegenTableMapper.selectById(tableId); + if (table == null) { + throw exception(CODEGEN_TABLE_NOT_EXISTS); + } + // 从数据库中,获得数据库表结构 + TableInfo tableInfo = databaseTableService.getTable(table.getDataSourceConfigId(), table.getTableName()); + // 执行同步 + syncCodegen0(tableId, tableInfo); + } + + private void syncCodegen0(Long tableId, TableInfo tableInfo) { + // 1. 校验导入的表和字段非空 + validateTableInfo(tableInfo); + List tableFields = tableInfo.getFields(); + + // 2. 构建 CodegenColumnDO 数组,只同步新增的字段 + List codegenColumns = codegenColumnMapper.selectListByTableId(tableId); + Set codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName); + + // 3.1 计算需要【修改】的字段,插入时重新插入,删除时将原来的删除 + Map codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName); + BiPredicate primaryKeyPredicate = + (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType()) + && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable() + && tableField.isKeyFlag() == codegenColumn.getPrimaryKey() + && tableField.getComment().equals(codegenColumn.getColumnComment()); + Set modifyFieldNames = tableFields.stream() + .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null + && !primaryKeyPredicate.test(tableField, codegenColumnDOMap.get(tableField.getColumnName()))) + .map(TableField::getColumnName) + .collect(Collectors.toSet()); + // 3.2 计算需要【删除】的字段 + Set tableFieldNames = convertSet(tableFields, TableField::getName); + Set deleteColumnIds = codegenColumns.stream() + .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName())) + .map(CodegenColumnDO::getId).collect(Collectors.toSet()); + // 移除已经存在的字段 + tableFields.removeIf(column -> codegenColumnNames.contains(column.getColumnName()) && (!modifyFieldNames.contains(column.getColumnName()))); + if (CollUtil.isEmpty(tableFields) && CollUtil.isEmpty(deleteColumnIds)) { + throw exception(CODEGEN_SYNC_NONE_CHANGE); + } + + // 4.1 插入新增的字段 + List columns = codegenBuilder.buildColumns(tableId, tableFields); + codegenColumnMapper.insertBatch(columns); + // 4.2 删除不存在的字段 + if (CollUtil.isNotEmpty(deleteColumnIds)) { + codegenColumnMapper.deleteBatchIds(deleteColumnIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteCodegen(Long tableId) { + // 校验是否已经存在 + if (codegenTableMapper.selectById(tableId) == null) { + throw exception(CODEGEN_TABLE_NOT_EXISTS); + } + + // 删除 table 表定义 + codegenTableMapper.deleteById(tableId); + // 删除 column 字段定义 + codegenColumnMapper.deleteListByTableId(tableId); + } + + @Override + public List getCodegenTableList(Long dataSourceConfigId) { + return codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId); + } + + @Override + public PageResult getCodegenTablePage(CodegenTablePageReqVO pageReqVO) { + return codegenTableMapper.selectPage(pageReqVO); + } + + @Override + public CodegenTableDO getCodegenTable(Long id) { + return codegenTableMapper.selectById(id); + } + + @Override + public List getCodegenColumnListByTableId(Long tableId) { + return codegenColumnMapper.selectListByTableId(tableId); + } + + @Override + public Map generationCodes(Long tableId) { + // 校验是否已经存在 + CodegenTableDO table = codegenTableMapper.selectById(tableId); + if (table == null) { + throw exception(CODEGEN_TABLE_NOT_EXISTS); + } + List columns = codegenColumnMapper.selectListByTableId(tableId); + if (CollUtil.isEmpty(columns)) { + throw exception(CODEGEN_COLUMN_NOT_EXISTS); + } + + // 如果是主子表,则加载对应的子表信息 + List subTables = null; + List> subColumnsList = null; + if (CodegenTemplateTypeEnum.isMaster(table.getTemplateType())) { + // 校验子表存在 + subTables = codegenTableMapper.selectListByTemplateTypeAndMasterTableId( + CodegenTemplateTypeEnum.SUB.getType(), tableId); + if (CollUtil.isEmpty(subTables)) { + throw exception(CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE); + } + // 校验子表的关联字段存在 + subColumnsList = new ArrayList<>(); + for (CodegenTableDO subTable : subTables) { + List subColumns = codegenColumnMapper.selectListByTableId(subTable.getId()); + if (CollUtil.findOne(subColumns, column -> column.getId().equals(subTable.getSubJoinColumnId())) == null) { + throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId()); + } + subColumnsList.add(subColumns); + } + } + + // 执行生成 + return codegenEngine.execute(table, columns, subTables, subColumnsList); + } + + @Override + public List getDatabaseTableList(Long dataSourceConfigId, String name, String comment) { + List tables = databaseTableService.getTableList(dataSourceConfigId, name, comment); + // 移除在 Codegen 中,已经存在的 + Set existsTables = convertSet( + codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName); + tables.removeIf(table -> existsTables.contains(table.getName())); + return BeanUtils.toBean(tables, DatabaseTableRespVO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java new file mode 100644 index 0000000..b529c49 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java @@ -0,0 +1,221 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnHtmlTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.google.common.collect.Sets; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.*; + +import static cn.hutool.core.text.CharSequenceUtil.*; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.hutool.core.util.RandomUtil.randomInt; + +/** + * 代码生成器的 Builder,负责: + * 1. 将数据库的表 {@link TableInfo} 定义,构建成 {@link CodegenTableDO} + * 2. 将数据库的列 {@link TableField} 构定义,建成 {@link CodegenColumnDO} + */ +@Component +public class CodegenBuilder { + + /** + * 字段名与 {@link CodegenColumnListConditionEnum} 的默认映射 + * 注意,字段的匹配以后缀的方式 + */ + private static final Map COLUMN_LIST_OPERATION_CONDITION_MAPPINGS = + MapUtil.builder() + .put("name", CodegenColumnListConditionEnum.LIKE) + .put("time", CodegenColumnListConditionEnum.BETWEEN) + .put("date", CodegenColumnListConditionEnum.BETWEEN) + .build(); + + /** + * 字段名与 {@link CodegenColumnHtmlTypeEnum} 的默认映射 + * 注意,字段的匹配以后缀的方式 + */ + private static final Map COLUMN_HTML_TYPE_MAPPINGS = + MapUtil.builder() + .put("status", CodegenColumnHtmlTypeEnum.RADIO) + .put("sex", CodegenColumnHtmlTypeEnum.RADIO) + .put("type", CodegenColumnHtmlTypeEnum.SELECT) + .put("image", CodegenColumnHtmlTypeEnum.IMAGE_UPLOAD) + .put("file", CodegenColumnHtmlTypeEnum.FILE_UPLOAD) + .put("content", CodegenColumnHtmlTypeEnum.EDITOR) + .put("description", CodegenColumnHtmlTypeEnum.EDITOR) + .put("demo", CodegenColumnHtmlTypeEnum.EDITOR) + .put("time", CodegenColumnHtmlTypeEnum.DATETIME) + .put("date", CodegenColumnHtmlTypeEnum.DATETIME) + .build(); + + /** + * 多租户编号的字段名 + */ + public static final String TENANT_ID_FIELD = "tenantId"; + /** + * {@link cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO} 的字段 + */ + public static final Set BASE_DO_FIELDS = new HashSet<>(); + /** + * 新增操作,不需要传递的字段 + */ + private static final Set CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); + /** + * 修改操作,不需要传递的字段 + */ + private static final Set UPDATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet(); + /** + * 列表操作的条件,不需要传递的字段 + */ + private static final Set LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id"); + /** + * 列表操作的结果,不需要返回的字段 + */ + private static final Set LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet(); + + static { + Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName())); + BASE_DO_FIELDS.add(TENANT_ID_FIELD); + // 处理 OPERATION 相关的字段 + CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是可能需要传递的 + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS); + LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是需要返回的 + } + + public CodegenTableDO buildTable(TableInfo tableInfo) { + CodegenTableDO table = CodegenConvert.INSTANCE.convert(tableInfo); + initTableDefault(table); + return table; + } + + /** + * 初始化 Table 表的默认字段 + * + * @param table 表定义 + */ + private void initTableDefault(CodegenTableDO table) { + // 以 system_dept 举例子。moduleName 为 system、businessName 为 dept、className 为 Dept + // 如果希望以 System 前缀,则可以手动在【代码生成 - 修改生成配置 - 基本信息】,将实体类名称改为 SystemDept 即可 + String tableName = table.getTableName().toLowerCase(); + // 第一步,_ 前缀的前面,作为 module 名字;第二步,moduleName 必须小写; + table.setModuleName(subBefore(tableName, '_', false).toLowerCase()); + // 第一步,第一个 _ 前缀的后面,作为 module 名字; 第二步,可能存在多个 _ 的情况,转换成驼峰; 第三步,businessName 必须小写; + table.setBusinessName(toCamelCase(subAfter(tableName, '_', false)).toLowerCase()); + // 驼峰 + 首字母大写;第一步,第一个 _ 前缀的后面,作为 class 名字;第二步,驼峰命名 + table.setClassName(upperFirst(toCamelCase(subAfter(tableName, '_', false)))); + // 去除结尾的表,作为类描述 + table.setClassComment(StrUtil.removeSuffixIgnoreCase(table.getTableComment(), "表")); + table.setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); + } + + public List buildColumns(Long tableId, List tableFields) { + List columns = CodegenConvert.INSTANCE.convertList(tableFields); + int index = 1; + for (CodegenColumnDO column : columns) { + column.setTableId(tableId); + column.setOrdinalPosition(index++); + // 特殊处理:Byte => Integer + if (Byte.class.getSimpleName().equals(column.getJavaType())) { + column.setJavaType(Integer.class.getSimpleName()); + } + // 初始化 Column 列的默认字段 + processColumnOperation(column); // 处理 CRUD 相关的字段的默认值 + processColumnUI(column); // 处理 UI 相关的字段的默认值 + processColumnExample(column); // 处理字段的 swagger example 示例 + } + return columns; + } + + private void processColumnOperation(CodegenColumnDO column) { + // 处理 createOperation 字段 + column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + && !column.getPrimaryKey()); // 对于主键,创建时无需传递 + // 处理 updateOperation 字段 + column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + || column.getPrimaryKey()); // 对于主键,更新时需要传递 + // 处理 listOperation 字段 + column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField()) + && !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递 + // 处理 listOperationCondition 字段 + COLUMN_LIST_OPERATION_CONDITION_MAPPINGS.entrySet().stream() + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey())) + .findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition())); + if (column.getListOperationCondition() == null) { + column.setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()); + } + // 处理 listOperationResult 字段 + column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField())); + } + + private void processColumnUI(CodegenColumnDO column) { + // 基于后缀进行匹配 + COLUMN_HTML_TYPE_MAPPINGS.entrySet().stream() + .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey())) + .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType())); + // 如果是 Boolean 类型时,设置为 radio 类型. + if (Boolean.class.getSimpleName().equals(column.getJavaType())) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType()); + } + // 如果是 LocalDateTime 类型,则设置为 datetime 类型 + if (LocalDateTime.class.getSimpleName().equals(column.getJavaType())) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType()); + } + // 兜底,设置默认为 input 类型 + if (column.getHtmlType() == null) { + column.setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType()); + } + } + + /** + * 处理字段的 swagger example 示例 + * + * @param column 字段 + */ + private void processColumnExample(CodegenColumnDO column) { + // id、price、count 等可能是整数的后缀 + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "id", "price", "count")) { + column.setExample(String.valueOf(randomInt(1, Short.MAX_VALUE))); + return; + } + // name + if (StrUtil.endWithIgnoreCase(column.getJavaField(), "name")) { + column.setExample(randomEle(new String[]{"张三", "李四", "王五", "赵六", "芋艿"})); + return; + } + // status + if (StrUtil.endWithAnyIgnoreCase(column.getJavaField(), "status", "type")) { + column.setExample(randomEle(new String[]{"1", "2"})); + return; + } + // url + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "url")) { + column.setExample("https://www.iocoder.cn"); + return; + } + // reason + if (StrUtil.endWithIgnoreCase(column.getColumnName(), "reason")) { + column.setExample(randomEle(new String[]{"不喜欢", "不对", "不好", "不香"})); + return; + } + // description、memo、remark + if (StrUtil.endWithAnyIgnoreCase(column.getColumnName(), "description", "memo", "remark")) { + column.setExample(randomEle(new String[]{"你猜", "随便", "你说的对"})); + return; + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java new file mode 100644 index 0000000..03f286e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java @@ -0,0 +1,519 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.template.TemplateConfig; +import cn.hutool.extra.template.TemplateEngine; +import cn.hutool.extra.template.engine.velocity.VelocityEngine; +import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Maps; +import com.google.common.collect.Table; +import lombok.Setter; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; + +import static cn.hutool.core.map.MapUtil.getStr; +import static cn.hutool.core.text.CharSequenceUtil.*; + +/** + * 代码生成的引擎,用于具体生成代码 + * 目前基于 {@link org.apache.velocity.app.Velocity} 模板引擎实现 + * + * 考虑到 Java 模板引擎的框架非常多,Freemarker、Velocity、Thymeleaf 等等,所以我们采用 hutool 封装的 {@link cn.hutool.extra.template.Template} 抽象 + * + * @author 芋道源码 + */ +@Component +public class CodegenEngine { + + /** + * 后端的模板配置 + * + * key:模板在 resources 的地址 + * value:生成的路径 + */ + private static final Map SERVER_TEMPLATES = MapUtil.builder(new LinkedHashMap<>()) // 有序 + // Java module-biz Main + .put(javaTemplatePath("controller/vo/pageReqVO"), javaModuleImplVOFilePath("PageReqVO")) + .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO")) + .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO")) + .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO")) + .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath()) + .put(javaTemplatePath("dal/do"), + javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO")) + .put(javaTemplatePath("dal/do_sub"), // 特殊:主子表专属逻辑 + javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${subTable.className}DO")) + .put(javaTemplatePath("dal/mapper"), + javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${table.className}Mapper")) + .put(javaTemplatePath("dal/mapper_sub"), // 特殊:主子表专属逻辑 + javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${subTable.className}Mapper")) + .put(javaTemplatePath("dal/mapper.xml"), mapperXmlFilePath()) + .put(javaTemplatePath("service/serviceImpl"), + javaModuleImplMainFilePath("service/${table.businessName}/${table.className}ServiceImpl")) + .put(javaTemplatePath("service/service"), + javaModuleImplMainFilePath("service/${table.businessName}/${table.className}Service")) + // Java module-biz Test + .put(javaTemplatePath("test/serviceTest"), + javaModuleImplTestFilePath("service/${table.businessName}/${table.className}ServiceImplTest")) + // Java module-api Main + .put(javaTemplatePath("enums/errorcode"), javaModuleApiMainFilePath("enums/ErrorCodeConstants_手动操作")) + // SQL + .put("codegen/sql/sql.vm", "sql/sql.sql") + .put("codegen/sql/h2.vm", "sql/h2.sql") + .build(); + + /** + * 后端的配置模版 + * + * key1:UI 模版的类型 {@link CodegenFrontTypeEnum#getType()} + * key2:模板在 resources 的地址 + * value:生成的路径 + */ + private static final Table FRONT_TEMPLATES = ImmutableTable.builder() + // Vue2 标准模版 + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/index.vue"), + vueFilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("api/api.js"), + vueFilePath("api/${table.moduleName}/${table.businessName}/index.js")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/form.vue"), + vueFilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑 + vueFilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + // Vue3 标准模版 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + // Vue3 Schema 模版 + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/data.ts"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts")) + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/form.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue")) + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + // Vue3 vben 模版 + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/data.ts"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/form.vue"), + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Modal.vue")) + .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + .build(); + + @Resource + private CodegenProperties codegenProperties; + + /** + * 是否使用 jakarta 包,用于解决 Spring Boot 2.X 和 3.X 的兼容性问题 + * + * true - 使用 jakarta.validation.constraints.* + * false - 使用 javax.validation.constraints.* + */ + @Setter // 允许设置的原因,是因为单测需要手动改变 + private Boolean jakartaEnable; + + /** + * 模板引擎,由 hutool 实现 + */ + private final TemplateEngine templateEngine; + /** + * 全局通用变量映射 + */ + private final Map globalBindingMap = new HashMap<>(); + + public CodegenEngine() { + // 初始化 TemplateEngine 属性 + TemplateConfig config = new TemplateConfig(); + config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH); + this.templateEngine = new VelocityEngine(config); + // 设置 javaxEnable,按照是否使用 JDK17 来判断 + this.jakartaEnable = SystemUtil.getJavaInfo().isJavaVersionAtLeast(1700); // 17.00 * 100 + } + + @PostConstruct + @VisibleForTesting + void initGlobalBindingMap() { + // 全局配置 + globalBindingMap.put("basePackage", codegenProperties.getBasePackage()); + globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage() + + '.' + "framework"); // 用于后续获取测试类的 package 地址 + globalBindingMap.put("jakartaPackage", jakartaEnable ? "jakarta" : "javax"); + // 全局 Java Bean + globalBindingMap.put("CommonResultClassName", CommonResult.class.getName()); + globalBindingMap.put("PageResultClassName", PageResult.class.getName()); + // VO 类,独有字段 + globalBindingMap.put("PageParamClassName", PageParam.class.getName()); + globalBindingMap.put("DictFormatClassName", DictFormat.class.getName()); + // DO 类,独有字段 + globalBindingMap.put("BaseDOClassName", BaseDO.class.getName()); + globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS); + globalBindingMap.put("QueryWrapperClassName", LambdaQueryWrapperX.class.getName()); + globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName()); + // Util 工具类 + globalBindingMap.put("ServiceExceptionUtilClassName", ServiceExceptionUtil.class.getName()); + globalBindingMap.put("DateUtilsClassName", DateUtils.class.getName()); + globalBindingMap.put("ExcelUtilsClassName", ExcelUtils.class.getName()); + globalBindingMap.put("LocalDateTimeUtilsClassName", LocalDateTimeUtils.class.getName()); + globalBindingMap.put("ObjectUtilsClassName", ObjectUtils.class.getName()); + globalBindingMap.put("DictConvertClassName", DictConvert.class.getName()); + globalBindingMap.put("ApiAccessLogClassName", ApiAccessLog.class.getName()); + globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName()); + globalBindingMap.put("BeanUtils", BeanUtils.class.getName()); + } + + /** + * 生成代码 + * + * @param table 表定义 + * @param columns table 的字段定义数组 + * @param subTables 子表数组,当且仅当主子表时使用 + * @param subColumnsList subTables 的字段定义数组 + * @return 生成的代码,key 是路径,value 是对应代码 + */ + public Map execute(CodegenTableDO table, List columns, + List subTables, List> subColumnsList) { + // 1.1 初始化 bindMap 上下文 + Map bindingMap = initBindingMap(table, columns, subTables, subColumnsList); + // 1.2 获得模版 + Map templates = getTemplates(table.getFrontType()); + + // 2. 执行生成 + Map result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序 + templates.forEach((vmPath, filePath) -> { + // 2.1 特殊:主子表专属逻辑 + if (isSubTemplate(vmPath)) { + generateSubCode(table, subTables, result, vmPath, filePath, bindingMap); + return; + // 2.2 特殊:树表专属逻辑 + } else if (isPageReqVOTemplate(vmPath)) { + // 减少多余的类生成,例如说 PageVO.java 类 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + return; + } + } else if (isListReqVOTemplate(vmPath)) { + // 减少多余的类生成,例如说 ListVO.java 类 + if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + return; + } + } + // 2.3 默认生成 + generateCode(result, vmPath, filePath, bindingMap); + }); + return result; + } + + private void generateCode(Map result, String vmPath, + String filePath, Map bindingMap) { + filePath = formatFilePath(filePath, bindingMap); + String content = templateEngine.getTemplate(vmPath).render(bindingMap); + // 格式化代码 + content = prettyCode(content); + result.put(filePath, content); + } + + private void generateSubCode(CodegenTableDO table, List subTables, + Map result, String vmPath, + String filePath, Map bindingMap) { + // 没有子表,所以不生成 + if (CollUtil.isEmpty(subTables)) { + return; + } + // 主子表的模式匹配。目的:过滤掉个性化的模版 + if (vmPath.contains("_normal") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_NORMAL.getType())) { + return; + } + if (vmPath.contains("_erp") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_ERP.getType())) { + return; + } + if (vmPath.contains("_inner") + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_INNER.getType())) { + return; + } + + // 逐个生成 + for (int i = 0; i < subTables.size(); i++) { + bindingMap.put("subIndex", i); + generateCode(result, vmPath, filePath, bindingMap); + } + bindingMap.remove("subIndex"); + } + + /** + * 格式化生成后的代码 + * + * 因为尽量让 vm 模版简单,所以统一的处理都在这个方法。 + * 如果不处理,Vue 的 Pretty 格式校验可能会报错 + * + * @param content 格式化前的代码 + * @return 格式化后的代码 + */ + private String prettyCode(String content) { + // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错 + content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }"); + // Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到 + if (StrUtil.count(content, "dateFormatter") == 1) { + content = StrUtils.removeLineContains(content, "dateFormatter"); + } + // Vue2 界面:修正 $refs + if (StrUtil.count(content, "this.refs") >= 1) { + content = content.replace("this.refs", "this.$refs"); + } + // Vue 界面:去除多的 dict 相关,只有一个的情况下,说明没使用到 + if (StrUtil.count(content, "getIntDictOptions") == 1) { + content = content.replace("getIntDictOptions, ", ""); + } + if (StrUtil.count(content, "getStrDictOptions") == 1) { + content = content.replace("getStrDictOptions, ", ""); + } + if (StrUtil.count(content, "getBoolDictOptions") == 1) { + content = content.replace("getBoolDictOptions, ", ""); + } + if (StrUtil.count(content, "DICT_TYPE.") == 0) { + content = StrUtils.removeLineContains(content, "DICT_TYPE"); + } + return content; + } + + private Map initBindingMap(CodegenTableDO table, List columns, + List subTables, List> subColumnsList) { + // 创建 bindingMap + Map bindingMap = new HashMap<>(globalBindingMap); + bindingMap.put("table", table); + bindingMap.put("columns", columns); + bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段 + bindingMap.put("sceneEnum", CodegenSceneEnum.valueOf(table.getScene())); + + // className 相关 + // 去掉指定前缀,将 TestDictType 转换成 DictType. 因为在 create 等方法后,不需要带上 Test 前缀 + String simpleClassName = equalsAnyIgnoreCase(table.getClassName(), table.getModuleName()) ? table.getClassName() + : removePrefix(table.getClassName(), upperFirst(table.getModuleName())); + bindingMap.put("simpleClassName", simpleClassName); + bindingMap.put("simpleClassName_underlineCase", toUnderlineCase(simpleClassName)); // 将 DictType 转换成 dict_type + bindingMap.put("classNameVar", lowerFirst(simpleClassName)); // 将 DictType 转换成 dictType,用于变量 + // 将 DictType 转换成 dict-type + String simpleClassNameStrikeCase = toSymbolCase(simpleClassName, '-'); + bindingMap.put("simpleClassName_strikeCase", simpleClassNameStrikeCase); + // permission 前缀 + bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase); + + // 特殊:树表专属逻辑 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) { + CodegenColumnDO treeParentColumn = CollUtil.findOne(columns, + column -> Objects.equals(column.getId(), table.getTreeParentColumnId())); + bindingMap.put("treeParentColumn", treeParentColumn); + bindingMap.put("treeParentColumn_javaField_underlineCase", toUnderlineCase(treeParentColumn.getJavaField())); + CodegenColumnDO treeNameColumn = CollUtil.findOne(columns, + column -> Objects.equals(column.getId(), table.getTreeNameColumnId())); + bindingMap.put("treeNameColumn", treeNameColumn); + bindingMap.put("treeNameColumn_javaField_underlineCase", toUnderlineCase(treeNameColumn.getJavaField())); + } + + // 特殊:主子表专属逻辑 + if (CollUtil.isNotEmpty(subTables)) { + // 创建 bindingMap + bindingMap.put("subTables", subTables); + bindingMap.put("subColumnsList", subColumnsList); + List subPrimaryColumns = new ArrayList<>(); + List subJoinColumns = new ArrayList<>(); + List subJoinColumnStrikeCases = new ArrayList<>(); + List subSimpleClassNames = new ArrayList<>(); + List subClassNameVars = new ArrayList<>(); + List simpleClassNameUnderlineCases = new ArrayList<>(); + List subSimpleClassNameStrikeCases = new ArrayList<>(); + for (int i = 0; i < subTables.size(); i++) { + CodegenTableDO subTable = subTables.get(i); + List subColumns = subColumnsList.get(i); + subPrimaryColumns.add(CollectionUtils.findFirst(subColumns, CodegenColumnDO::getPrimaryKey)); // + CodegenColumnDO subColumn = CollectionUtils.findFirst(subColumns, // 关联的字段 + column -> Objects.equals(column.getId(), subTable.getSubJoinColumnId())); + subJoinColumns.add(subColumn); + subJoinColumnStrikeCases.add(toSymbolCase(subColumn.getJavaField(), '-')); // 将 DictType 转换成 dict-type + // className 相关 + String subSimpleClassName = removePrefix(subTable.getClassName(), upperFirst(subTable.getModuleName())); + subSimpleClassNames.add(subSimpleClassName); + simpleClassNameUnderlineCases.add(toUnderlineCase(subSimpleClassName)); // 将 DictType 转换成 dict_type + subClassNameVars.add(lowerFirst(subSimpleClassName)); // 将 DictType 转换成 dictType,用于变量 + subSimpleClassNameStrikeCases.add(toSymbolCase(subSimpleClassName, '-')); // 将 DictType 转换成 dict-type + } + bindingMap.put("subPrimaryColumns", subPrimaryColumns); + bindingMap.put("subJoinColumns", subJoinColumns); + bindingMap.put("subJoinColumn_strikeCases", subJoinColumnStrikeCases); + bindingMap.put("subSimpleClassNames", subSimpleClassNames); + bindingMap.put("simpleClassNameUnderlineCases", simpleClassNameUnderlineCases); + bindingMap.put("subClassNameVars", subClassNameVars); + bindingMap.put("subSimpleClassName_strikeCases", subSimpleClassNameStrikeCases); + } + return bindingMap; + } + + private Map getTemplates(Integer frontType) { + Map templates = new LinkedHashMap<>(); + templates.putAll(SERVER_TEMPLATES); + templates.putAll(FRONT_TEMPLATES.row(frontType)); + return templates; + } + + @SuppressWarnings("unchecked") + private String formatFilePath(String filePath, Map bindingMap) { + filePath = StrUtil.replace(filePath, "${basePackage}", + getStr(bindingMap, "basePackage").replaceAll("\\.", "/")); + filePath = StrUtil.replace(filePath, "${classNameVar}", + getStr(bindingMap, "classNameVar")); + filePath = StrUtil.replace(filePath, "${simpleClassName}", + getStr(bindingMap, "simpleClassName")); + // sceneEnum 包含的字段 + CodegenSceneEnum sceneEnum = (CodegenSceneEnum) bindingMap.get("sceneEnum"); + filePath = StrUtil.replace(filePath, "${sceneEnum.prefixClass}", sceneEnum.getPrefixClass()); + filePath = StrUtil.replace(filePath, "${sceneEnum.basePackage}", sceneEnum.getBasePackage()); + // table 包含的字段 + CodegenTableDO table = (CodegenTableDO) bindingMap.get("table"); + filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName()); + filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName()); + filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName()); + // 特殊:主子表专属逻辑 + Integer subIndex = (Integer) bindingMap.get("subIndex"); + if (subIndex != null) { + CodegenTableDO subTable = ((List) bindingMap.get("subTables")).get(subIndex); + filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName()); + filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName()); + filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName()); + filePath = StrUtil.replace(filePath, "${subSimpleClassName}", + ((List) bindingMap.get("subSimpleClassNames")).get(subIndex)); + } + return filePath; + } + + private static String javaTemplatePath(String path) { + return "codegen/java/" + path + ".vm"; + } + + private static String javaModuleImplVOFilePath(String path) { + return javaModuleFilePath("controller/${sceneEnum.basePackage}/${table.businessName}/" + + "vo/${sceneEnum.prefixClass}${table.className}" + path, "biz", "main"); + } + + private static String javaModuleImplControllerFilePath() { + return javaModuleFilePath("controller/${sceneEnum.basePackage}/${table.businessName}/" + + "${sceneEnum.prefixClass}${table.className}Controller", "biz", "main"); + } + + private static String javaModuleImplMainFilePath(String path) { + return javaModuleFilePath(path, "biz", "main"); + } + + private static String javaModuleApiMainFilePath(String path) { + return javaModuleFilePath(path, "api", "main"); + } + + private static String javaModuleImplTestFilePath(String path) { + return javaModuleFilePath(path, "biz", "test"); + } + + private static String javaModuleFilePath(String path, String module, String src) { + return "yudao-module-${table.moduleName}/" + // 顶级模块 + "yudao-module-${table.moduleName}-" + module + "/" + // 子模块 + "src/" + src + "/java/${basePackage}/module/${table.moduleName}/" + path + ".java"; + } + + private static String mapperXmlFilePath() { + return "yudao-module-${table.moduleName}/" + // 顶级模块 + "yudao-module-${table.moduleName}-biz/" + // 子模块 + "src/main/resources/mapper/${table.businessName}/${table.className}Mapper.xml"; + } + + private static String vueTemplatePath(String path) { + return "codegen/vue/" + path + ".vm"; + } + + private static String vueFilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-vue2/" + // 顶级目录 + "src/" + path; + } + + private static String vue3TemplatePath(String path) { + return "codegen/vue3/" + path + ".vm"; + } + + private static String vue3FilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-vue3/" + // 顶级目录 + "src/" + path; + } + + private static String vue3SchemaTemplatePath(String path) { + return "codegen/vue3_schema/" + path + ".vm"; + } + + private static String vue3VbenTemplatePath(String path) { + return "codegen/vue3_vben/" + path + ".vm"; + } + + private static boolean isSubTemplate(String path) { + return path.contains("_sub"); + } + + private static boolean isPageReqVOTemplate(String path) { + return path.contains("pageReqVO"); + } + + private static boolean isListReqVOTemplate(String path) { + return path.contains("listReqVO"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java new file mode 100644 index 0000000..a697902 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigService.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.infra.service.config; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; + +import javax.validation.Valid; + +/** + * 参数配置 Service 接口 + * + * @author 芋道源码 + */ +public interface ConfigService { + + /** + * 创建参数配置 + * + * @param createReqVO 创建信息 + * @return 配置编号 + */ + Long createConfig(@Valid ConfigSaveReqVO createReqVO); + + /** + * 更新参数配置 + * + * @param updateReqVO 更新信息 + */ + void updateConfig(@Valid ConfigSaveReqVO updateReqVO); + + /** + * 删除参数配置 + * + * @param id 配置编号 + */ + void deleteConfig(Long id); + + /** + * 获得参数配置 + * + * @param id 配置编号 + * @return 参数配置 + */ + ConfigDO getConfig(Long id); + + /** + * 根据参数键,获得参数配置 + * + * @param key 配置键 + * @return 参数配置 + */ + ConfigDO getConfigByKey(String key); + + /** + * 获得参数配置分页列表 + * + * @param reqVO 分页条件 + * @return 分页列表 + */ + PageResult getConfigPage(@Valid ConfigPageReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java new file mode 100644 index 0000000..6d14ad9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImpl.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.infra.service.config; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.convert.config.ConfigConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigMapper; +import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 参数配置 Service 实现类 + */ +@Service +@Slf4j +@Validated +public class ConfigServiceImpl implements ConfigService { + + @Resource + private ConfigMapper configMapper; + + @Override + public Long createConfig(ConfigSaveReqVO createReqVO) { + // 校验参数配置 key 的唯一性 + validateConfigKeyUnique(null, createReqVO.getKey()); + + // 插入参数配置 + ConfigDO config = ConfigConvert.INSTANCE.convert(createReqVO); + config.setType(ConfigTypeEnum.CUSTOM.getType()); + configMapper.insert(config); + return config.getId(); + } + + @Override + public void updateConfig(ConfigSaveReqVO updateReqVO) { + // 校验自己存在 + validateConfigExists(updateReqVO.getId()); + // 校验参数配置 key 的唯一性 + validateConfigKeyUnique(updateReqVO.getId(), updateReqVO.getKey()); + + // 更新参数配置 + ConfigDO updateObj = ConfigConvert.INSTANCE.convert(updateReqVO); + configMapper.updateById(updateObj); + } + + @Override + public void deleteConfig(Long id) { + // 校验配置存在 + ConfigDO config = validateConfigExists(id); + // 内置配置,不允许删除 + if (ConfigTypeEnum.SYSTEM.getType().equals(config.getType())) { + throw exception(CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE); + } + // 删除 + configMapper.deleteById(id); + } + + @Override + public ConfigDO getConfig(Long id) { + return configMapper.selectById(id); + } + + @Override + public ConfigDO getConfigByKey(String key) { + return configMapper.selectByKey(key); + } + + @Override + public PageResult getConfigPage(ConfigPageReqVO pageReqVO) { + return configMapper.selectPage(pageReqVO); + } + + @VisibleForTesting + public ConfigDO validateConfigExists(Long id) { + if (id == null) { + return null; + } + ConfigDO config = configMapper.selectById(id); + if (config == null) { + throw exception(CONFIG_NOT_EXISTS); + } + return config; + } + + @VisibleForTesting + public void validateConfigKeyUnique(Long id, String key) { + ConfigDO config = configMapper.selectByKey(key); + if (config == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的参数配置 + if (id == null) { + throw exception(CONFIG_KEY_DUPLICATE); + } + if (!config.getId().equals(id)) { + throw exception(CONFIG_KEY_DUPLICATE); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java new file mode 100644 index 0000000..2838f44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigService.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 数据源配置 Service 接口 + * + * @author 芋道源码 + */ +public interface DataSourceConfigService { + + /** + * 创建数据源配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDataSourceConfig(@Valid DataSourceConfigSaveReqVO createReqVO); + + /** + * 更新数据源配置 + * + * @param updateReqVO 更新信息 + */ + void updateDataSourceConfig(@Valid DataSourceConfigSaveReqVO updateReqVO); + + /** + * 删除数据源配置 + * + * @param id 编号 + */ + void deleteDataSourceConfig(Long id); + + /** + * 获得数据源配置 + * + * @param id 编号 + * @return 数据源配置 + */ + DataSourceConfigDO getDataSourceConfig(Long id); + + /** + * 获得数据源配置列表 + * + * @return 数据源配置列表 + */ + List getDataSourceConfigList(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java new file mode 100644 index 0000000..c5bcece --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_OK; + +/** + * 数据源配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DataSourceConfigServiceImpl implements DataSourceConfigService { + + @Resource + private DataSourceConfigMapper dataSourceConfigMapper; + + @Resource + private DynamicDataSourceProperties dynamicDataSourceProperties; + + @Override + public Long createDataSourceConfig(DataSourceConfigSaveReqVO createReqVO) { + DataSourceConfigDO config = BeanUtils.toBean(createReqVO, DataSourceConfigDO.class); + validateConnectionOK(config); + + // 插入 + dataSourceConfigMapper.insert(config); + // 返回 + return config.getId(); + } + + @Override + public void updateDataSourceConfig(DataSourceConfigSaveReqVO updateReqVO) { + // 校验存在 + validateDataSourceConfigExists(updateReqVO.getId()); + DataSourceConfigDO updateObj = BeanUtils.toBean(updateReqVO, DataSourceConfigDO.class); + validateConnectionOK(updateObj); + + // 更新 + dataSourceConfigMapper.updateById(updateObj); + } + + @Override + public void deleteDataSourceConfig(Long id) { + // 校验存在 + validateDataSourceConfigExists(id); + // 删除 + dataSourceConfigMapper.deleteById(id); + } + + private void validateDataSourceConfigExists(Long id) { + if (dataSourceConfigMapper.selectById(id) == null) { + throw exception(DATA_SOURCE_CONFIG_NOT_EXISTS); + } + } + + @Override + public DataSourceConfigDO getDataSourceConfig(Long id) { + // 如果 id 为 0,默认为 master 的数据源 + if (Objects.equals(id, DataSourceConfigDO.ID_MASTER)) { + return buildMasterDataSourceConfig(); + } + // 从 DB 中读取 + return dataSourceConfigMapper.selectById(id); + } + + @Override + public List getDataSourceConfigList() { + List result = dataSourceConfigMapper.selectList(); + // 补充 master 数据源 + result.add(0, buildMasterDataSourceConfig()); + return result; + } + + private void validateConnectionOK(DataSourceConfigDO config) { + boolean success = JdbcUtils.isConnectionOK(config.getUrl(), config.getUsername(), config.getPassword()); + if (!success) { + throw exception(DATA_SOURCE_CONFIG_NOT_OK); + } + } + + private DataSourceConfigDO buildMasterDataSourceConfig() { + String primary = dynamicDataSourceProperties.getPrimary(); + DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary); + return new DataSourceConfigDO().setId(DataSourceConfigDO.ID_MASTER).setName(primary) + .setUrl(dataSourceProperty.getUrl()) + .setUsername(dataSourceProperty.getUsername()) + .setPassword(dataSourceProperty.getPassword()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableService.java new file mode 100644 index 0000000..9fd2ee9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableService.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import com.baomidou.mybatisplus.generator.config.po.TableInfo; + +import java.util.List; + +/** + * 数据库表 Service + * + * @author 芋道源码 + */ +public interface DatabaseTableService { + + /** + * 获得表列表,基于表名称 + 表描述进行模糊匹配 + * + * @param dataSourceConfigId 数据源配置的编号 + * @param nameLike 表名称,模糊匹配 + * @param commentLike 表描述,模糊匹配 + * @return 表列表 + */ + List getTableList(Long dataSourceConfigId, String nameLike, String commentLike); + + /** + * 获得指定表名 + * + * @param dataSourceConfigId 数据源配置的编号 + * @param tableName 表名称 + * @return 表 + */ + TableInfo getTable(Long dataSourceConfigId, String tableName); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java new file mode 100644 index 0000000..deb4aab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.generator.config.DataSourceConfig; +import com.baomidou.mybatisplus.generator.config.GlobalConfig; +import com.baomidou.mybatisplus.generator.config.StrategyConfig; +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.DateType; +import com.baomidou.mybatisplus.generator.query.SQLQuery; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 数据库表 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class DatabaseTableServiceImpl implements DatabaseTableService { + + @Resource + private DataSourceConfigService dataSourceConfigService; + + @Override + public List getTableList(Long dataSourceConfigId, String nameLike, String commentLike) { + List tables = getTableList0(dataSourceConfigId, null); + return tables.stream().filter(tableInfo -> (StrUtil.isEmpty(nameLike) || tableInfo.getName().contains(nameLike)) + && (StrUtil.isEmpty(commentLike) || tableInfo.getComment().contains(commentLike))) + .collect(Collectors.toList()); + } + + @Override + public TableInfo getTable(Long dataSourceConfigId, String name) { + return CollUtil.getFirst(getTableList0(dataSourceConfigId, name)); + } + + private List getTableList0(Long dataSourceConfigId, String name) { + // 获得数据源配置 + DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(dataSourceConfigId); + Assert.notNull(config, "数据源({}) 不存在!", dataSourceConfigId); + DbType dbType = JdbcUtils.getDbType(config.getUrl()); + + // 使用 MyBatis Plus Generator 解析表结构 + DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig.Builder(config.getUrl(), config.getUsername(), + config.getPassword()); + if (Objects.equals(dbType, DbType.SQL_SERVER)) { // 特殊:SQLServer jdbc 非标准,参见 https://github.com/baomidou/mybatis-plus/issues/5419 + dataSourceConfigBuilder.databaseQueryClass(SQLQuery.class); + } + StrategyConfig.Builder strategyConfig = new StrategyConfig.Builder().enableSkipView(); // 忽略视图,业务上一般用不到 + if (StrUtil.isNotEmpty(name)) { + strategyConfig.addInclude(name); + } else { + // 移除工作流和定时任务前缀的表名 + strategyConfig.addExclude("ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+"); + // 移除 ORACLE 相关的系统表 + strategyConfig.addExclude("IMPDP_[\\S\\s]+|ALL_[\\S\\s]+|HS_[\\S\\\\s]+"); + strategyConfig.addExclude("[\\S\\s]+\\$[\\S\\s]+|[\\S\\s]+\\$"); // 表里不能有 $,一般有都是系统的表 + } + + GlobalConfig globalConfig = new GlobalConfig.Builder().dateType(DateType.TIME_PACK).build(); // 只使用 LocalDateTime 类型,不使用 LocalDate + ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfigBuilder.build(), strategyConfig.build(), + null, globalConfig, null); + // 按照名字排序 + List tables = builder.getTableInfoList(); + tables.sort(Comparator.comparing(TableInfo::getName)); + return tables; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactService.java new file mode 100644 index 0000000..e3a1b6d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo01; + +import javax.validation.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * 示例联系人 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo01ContactService { + + /** + * 创建示例联系人 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo01Contact(@Valid Demo01ContactSaveReqVO createReqVO); + + /** + * 更新示例联系人 + * + * @param updateReqVO 更新信息 + */ + void updateDemo01Contact(@Valid Demo01ContactSaveReqVO updateReqVO); + + /** + * 删除示例联系人 + * + * @param id 编号 + */ + void deleteDemo01Contact(Long id); + + /** + * 获得示例联系人 + * + * @param id 编号 + * @return 示例联系人 + */ + Demo01ContactDO getDemo01Contact(Long id); + + /** + * 获得示例联系人分页 + * + * @param pageReqVO 分页查询 + * @return 示例联系人分页 + */ + PageResult getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactServiceImpl.java new file mode 100644 index 0000000..cde4906 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactServiceImpl.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo01; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo01.Demo01ContactMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 示例联系人 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo01ContactServiceImpl implements Demo01ContactService { + + @Resource + private Demo01ContactMapper demo01ContactMapper; + + @Override + public Long createDemo01Contact(Demo01ContactSaveReqVO createReqVO) { + // 插入 + Demo01ContactDO demo01Contact = BeanUtils.toBean(createReqVO, Demo01ContactDO.class); + demo01ContactMapper.insert(demo01Contact); + // 返回 + return demo01Contact.getId(); + } + + @Override + public void updateDemo01Contact(Demo01ContactSaveReqVO updateReqVO) { + // 校验存在 + validateDemo01ContactExists(updateReqVO.getId()); + // 更新 + Demo01ContactDO updateObj = BeanUtils.toBean(updateReqVO, Demo01ContactDO.class); + demo01ContactMapper.updateById(updateObj); + } + + @Override + public void deleteDemo01Contact(Long id) { + // 校验存在 + validateDemo01ContactExists(id); + // 删除 + demo01ContactMapper.deleteById(id); + } + + private void validateDemo01ContactExists(Long id) { + if (demo01ContactMapper.selectById(id) == null) { + throw exception(DEMO01_CONTACT_NOT_EXISTS); + } + } + + @Override + public Demo01ContactDO getDemo01Contact(Long id) { + return demo01ContactMapper.selectById(id); + } + + @Override + public PageResult getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO) { + return demo01ContactMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryService.java new file mode 100644 index 0000000..7980fdb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo02; + +import java.util.*; +import javax.validation.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; + +/** + * 示例分类 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo02CategoryService { + + /** + * 创建示例分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo02Category(@Valid Demo02CategorySaveReqVO createReqVO); + + /** + * 更新示例分类 + * + * @param updateReqVO 更新信息 + */ + void updateDemo02Category(@Valid Demo02CategorySaveReqVO updateReqVO); + + /** + * 删除示例分类 + * + * @param id 编号 + */ + void deleteDemo02Category(Long id); + + /** + * 获得示例分类 + * + * @param id 编号 + * @return 示例分类 + */ + Demo02CategoryDO getDemo02Category(Long id); + + /** + * 获得示例分类列表 + * + * @param listReqVO 查询条件 + * @return 示例分类列表 + */ + List getDemo02CategoryList(Demo02CategoryListReqVO listReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryServiceImpl.java new file mode 100644 index 0000000..7ab4ec5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryServiceImpl.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo02; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo02.Demo02CategoryMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 示例分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo02CategoryServiceImpl implements Demo02CategoryService { + + @Resource + private Demo02CategoryMapper demo02CategoryMapper; + + @Override + public Long createDemo02Category(Demo02CategorySaveReqVO createReqVO) { + // 校验父级编号的有效性 + validateParentDemo02Category(null, createReqVO.getParentId()); + // 校验名字的唯一性 + validateDemo02CategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + Demo02CategoryDO demo02Category = BeanUtils.toBean(createReqVO, Demo02CategoryDO.class); + demo02CategoryMapper.insert(demo02Category); + // 返回 + return demo02Category.getId(); + } + + @Override + public void updateDemo02Category(Demo02CategorySaveReqVO updateReqVO) { + // 校验存在 + validateDemo02CategoryExists(updateReqVO.getId()); + // 校验父级编号的有效性 + validateParentDemo02Category(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验名字的唯一性 + validateDemo02CategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + Demo02CategoryDO updateObj = BeanUtils.toBean(updateReqVO, Demo02CategoryDO.class); + demo02CategoryMapper.updateById(updateObj); + } + + @Override + public void deleteDemo02Category(Long id) { + // 校验存在 + validateDemo02CategoryExists(id); + // 校验是否有子示例分类 + if (demo02CategoryMapper.selectCountByParentId(id) > 0) { + throw exception(DEMO02_CATEGORY_EXITS_CHILDREN); + } + // 删除 + demo02CategoryMapper.deleteById(id); + } + + private void validateDemo02CategoryExists(Long id) { + if (demo02CategoryMapper.selectById(id) == null) { + throw exception(DEMO02_CATEGORY_NOT_EXISTS); + } + } + + private void validateParentDemo02Category(Long id, Long parentId) { + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父示例分类 + if (Objects.equals(id, parentId)) { + throw exception(DEMO02_CATEGORY_PARENT_ERROR); + } + // 2. 父示例分类不存在 + Demo02CategoryDO parentDemo02Category = demo02CategoryMapper.selectById(parentId); + if (parentDemo02Category == null) { + throw exception(DEMO02_CATEGORY_PARENT_NOT_EXITS); + } + // 3. 递归校验父示例分类,如果父示例分类是自己的子示例分类,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentDemo02Category.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(DEMO02_CATEGORY_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父示例分类 + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentDemo02Category = demo02CategoryMapper.selectById(parentId); + if (parentDemo02Category == null) { + break; + } + } + } + + private void validateDemo02CategoryNameUnique(Long id, Long parentId, String name) { + Demo02CategoryDO demo02Category = demo02CategoryMapper.selectByParentIdAndName(parentId, name); + if (demo02Category == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的示例分类 + if (id == null) { + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE); + } + if (!Objects.equals(demo02Category.getId(), id)) { + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE); + } + } + + @Override + public Demo02CategoryDO getDemo02Category(Long id) { + return demo02CategoryMapper.selectById(id); + } + + @Override + public List getDemo02CategoryList(Demo02CategoryListReqVO listReqVO) { + return demo02CategoryMapper.selectList(listReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentService.java new file mode 100644 index 0000000..c9a4c59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentService.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo03; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface Demo03StudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemo03Student(@Valid Demo03StudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateDemo03Student(@Valid Demo03StudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteDemo03Student(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + Demo03StudentDO getDemo03Student(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO); + + + // ==================== 子表(学生课程) ==================== + + /** + * 获得学生课程列表 + * + * @param studentId 学生编号 + * @return 学生课程列表 + */ + List getDemo03CourseListByStudentId(Long studentId); + + /** + * 获得学生课程分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生课程分页 + */ + PageResult getDemo03CoursePage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生课程 + * + * @param demo03Course 创建信息 + * @return 编号 + */ + Long createDemo03Course(@Valid Demo03CourseDO demo03Course); + + /** + * 更新学生课程 + * + * @param demo03Course 更新信息 + */ + void updateDemo03Course(@Valid Demo03CourseDO demo03Course); + + /** + * 删除学生课程 + * + * @param id 编号 + */ + void deleteDemo03Course(Long id); + + /** + * 获得学生课程 + * + * @param id 编号 + * @return 学生课程 + */ + Demo03CourseDO getDemo03Course(Long id); + + // ==================== 子表(学生班级) ==================== + + /** + * 获得学生班级 + * + * @param studentId 学生编号 + * @return 学生班级 + */ + Demo03GradeDO getDemo03GradeByStudentId(Long studentId); + + /** + * 获得学生班级分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生班级分页 + */ + PageResult getDemo03GradePage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生班级 + * + * @param demo03Grade 创建信息 + * @return 编号 + */ + Long createDemo03Grade(@Valid Demo03GradeDO demo03Grade); + + /** + * 更新学生班级 + * + * @param demo03Grade 更新信息 + */ + void updateDemo03Grade(@Valid Demo03GradeDO demo03Grade); + + /** + * 删除学生班级 + * + * @param id 编号 + */ + void deleteDemo03Grade(Long id); + + /** + * 获得学生班级 + * + * @param id 编号 + * @return 学生班级 + */ + Demo03GradeDO getDemo03Grade(Long id); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentServiceImpl.java new file mode 100644 index 0000000..7b69e4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentServiceImpl.java @@ -0,0 +1,217 @@ +package cn.iocoder.yudao.module.infra.service.demo.demo03; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03CourseMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03GradeMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03StudentMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class Demo03StudentServiceImpl implements Demo03StudentService { + + @Resource + private Demo03StudentMapper demo03StudentMapper; + @Resource + private Demo03CourseMapper demo03CourseMapper; + @Resource + private Demo03GradeMapper demo03GradeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createDemo03Student(Demo03StudentSaveReqVO createReqVO) { + // 插入 + Demo03StudentDO demo03Student = BeanUtils.toBean(createReqVO, Demo03StudentDO.class); + demo03StudentMapper.insert(demo03Student); + + // 插入子表 + createDemo03CourseList(demo03Student.getId(), createReqVO.getDemo03Courses()); + createDemo03Grade(demo03Student.getId(), createReqVO.getDemo03Grade()); + // 返回 + return demo03Student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDemo03Student(Demo03StudentSaveReqVO updateReqVO) { + // 校验存在 + validateDemo03StudentExists(updateReqVO.getId()); + // 更新 + Demo03StudentDO updateObj = BeanUtils.toBean(updateReqVO, Demo03StudentDO.class); + demo03StudentMapper.updateById(updateObj); + + // 更新子表 + updateDemo03CourseList(updateReqVO.getId(), updateReqVO.getDemo03Courses()); + updateDemo03Grade(updateReqVO.getId(), updateReqVO.getDemo03Grade()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDemo03Student(Long id) { + // 校验存在 + validateDemo03StudentExists(id); + // 删除 + demo03StudentMapper.deleteById(id); + + // 删除子表 + deleteDemo03CourseByStudentId(id); + deleteDemo03GradeByStudentId(id); + } + + private void validateDemo03StudentExists(Long id) { + if (demo03StudentMapper.selectById(id) == null) { + throw exception(DEMO03_STUDENT_NOT_EXISTS); + } + } + + @Override + public Demo03StudentDO getDemo03Student(Long id) { + return demo03StudentMapper.selectById(id); + } + + @Override + public PageResult getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO) { + return demo03StudentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生课程) ==================== + + @Override + public List getDemo03CourseListByStudentId(Long studentId) { + return demo03CourseMapper.selectListByStudentId(studentId); + } + + private void createDemo03CourseList(Long studentId, List list) { + if (list != null) { + list.forEach(o -> o.setStudentId(studentId)); + } + demo03CourseMapper.insertBatch(list); + } + + private void updateDemo03CourseList(Long studentId, List list) { + deleteDemo03CourseByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createDemo03CourseList(studentId, list); + } + + private void deleteDemo03CourseByStudentId(Long studentId) { + demo03CourseMapper.deleteByStudentId(studentId); + } + + @Override + public PageResult getDemo03CoursePage(PageParam pageReqVO, Long studentId) { + return demo03CourseMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createDemo03Course(Demo03CourseDO demo03Course) { + demo03CourseMapper.insert(demo03Course); + return demo03Course.getId(); + } + + @Override + public void updateDemo03Course(Demo03CourseDO demo03Course) { + demo03CourseMapper.updateById(demo03Course); + } + + @Override + public void deleteDemo03Course(Long id) { + demo03CourseMapper.deleteById(id); + } + + @Override + public Demo03CourseDO getDemo03Course(Long id) { + return demo03CourseMapper.selectById(id); + } + + // ==================== 子表(学生班级) ==================== + + @Override + public Demo03GradeDO getDemo03GradeByStudentId(Long studentId) { + return demo03GradeMapper.selectByStudentId(studentId); + } + + private void createDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) { + if (demo03Grade == null) { + return; + } + demo03Grade.setStudentId(studentId); + demo03GradeMapper.insert(demo03Grade); + } + + private void updateDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) { + if (demo03Grade == null) { + return; + } + demo03Grade.setStudentId(studentId); + demo03Grade.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + demo03GradeMapper.insertOrUpdate(demo03Grade); + } + + private void deleteDemo03GradeByStudentId(Long studentId) { + demo03GradeMapper.deleteByStudentId(studentId); + } + + @Override + public PageResult getDemo03GradePage(PageParam pageReqVO, Long studentId) { + return demo03GradeMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createDemo03Grade(Demo03GradeDO demo03Grade) { + // 校验是否已经存在 + if (demo03GradeMapper.selectByStudentId(demo03Grade.getStudentId()) != null) { + throw exception(DEMO03_GRADE_EXISTS); + } + demo03GradeMapper.insert(demo03Grade); + return demo03Grade.getId(); + } + + @Override + public void updateDemo03Grade(Demo03GradeDO demo03Grade) { + // 校验存在 + validateDemo03GradeExists(demo03Grade.getId()); + // 更新 + demo03GradeMapper.updateById(demo03Grade); + } + + @Override + public void deleteDemo03Grade(Long id) { + // 校验存在 + validateDemo03GradeExists(id); + // 删除 + demo03GradeMapper.deleteById(id); + } + + @Override + public Demo03GradeDO getDemo03Grade(Long id) { + return demo03GradeMapper.selectById(id); + } + + private void validateDemo03GradeExists(Long id) { + if (demo03GradeMapper.selectById(id) == null) { + throw exception(DEMO03_GRADE_NOT_EXISTS); + } + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java new file mode 100644 index 0000000..23a7228 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; + +import javax.validation.Valid; + +/** + * 文件配置 Service 接口 + * + * @author 芋道源码 + */ +public interface FileConfigService { + + /** + * 创建文件配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFileConfig(@Valid FileConfigSaveReqVO createReqVO); + + /** + * 更新文件配置 + * + * @param updateReqVO 更新信息 + */ + void updateFileConfig(@Valid FileConfigSaveReqVO updateReqVO); + + /** + * 更新文件配置为 Master + * + * @param id 编号 + */ + void updateFileConfigMaster(Long id); + + /** + * 删除文件配置 + * + * @param id 编号 + */ + void deleteFileConfig(Long id); + + /** + * 获得文件配置 + * + * @param id 编号 + * @return 文件配置 + */ + FileConfigDO getFileConfig(Long id); + + /** + * 获得文件配置分页 + * + * @param pageReqVO 分页查询 + * @return 文件配置分页 + */ + PageResult getFileConfigPage(FileConfigPageReqVO pageReqVO); + + /** + * 测试文件配置是否正确,通过上传文件 + * + * @param id 编号 + * @return 文件 URL + */ + String testFileConfig(Long id) throws Exception; + + /** + * 获得指定编号的文件客户端 + * + * @param id 配置编号 + * @return 文件客户端 + */ + FileClient getFileClient(Long id); + + /** + * 获得 Master 文件客户端 + * + * @return 文件客户端 + */ + FileClient getMasterFileClient(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java new file mode 100644 index 0000000..7d84bff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientFactory; +import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.time.Duration; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; + +/** + * 文件配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class FileConfigServiceImpl implements FileConfigService { + + private static final Long CACHE_MASTER_ID = 0L; + + /** + * {@link FileClient} 缓存,通过它异步刷新 fileClientFactory + */ + @Getter + private final LoadingCache clientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public FileClient load(Long id) { + FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ? + fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id); + if (config != null) { + fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); + } + return fileClientFactory.getFileClient(null == config ? id : config.getId()); + } + + }); + + @Resource + private FileClientFactory fileClientFactory; + + @Resource + private FileConfigMapper fileConfigMapper; + + @Resource + private Validator validator; + + @Override + public Long createFileConfig(FileConfigSaveReqVO createReqVO) { + FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO) + .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) + .setMaster(false); // 默认非 master + fileConfigMapper.insert(fileConfig); + return fileConfig.getId(); + } + + @Override + public void updateFileConfig(FileConfigSaveReqVO updateReqVO) { + // 校验存在 + FileConfigDO config = validateFileConfigExists(updateReqVO.getId()); + // 更新 + FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) + .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); + fileConfigMapper.updateById(updateObj); + + // 清空缓存 + clearCache(config.getId(), null); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateFileConfigMaster(Long id) { + // 校验存在 + validateFileConfigExists(id); + // 更新其它为非 master + fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false)); + // 更新 + fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); + + // 清空缓存 + clearCache(null, true); + } + + private FileClientConfig parseClientConfig(Integer storage, Map config) { + // 获取配置类 + Class configClass = FileStorageEnum.getByStorage(storage) + .getConfigClass(); + FileClientConfig clientConfig = JsonUtils.parseObject2(JsonUtils.toJsonString(config), configClass); + // 参数校验 + ValidationUtils.validate(validator, clientConfig); + // 设置参数 + return clientConfig; + } + + @Override + public void deleteFileConfig(Long id) { + // 校验存在 + FileConfigDO config = validateFileConfigExists(id); + if (Boolean.TRUE.equals(config.getMaster())) { + throw exception(FILE_CONFIG_DELETE_FAIL_MASTER); + } + // 删除 + fileConfigMapper.deleteById(id); + + // 清空缓存 + clearCache(id, null); + } + + /** + * 清空指定文件配置 + * + * @param id 配置编号 + * @param master 是否主配置 + */ + private void clearCache(Long id, Boolean master) { + if (id != null) { + clientCache.invalidate(id); + } + if (Boolean.TRUE.equals(master)) { + clientCache.invalidate(CACHE_MASTER_ID); + } + } + + private FileConfigDO validateFileConfigExists(Long id) { + FileConfigDO config = fileConfigMapper.selectById(id); + if (config == null) { + throw exception(FILE_CONFIG_NOT_EXISTS); + } + return config; + } + + @Override + public FileConfigDO getFileConfig(Long id) { + return fileConfigMapper.selectById(id); + } + + @Override + public PageResult getFileConfigPage(FileConfigPageReqVO pageReqVO) { + return fileConfigMapper.selectPage(pageReqVO); + } + + @Override + public String testFileConfig(Long id) throws Exception { + // 校验存在 + validateFileConfigExists(id); + // 上传文件 + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + return getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); + } + + @Override + public FileClient getFileClient(Long id) { + return clientCache.getUnchecked(id); + } + + @Override + public FileClient getMasterFileClient() { + return clientCache.getUnchecked(CACHE_MASTER_ID); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java new file mode 100644 index 0000000..3ca9a24 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; + +/** + * 文件 Service 接口 + * + * @author 芋道源码 + */ +public interface FileService { + + /** + * 获得文件分页 + * + * @param pageReqVO 分页查询 + * @return 文件分页 + */ + PageResult getFilePage(FilePageReqVO pageReqVO); + + /** + * 保存文件,并返回文件的访问路径 + * + * @param name 文件名称 + * @param path 文件路径 + * @param content 文件内容 + * @return 文件路径 + */ + String createFile(String name, String path, byte[] content); + + /** + * 创建文件 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFile(FileCreateReqVO createReqVO); + + /** + * 删除文件 + * + * @param id 编号 + */ + void deleteFile(Long id) throws Exception; + + /** + * 获得文件内容 + * + * @param configId 配置编号 + * @param path 文件路径 + * @return 文件内容 + */ + byte[] getFileContent(Long configId, String path) throws Exception; + + /** + * 生成文件预签名地址信息 + * + * @param path 文件路径 + * @return 预签名地址信息 + */ + FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java new file mode 100644 index 0000000..8efa5fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.FilePresignedUrlRespDTO; +import cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; + +/** + * 文件 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class FileServiceImpl implements FileService { + + @Resource + private FileConfigService fileConfigService; + + @Resource + private FileMapper fileMapper; + + @Override + public PageResult getFilePage(FilePageReqVO pageReqVO) { + return fileMapper.selectPage(pageReqVO); + } + + @Override + @SneakyThrows + public String createFile(String name, String path, byte[] content) { + // 计算默认的 path 名 + String type = FileTypeUtils.getMineType(content, name); + if (StrUtil.isEmpty(path)) { + path = FileUtils.generatePath(content, name); + } + // 如果 name 为空,则使用 path 填充 + if (StrUtil.isEmpty(name)) { + name = path; + } + + // 上传到文件存储器 + FileClient client = fileConfigService.getMasterFileClient(); + Assert.notNull(client, "客户端(master) 不能为空"); + String url = client.upload(content, path, type); + + // 保存到数据库 + FileDO file = new FileDO(); + file.setConfigId(client.getId()); + file.setName(name); + file.setPath(path); + file.setUrl(url); + file.setType(type); + file.setSize(content.length); + fileMapper.insert(file); + return url; + } + + @Override + public Long createFile(FileCreateReqVO createReqVO) { + FileDO file = BeanUtils.toBean(createReqVO, FileDO.class); + fileMapper.insert(file); + return file.getId(); + } + + @Override + public void deleteFile(Long id) throws Exception { + // 校验存在 + FileDO file = validateFileExists(id); + + // 从文件存储器中删除 + FileClient client = fileConfigService.getFileClient(file.getConfigId()); + Assert.notNull(client, "客户端({}) 不能为空", file.getConfigId()); + client.delete(file.getPath()); + + // 删除记录 + fileMapper.deleteById(id); + } + + private FileDO validateFileExists(Long id) { + FileDO fileDO = fileMapper.selectById(id); + if (fileDO == null) { + throw exception(FILE_NOT_EXISTS); + } + return fileDO; + } + + @Override + public byte[] getFileContent(Long configId, String path) throws Exception { + FileClient client = fileConfigService.getFileClient(configId); + Assert.notNull(client, "客户端({}) 不能为空", configId); + return client.getContent(path); + } + + @Override + public FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception { + FileClient fileClient = fileConfigService.getMasterFileClient(); + FilePresignedUrlRespDTO presignedObjectUrl = fileClient.getPresignedObjectUrl(path); + return BeanUtils.toBean(presignedObjectUrl, FilePresignedUrlRespVO.class, + object -> object.setConfigId(fileClient.getId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogService.java new file mode 100644 index 0000000..f1e7e7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO; + +/** + * Job 日志 Service 接口 + * + * @author 芋道源码 + */ +public interface JobLogService extends JobLogFrameworkService { + + /** + * 获得定时任务 + * + * @param id 编号 + * @return 定时任务 + */ + JobLogDO getJobLog(Long id); + + /** + * 获得定时任务分页 + * + * @param pageReqVO 分页查询 + * @return 定时任务分页 + */ + PageResult getJobLogPage(JobLogPageReqVO pageReqVO); + + /** + * 清理 exceedDay 天前的任务日志 + * + * @param exceedDay 超过多少天就进行清理 + * @param deleteLimit 清理的间隔条数 + */ + Integer cleanJobLog(Integer exceedDay, Integer deleteLimit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImpl.java new file mode 100644 index 0000000..868fd1b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImpl.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper; +import cn.iocoder.yudao.module.infra.enums.job.JobLogStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +/** + * Job 日志 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class JobLogServiceImpl implements JobLogService { + + @Resource + private JobLogMapper jobLogMapper; + + @Override + public Long createJobLog(Long jobId, LocalDateTime beginTime, + String jobHandlerName, String jobHandlerParam, Integer executeIndex) { + JobLogDO log = JobLogDO.builder().jobId(jobId).handlerName(jobHandlerName) + .handlerParam(jobHandlerParam).executeIndex(executeIndex) + .beginTime(beginTime).status(JobLogStatusEnum.RUNNING.getStatus()).build(); + jobLogMapper.insert(log); + return log.getId(); + } + + @Override + @Async + public void updateJobLogResultAsync(Long logId, LocalDateTime endTime, Integer duration, boolean success, String result) { + try { + JobLogDO updateObj = JobLogDO.builder().id(logId).endTime(endTime).duration(duration) + .status(success ? JobLogStatusEnum.SUCCESS.getStatus() : JobLogStatusEnum.FAILURE.getStatus()) + .result(result).build(); + jobLogMapper.updateById(updateObj); + } catch (Exception ex) { + log.error("[updateJobLogResultAsync][logId({}) endTime({}) duration({}) success({}) result({})]", + logId, endTime, duration, success, result); + } + } + + @Override + @SuppressWarnings("DuplicatedCode") + public Integer cleanJobLog(Integer exceedDay, Integer deleteLimit) { + int count = 0; + LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay); + // 循环删除,直到没有满足条件的数据 + for (int i = 0; i < Short.MAX_VALUE; i++) { + int deleteCount = jobLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit); + count += deleteCount; + // 达到删除预期条数,说明到底了 + if (deleteCount < deleteLimit) { + break; + } + } + return count; + } + + @Override + public JobLogDO getJobLog(Long id) { + return jobLogMapper.selectById(id); + } + + @Override + public PageResult getJobLogPage(JobLogPageReqVO pageReqVO) { + return jobLogMapper.selectPage(pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobService.java new file mode 100644 index 0000000..ff1cca5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobService.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; +import org.quartz.SchedulerException; + +import javax.validation.Valid; + +/** + * 定时任务 Service 接口 + * + * @author 芋道源码 + */ +public interface JobService { + + /** + * 创建定时任务 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createJob(@Valid JobSaveReqVO createReqVO) throws SchedulerException; + + /** + * 更新定时任务 + * + * @param updateReqVO 更新信息 + */ + void updateJob(@Valid JobSaveReqVO updateReqVO) throws SchedulerException; + + /** + * 更新定时任务的状态 + * + * @param id 任务编号 + * @param status 状态 + */ + void updateJobStatus(Long id, Integer status) throws SchedulerException; + + /** + * 触发定时任务 + * + * @param id 任务编号 + */ + void triggerJob(Long id) throws SchedulerException; + + /** + * 同步定时任务 + * + * 目的:自己存储的 Job 信息,强制同步到 Quartz 中 + */ + void syncJob() throws SchedulerException; + + /** + * 删除定时任务 + * + * @param id 编号 + */ + void deleteJob(Long id) throws SchedulerException; + + /** + * 获得定时任务 + * + * @param id 编号 + * @return 定时任务 + */ + JobDO getJob(Long id); + + /** + * 获得定时任务分页 + * + * @param pageReqVO 分页查询 + * @return 定时任务分页 + */ + PageResult getJobPage(JobPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java new file mode 100644 index 0000000..abdb613 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java @@ -0,0 +1,199 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; +import cn.iocoder.yudao.framework.quartz.core.util.CronUtils; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; +import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper; +import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.containsAny; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 定时任务 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class JobServiceImpl implements JobService { + + @Resource + private JobMapper jobMapper; + + @Resource + private SchedulerManager schedulerManager; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createJob(JobSaveReqVO createReqVO) throws SchedulerException { + validateCronExpression(createReqVO.getCronExpression()); + // 1.1 校验唯一性 + if (jobMapper.selectByHandlerName(createReqVO.getHandlerName()) != null) { + throw exception(JOB_HANDLER_EXISTS); + } + // 1.2 校验 JobHandler 是否存在 + validateJobHandlerExists(createReqVO.getHandlerName()); + + // 2. 插入 JobDO + JobDO job = BeanUtils.toBean(createReqVO, JobDO.class); + job.setStatus(JobStatusEnum.INIT.getStatus()); + fillJobMonitorTimeoutEmpty(job); + jobMapper.insert(job); + + // 3.1 添加 Job 到 Quartz 中 + schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(), + createReqVO.getRetryCount(), createReqVO.getRetryInterval()); + // 3.2 更新 JobDO + JobDO updateObj = JobDO.builder().id(job.getId()).status(JobStatusEnum.NORMAL.getStatus()).build(); + jobMapper.updateById(updateObj); + return job.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateJob(JobSaveReqVO updateReqVO) throws SchedulerException { + validateCronExpression(updateReqVO.getCronExpression()); + // 1.1 校验存在 + JobDO job = validateJobExists(updateReqVO.getId()); + // 1.2 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行 + if (!job.getStatus().equals(JobStatusEnum.NORMAL.getStatus())) { + throw exception(JOB_UPDATE_ONLY_NORMAL_STATUS); + } + // 1.3 校验 JobHandler 是否存在 + validateJobHandlerExists(updateReqVO.getHandlerName()); + + // 2. 更新 JobDO + JobDO updateObj = BeanUtils.toBean(updateReqVO, JobDO.class); + fillJobMonitorTimeoutEmpty(updateObj); + jobMapper.updateById(updateObj); + + // 3. 更新 Job 到 Quartz 中 + schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression(), + updateReqVO.getRetryCount(), updateReqVO.getRetryInterval()); + } + + private void validateJobHandlerExists(String handlerName) { + Object handler = SpringUtil.getBean(handlerName); + if (handler == null) { + throw exception(JOB_HANDLER_BEAN_NOT_EXISTS); + } + if (!(handler instanceof JobHandler)) { + throw exception(JOB_HANDLER_BEAN_TYPE_ERROR); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateJobStatus(Long id, Integer status) throws SchedulerException { + // 校验 status + if (!containsAny(status, JobStatusEnum.NORMAL.getStatus(), JobStatusEnum.STOP.getStatus())) { + throw exception(JOB_CHANGE_STATUS_INVALID); + } + // 校验存在 + JobDO job = validateJobExists(id); + // 校验是否已经为当前状态 + if (job.getStatus().equals(status)) { + throw exception(JOB_CHANGE_STATUS_EQUALS); + } + // 更新 Job 状态 + JobDO updateObj = JobDO.builder().id(id).status(status).build(); + jobMapper.updateById(updateObj); + + // 更新状态 Job 到 Quartz 中 + if (JobStatusEnum.NORMAL.getStatus().equals(status)) { // 开启 + schedulerManager.resumeJob(job.getHandlerName()); + } else { // 暂停 + schedulerManager.pauseJob(job.getHandlerName()); + } + } + + @Override + public void triggerJob(Long id) throws SchedulerException { + // 校验存在 + JobDO job = validateJobExists(id); + + // 触发 Quartz 中的 Job + schedulerManager.triggerJob(job.getId(), job.getHandlerName(), job.getHandlerParam()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncJob() throws SchedulerException { + // 1. 查询 Job 配置 + List jobList = jobMapper.selectList(); + + // 2. 遍历处理 + for (JobDO job : jobList) { + // 2.1 先删除,再创建 + schedulerManager.deleteJob(job.getHandlerName()); + schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(), + job.getRetryCount(), job.getRetryInterval()); + // 2.2 如果 status 为暂停,则需要暂停 + if (Objects.equals(job.getStatus(), JobStatusEnum.STOP.getStatus())) { + schedulerManager.pauseJob(job.getHandlerName()); + } + log.info("[syncJob][id({}) handlerName({}) 同步完成]", job.getId(), job.getHandlerName()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteJob(Long id) throws SchedulerException { + // 校验存在 + JobDO job = validateJobExists(id); + // 更新 + jobMapper.deleteById(id); + + // 删除 Job 到 Quartz 中 + schedulerManager.deleteJob(job.getHandlerName()); + } + + private JobDO validateJobExists(Long id) { + JobDO job = jobMapper.selectById(id); + if (job == null) { + throw exception(JOB_NOT_EXISTS); + } + return job; + } + + private void validateCronExpression(String cronExpression) { + if (!CronUtils.isValid(cronExpression)) { + throw exception(JOB_CRON_EXPRESSION_VALID); + } + } + + @Override + public JobDO getJob(Long id) { + return jobMapper.selectById(id); + } + + @Override + public PageResult getJobPage(JobPageReqVO pageReqVO) { + return jobMapper.selectPage(pageReqVO); + } + + private static void fillJobMonitorTimeoutEmpty(JobDO job) { + if (job.getMonitorTimeout() == null) { + job.setMonitorTimeout(0); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java new file mode 100644 index 0000000..fd4e841 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; + +/** + * API 访问日志 Service 接口 + * + * @author 芋道源码 + */ +public interface ApiAccessLogService { + + /** + * 创建 API 访问日志 + * + * @param createReqDTO API 访问日志 + */ + void createApiAccessLog(ApiAccessLogCreateReqDTO createReqDTO); + + /** + * 获得 API 访问日志分页 + * + * @param pageReqVO 分页查询 + * @return API 访问日志分页 + */ + PageResult getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO); + + /** + * 清理 exceedDay 天前的访问日志 + * + * @param exceedDay 超过多少天就进行清理 + * @param deleteLimit 清理的间隔条数 + */ + Integer cleanAccessLog(Integer exceedDay, Integer deleteLimit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java new file mode 100644 index 0000000..ada32eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiAccessLogMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO.REQUEST_PARAMS_MAX_LENGTH; +import static cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO.RESULT_MSG_MAX_LENGTH; + +/** + * API 访问日志 Service 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@Service +@Validated +public class ApiAccessLogServiceImpl implements ApiAccessLogService { + + @Resource + private ApiAccessLogMapper apiAccessLogMapper; + + @Override + public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { + ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class); + apiAccessLog.setRequestParams(StrUtil.maxLength(apiAccessLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); + apiAccessLog.setResultMsg(StrUtil.maxLength(apiAccessLog.getResultMsg(), RESULT_MSG_MAX_LENGTH)); + apiAccessLogMapper.insert(apiAccessLog); + } + + @Override + public PageResult getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO) { + return apiAccessLogMapper.selectPage(pageReqVO); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public Integer cleanAccessLog(Integer exceedDay, Integer deleteLimit) { + int count = 0; + LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay); + // 循环删除,直到没有满足条件的数据 + for (int i = 0; i < Short.MAX_VALUE; i++) { + int deleteCount = apiAccessLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit); + count += deleteCount; + // 达到删除预期条数,说明到底了 + if (deleteCount < deleteLimit) { + break; + } + } + return count; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java new file mode 100644 index 0000000..82eb3c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; + +/** + * API 错误日志 Service 接口 + * + * @author 芋道源码 + */ +public interface ApiErrorLogService { + + /** + * 创建 API 错误日志 + * + * @param createReqDTO API 错误日志 + */ + void createApiErrorLog(ApiErrorLogCreateReqDTO createReqDTO); + + /** + * 获得 API 错误日志分页 + * + * @param pageReqVO 分页查询 + * @return API 错误日志分页 + */ + PageResult getApiErrorLogPage(ApiErrorLogPageReqVO pageReqVO); + + /** + * 更新 API 错误日志已处理 + * + * @param id API 日志编号 + * @param processStatus 处理结果 + * @param processUserId 处理人 + */ + void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId); + + /** + * 清理 exceedDay 天前的错误日志 + * + * @param exceedDay 超过多少天就进行清理 + * @param deleteLimit 清理的间隔条数 + */ + Integer cleanErrorLog(Integer exceedDay, Integer deleteLimit); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java new file mode 100644 index 0000000..2c4bf4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper; +import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO.REQUEST_PARAMS_MAX_LENGTH; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_NOT_FOUND; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_PROCESSED; + +/** + * API 错误日志 Service 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@Service +@Validated +public class ApiErrorLogServiceImpl implements ApiErrorLogService { + + @Resource + private ApiErrorLogMapper apiErrorLogMapper; + + @Override + public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { + ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class) + .setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); + apiErrorLog.setRequestParams(StrUtil.maxLength(apiErrorLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); + apiErrorLogMapper.insert(apiErrorLog); + } + + @Override + public PageResult getApiErrorLogPage(ApiErrorLogPageReqVO pageReqVO) { + return apiErrorLogMapper.selectPage(pageReqVO); + } + + @Override + public void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId) { + ApiErrorLogDO errorLog = apiErrorLogMapper.selectById(id); + if (errorLog == null) { + throw exception(API_ERROR_LOG_NOT_FOUND); + } + if (!ApiErrorLogProcessStatusEnum.INIT.getStatus().equals(errorLog.getProcessStatus())) { + throw exception(API_ERROR_LOG_PROCESSED); + } + // 标记处理 + apiErrorLogMapper.updateById(ApiErrorLogDO.builder().id(id).processStatus(processStatus) + .processUserId(processUserId).processTime(LocalDateTime.now()).build()); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public Integer cleanErrorLog(Integer exceedDay, Integer deleteLimit) { + int count = 0; + LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay); + // 循环删除,直到没有满足条件的数据 + for (int i = 0; i < Short.MAX_VALUE; i++) { + int deleteCount = apiErrorLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit); + count += deleteCount; + // 达到删除预期条数,说明到底了 + if (deleteCount < deleteLimit) { + break; + } + } + return count; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/DemoWebSocketMessageListener.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/DemoWebSocketMessageListener.java new file mode 100644 index 0000000..9ccf607 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/DemoWebSocketMessageListener.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.infra.websocket; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; +import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import cn.iocoder.yudao.module.infra.websocket.message.DemoReceiveMessage; +import cn.iocoder.yudao.module.infra.websocket.message.DemoSendMessage; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +import javax.annotation.Resource; + +/** + * WebSocket 示例:单发消息 + * + * @author 芋道源码 + */ +@Component +public class DemoWebSocketMessageListener implements WebSocketMessageListener { + + @Resource + private WebSocketMessageSender webSocketMessageSender; + + @Override + public void onMessage(WebSocketSession session, DemoSendMessage message) { + Long fromUserId = WebSocketFrameworkUtils.getLoginUserId(session); + // 情况一:单发 + if (message.getToUserId() != null) { + DemoReceiveMessage toMessage = new DemoReceiveMessage().setFromUserId(fromUserId) + .setText(message.getText()).setSingle(true); + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getToUserId(), // 给指定用户 + "demo-message-receive", toMessage); + return; + } + // 情况二:群发 + DemoReceiveMessage toMessage = new DemoReceiveMessage().setFromUserId(fromUserId) + .setText(message.getText()).setSingle(false); + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), // 给所有用户 + "demo-message-receive", toMessage); + } + + @Override + public String getType() { + return "demo-message-send"; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoReceiveMessage.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoReceiveMessage.java new file mode 100644 index 0000000..03a246c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoReceiveMessage.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.infra.websocket.message; + +import lombok.Data; + +/** + * 示例:server -> client 同步消息 + * + * @author 芋道源码 + */ +@Data +public class DemoReceiveMessage { + + /** + * 接收人的编号 + */ + private Long fromUserId; + /** + * 内容 + */ + private String text; + + /** + * 是否单聊 + */ + private Boolean single; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoSendMessage.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoSendMessage.java new file mode 100644 index 0000000..f0c14f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/websocket/message/DemoSendMessage.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.websocket.message; + +import lombok.Data; + +/** + * 示例:client -> server 发送消息 + * + * @author 芋道源码 + */ +@Data +public class DemoSendMessage { + + /** + * 发送给谁 + * + * 如果为空,说明发送给所有人 + */ + private Long toUserId; + /** + * 内容 + */ + private String text; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm new file mode 100644 index 0000000..5aa3bae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm @@ -0,0 +1,233 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}; + +import org.springframework.web.bind.annotation.*; +import ${jakartaPackage}.annotation.Resource; +import org.springframework.validation.annotation.Validated; +#if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import ${jakartaPackage}.validation.constraints.*; +import ${jakartaPackage}.validation.*; +import ${jakartaPackage}.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import ${PageParamClassName}; +import ${PageResultClassName}; +import ${CommonResultClassName}; +import ${BeanUtils}; +import static ${CommonResultClassName}.success; + +import ${ExcelUtilsClassName}; + +import ${ApiAccessLogClassName}; +import static ${OperateTypeEnumClassName}.*; + +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${basePackage}.module.${table.moduleName}.service.${table.businessName}.${table.className}Service; + +@Tag(name = "${sceneEnum.name} - ${table.classComment}") +@RestController +##二级的 businessName 暂时不算在 HTTP 路径上,可以根据需要写 +@RequestMapping("/${table.moduleName}/${simpleClassName_strikeCase}") +@Validated +public class ${sceneEnum.prefixClass}${table.className}Controller { + + @Resource + private ${table.className}Service ${classNameVar}Service; + + @PostMapping("/create") + @Operation(summary = "创建${table.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')") +#end + public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) { + return success(${classNameVar}Service.create${simpleClassName}(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新${table.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')") +#end + public CommonResult update${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) { + ${classNameVar}Service.update${simpleClassName}(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除${table.classComment}") + @Parameter(name = "id", description = "编号", required = true) +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')") +#end + public CommonResult delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) { + ${classNameVar}Service.delete${simpleClassName}(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得${table.classComment}") + @Parameter(name = "id", description = "编号", required = true, example = "1024") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${sceneEnum.prefixClass}${table.className}RespVO> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) { + ${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id); + return success(BeanUtils.toBean(${classNameVar}, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +#if ( $table.templateType != 2 ) + @GetMapping("/page") + @Operation(summary = "获得${table.classComment}分页") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${simpleClassName}Page(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) { + PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO); + return success(BeanUtils.toBean(pageResult, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#else + @GetMapping("/list") + @Operation(summary = "获得${table.classComment}列表") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${simpleClassName}List(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) { + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO); + return success(BeanUtils.toBean(list, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } + +#end + @GetMapping("/export-excel") + @Operation(summary = "导出${table.classComment} Excel") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')") +#end + @ApiAccessLog(operateType = EXPORT) +#if ( $table.templateType != 2 ) + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${sceneEnum.prefixClass}${table.className}RespVO.class, + BeanUtils.toBean(list, ${sceneEnum.prefixClass}${table.className}RespVO.class)); + } +## 特殊:树表专属逻辑(树不需要分页接口) +#else + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${table.className}RespVO.class, + BeanUtils.toBean(list, ${table.className}RespVO.class)); + } +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + @GetMapping("/${subSimpleClassName_strikeCase}/page") + @Operation(summary = "获得${subTable.classComment}分页") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${subSimpleClassName}Page(PageParam pageReqVO, + @RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}Page(pageReqVO, ${subJoinColumn.javaField})); + } + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + @GetMapping("/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}") + @Operation(summary = "获得${subTable.classComment}列表") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult> get${subSimpleClassName}ListBy${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField})); + } + + #else + @GetMapping("/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}") + @Operation(summary = "获得${subTable.classComment}") + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${subTable.className}DO> get${subSimpleClassName}By${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return success(${classNameVar}Service.get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField})); + } + + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + @PostMapping("/${subSimpleClassName_strikeCase}/create") + @Operation(summary = "创建${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')") +#end + public CommonResult<${subPrimaryColumn.javaType}> create${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) { + return success(${classNameVar}Service.create${subSimpleClassName}(${subClassNameVar})); + } + + @PutMapping("/${subSimpleClassName_strikeCase}/update") + @Operation(summary = "更新${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')") +#end + public CommonResult update${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) { + ${classNameVar}Service.update${subSimpleClassName}(${subClassNameVar}); + return success(true); + } + + @DeleteMapping("/${subSimpleClassName_strikeCase}/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除${subTable.classComment}") +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')") +#end + public CommonResult delete${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) { + ${classNameVar}Service.delete${subSimpleClassName}(id); + return success(true); + } + + @GetMapping("/${subSimpleClassName_strikeCase}/get") + @Operation(summary = "获得${subTable.classComment}") + @Parameter(name = "id", description = "编号", required = true) +#if ($sceneEnum.scene == 1) + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')") +#end + public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) { + return success(${classNameVar}Service.get${subSimpleClassName}(id)); + } + +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm new file mode 100644 index 0000000..46b6a25 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm @@ -0,0 +1,45 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import ${PageParamClassName}; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperation} && ${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +#break +#end +#end +## 字段模板 +#macro(columnTpl $prefix $prefixStr) + @Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}列表 Request VO") +@Data +public class ${sceneEnum.prefixClass}${table.className}ListReqVO { + +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 + @Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; +#else##情况二,非 Between 的时间 + #columnTpl('', '') +#end + +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm new file mode 100644 index 0000000..003bac9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm @@ -0,0 +1,47 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import ${PageParamClassName}; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperationCondition} && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +#break +#end +#end +## 字段模板 +#macro(columnTpl $prefix $prefixStr) + @Schema(description = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ${sceneEnum.prefixClass}${table.className}PageReqVO extends PageParam { + +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 + @Schema(description = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; +#else##情况二,非 Between 的时间 + #columnTpl('', '') +#end + +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm new file mode 100644 index 0000000..24c3519 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm @@ -0,0 +1,53 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +## 处理 BigDecimal 字段的引入 +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if (${column.listOperationResult} && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +#break +#end +#end +## 处理 Excel 导出 +import com.alibaba.excel.annotation.*; +#foreach ($column in $columns) +#if ("$!column.dictType" != "")## 有设置数据字典 +import ${DictFormatClassName}; +import ${DictConvertClassName}; +#break +#end +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO") +@Data +@ExcelIgnoreUnannotated +public class ${sceneEnum.prefixClass}${table.className}RespVO { + +## 逐个处理字段 +#foreach ($column in $columns) +#if (${column.listOperationResult}) +## 1. 处理 Swagger 注解 + @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end) +## 2. 处理 Excel 导出 +#if ("$!column.dictType" != "")##处理枚举值 + @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class) + @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 +#else + @ExcelProperty("${column.columnComment}") +#end +## 3. 处理字段定义 + private ${column.javaType} ${column.javaField}; + +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm new file mode 100644 index 0000000..b432c75 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm @@ -0,0 +1,64 @@ +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import ${jakartaPackage}.validation.constraints.*; +## 处理 BigDecimal 字段的引入 +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end +## 处理 LocalDateTime 字段的引入 +#foreach ($column in $columns) +#if ((${column.createOperation} || ${column.updateOperation}) && ${column.javaType} == "LocalDateTime") +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +#break +#end +#end +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end + +@Schema(description = "${sceneEnum.name} - ${table.classComment}新增/修改 Request VO") +@Data +public class ${sceneEnum.prefixClass}${table.className}SaveReqVO { + +## 逐个处理字段 +#foreach ($column in $columns) +#if (${column.createOperation} || ${column.updateOperation}) +## 1. 处理 Swagger 注解 + @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end) +## 2. 处理 Validator 参数校验 +#if (!${column.nullable} && !${column.primaryKey}) +#if (${column.javaType} == 'String') + @NotEmpty(message = "${column.columnComment}不能为空") +#else + @NotNull(message = "${column.columnComment}不能为空") +#end +#end +## 3. 处理字段定义 + private ${column.javaType} ${column.javaField}; + +#end +#end +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) + #if ( $subTable.subJoinMany) + @Schema(description = "${subTable.classComment}列表") + private List<${subTable.className}DO> ${subClassNameVars.get($index)}s; + + #else + @Schema(description = "${subTable.classComment}") + private ${subTable.className}DO ${subClassNameVars.get($index)}; + + #end +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm new file mode 100644 index 0000000..b019d6e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm @@ -0,0 +1,52 @@ +package ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}; + +import lombok.*; +import java.util.*; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#end +#if (${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +#end +#end +import com.baomidou.mybatisplus.annotation.*; +import ${BaseDOClassName}; + +/** + * ${table.classComment} DO + * + * @author ${table.author} + */ +@TableName("${table.tableName.toLowerCase()}") +@KeySequence("${table.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ${table.className}DO extends BaseDO { + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) + public static final Long ${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT = 0L; + +#end +#foreach ($column in $columns) +#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 + /** + * ${column.columnComment} + #if ("$!column.dictType" != "")##处理枚举值 + * + * 枚举 {@link TODO ${column.dictType} 对应的类} + #end + */ + #if (${column.primaryKey})##处理主键 + @TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#end + #end + private ${column.javaType} ${column.javaField}; +#end +#end + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm new file mode 100644 index 0000000..16be55e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm @@ -0,0 +1,49 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +package ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}; + +import lombok.*; +import java.util.*; +#foreach ($column in $subColumns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#end +#if (${column.javaType} == "LocalDateTime") +import java.time.LocalDateTime; +#end +#end +import com.baomidou.mybatisplus.annotation.*; +import ${BaseDOClassName}; + +/** + * ${subTable.classComment} DO + * + * @author ${subTable.author} + */ +@TableName("${subTable.tableName.toLowerCase()}") +@KeySequence("${subTable.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ${subTable.className}DO extends BaseDO { + +#foreach ($column in $subColumns) +#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段 + /** + * ${column.columnComment} + #if ("$!column.dictType" != "")##处理枚举值 + * + * 枚举 {@link TODO ${column.dictType} 对应的类} + #end + */ + #if (${column.primaryKey})##处理主键 + @TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#end + #end + private ${column.javaType} ${column.javaField}; +#end +#end + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm new file mode 100644 index 0000000..b98b471 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm @@ -0,0 +1,82 @@ +package ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}; + +import java.util.*; + +import ${PageResultClassName}; +import ${QueryWrapperClassName}; +import ${BaseMapperClassName}; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +import org.apache.ibatis.annotations.Mapper; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; + +## 字段模板 +#macro(listCondition) +#foreach ($column in $columns) +#if (${column.listOperation}) +#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 +#if (${column.listOperationCondition} == "=")##情况一,= 的时候 + .eqIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "!=")##情况二,!= 的时候 + .neIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == ">")##情况三,> 的时候 + .gtIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == ">=")##情况四,>= 的时候 + .geIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "<")##情况五,< 的时候 + .ltIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "<=")##情况五,<= 的时候 + .leIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "LIKE")##情况七,Like 的时候 + .likeIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#if (${column.listOperationCondition} == "BETWEEN")##情况八,Between 的时候 + .betweenIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) +#end +#end +#end +#end +/** + * ${table.classComment} Mapper + * + * @author ${table.author} + */ +@Mapper +public interface ${table.className}Mapper extends BaseMapperX<${table.className}DO> { + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + default PageResult<${table.className}DO> selectPage(${sceneEnum.prefixClass}${table.className}PageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX<${table.className}DO>() + #listCondition() + .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序 + + } +#else + default List<${table.className}DO> selectList(${sceneEnum.prefixClass}${table.className}ListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX<${table.className}DO>() + #listCondition() + .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序 + + } +#end + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + default ${table.className}DO selectBy${TreeParentJavaField}And${TreeNameJavaField}(Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) { + return selectOne(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}, ${table.className}DO::get${TreeNameJavaField}, ${treeNameColumn.javaField}); + } + + default Long selectCountBy${TreeParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) { + return selectCount(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}); + } + +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm new file mode 100644 index 0000000..290378d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm new file mode 100644 index 0000000..6ccaea7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm @@ -0,0 +1,57 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subJoinColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +package ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}; + +import java.util.*; + +import ${PageResultClassName}; +import ${PageParamClassName}; +import ${QueryWrapperClassName}; +import ${BaseMapperClassName}; +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +import org.apache.ibatis.annotations.Mapper; + +/** + * ${subTable.classComment} Mapper + * + * @author ${subTable.author} + */ +@Mapper +public interface ${subTable.className}Mapper extends BaseMapperX<${subTable.className}DO> { + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + default PageResult<${subTable.className}DO> selectPage(PageParam reqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectPage(reqVO, new LambdaQueryWrapperX<${subTable.className}DO>() + .eq(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}) + .orderByDesc(${subTable.className}DO::getId));## 大多数情况下,id 倒序 + + } +## 主表与子表是一对一时 + #if (!$subTable.subJoinMany) + default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + #end + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany) + default List<${subTable.className}DO> selectListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectList(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + + #else + default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + + #end + #end + default int deleteBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return delete(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField}); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm new file mode 100644 index 0000000..b7e21e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm @@ -0,0 +1,22 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-${table.moduleName}-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== ${table.classComment} TODO 补充编号 ========== +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${table.classComment}不存在"); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级${table.classComment}不存在"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父${table.classComment}"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该${treeNameColumn.columnComment}的${table.classComment}"); +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子${table.className}为父${table.className}"); +#end +## 特殊:主子表专属逻辑 +#if ( $table.templateType == 11 )## 特殊:ERP 情况 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index)) +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}不存在"); +#if ( !$subTable.subJoinMany ) +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}已存在"); +#end +#end +#end \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/service.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/service.vm new file mode 100644 index 0000000..c4ee4f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/service.vm @@ -0,0 +1,147 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import java.util.*; +import ${jakartaPackage}.validation.*; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${PageResultClassName}; +import ${PageParamClassName}; + +/** + * ${table.classComment} Service 接口 + * + * @author ${table.author} + */ +public interface ${table.className}Service { + + /** + * 创建${table.classComment} + * + * @param createReqVO 创建信息 + * @return 编号 + */ + ${primaryColumn.javaType} create${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO); + + /** + * 更新${table.classComment} + * + * @param updateReqVO 更新信息 + */ + void update${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO); + + /** + * 删除${table.classComment} + * + * @param id 编号 + */ + void delete${simpleClassName}(${primaryColumn.javaType} id); + + /** + * 获得${table.classComment} + * + * @param id 编号 + * @return ${table.classComment} + */ + ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id); + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + /** + * 获得${table.classComment}分页 + * + * @param pageReqVO 分页查询 + * @return ${table.classComment}分页 + */ + PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO); +#else + /** + * 获得${table.classComment}列表 + * + * @param listReqVO 查询条件 + * @return ${table.classComment}列表 + */ + List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO); +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + /** + * 获得${subTable.classComment}分页 + * + * @param pageReqVO 分页查询 + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment}分页 + */ + PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}); + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + /** + * 获得${subTable.classComment}列表 + * + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment}列表 + */ + List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}); + + #else + /** + * 获得${subTable.classComment} + * + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment} + * @return ${subTable.classComment} + */ + ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}); + + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + /** + * 创建${subTable.classComment} + * + * @param ${subClassNameVar} 创建信息 + * @return 编号 + */ + ${subPrimaryColumn.javaType} create${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar}); + + /** + * 更新${subTable.classComment} + * + * @param ${subClassNameVar} 更新信息 + */ + void update${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar}); + + /** + * 删除${subTable.classComment} + * + * @param id 编号 + */ + void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id); + + /** + * 获得${subTable.classComment} + * + * @param id 编号 + * @return ${subTable.classComment} + */ + ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id); + +#end +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm new file mode 100644 index 0000000..a8184e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm @@ -0,0 +1,350 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import org.springframework.stereotype.Service; +import ${jakartaPackage}.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO; +#end +import ${PageResultClassName}; +import ${PageParamClassName}; +import ${BeanUtils}; + +import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +import ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}.${subTable.className}Mapper; +#end + +import static ${ServiceExceptionUtilClassName}.exception; +import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; + +/** + * ${table.classComment} Service 实现类 + * + * @author ${table.author} + */ +@Service +@Validated +public class ${table.className}ServiceImpl implements ${table.className}Service { + + @Resource + private ${table.className}Mapper ${classNameVar}Mapper; +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) + @Resource + private ${subTable.className}Mapper ${subClassNameVars.get($index)}Mapper; +#end + + @Override +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + @Transactional(rollbackFor = Exception.class) +#end + public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) { +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + // 校验${treeParentColumn.columnComment}的有效性 + validateParent${simpleClassName}(null, createReqVO.get${TreeParentJavaField}()); + // 校验${treeNameColumn.columnComment}的唯一性 + validate${simpleClassName}${TreeNameJavaField}Unique(null, createReqVO.get${TreeParentJavaField}(), createReqVO.get${TreeNameJavaField}()); + +#end + // 插入 + ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class); + ${classNameVar}Mapper.insert(${classNameVar}); +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + + // 插入子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #if ( $subTable.subJoinMany) + create${subSimpleClassName}List(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}s()); + #else + create${subSimpleClassName}(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}()); + #end +#end +#end + // 返回 + return ${classNameVar}.getId(); + } + + @Override +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 ) + @Transactional(rollbackFor = Exception.class) +#end + public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) { + // 校验存在 + validate${simpleClassName}Exists(updateReqVO.getId()); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + // 校验${treeParentColumn.columnComment}的有效性 + validateParent${simpleClassName}(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}()); + // 校验${treeNameColumn.columnComment}的唯一性 + validate${simpleClassName}${TreeNameJavaField}Unique(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}(), updateReqVO.get${TreeNameJavaField}()); + +#end + // 更新 + ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class); + ${classNameVar}Mapper.updateById(updateObj); +## 特殊:主子表专属逻辑(非 ERP 模式) +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11) + + // 更新子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #if ( $subTable.subJoinMany) + update${subSimpleClassName}List(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}s()); + #else + update${subSimpleClassName}(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}()); + #end +#end +#end + } + + @Override +## 特殊:主子表专属逻辑 +#if ( $subTables && $subTables.size() > 0) + @Transactional(rollbackFor = Exception.class) +#end + public void delete${simpleClassName}(${primaryColumn.javaType} id) { + // 校验存在 + validate${simpleClassName}Exists(id); +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 + // 校验是否有子${table.classComment} + if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN); + } +#end + // 删除 + ${classNameVar}Mapper.deleteById(id); +## 特殊:主子表专属逻辑 +#if ( $subTables && $subTables.size() > 0) + + // 删除子表 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + delete${subSimpleClassName}By${SubJoinColumnName}(id); +#end +#end + } + + private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) { + if (${classNameVar}Mapper.selectById(id) == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + } + +## 特殊:树表专属逻辑 +#if ( $table.templateType == 2 ) +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写 + private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) { + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) { + return; + } + // 1. 不能设置自己为父${table.classComment} + if (Objects.equals(id, ${treeParentColumn.javaField})) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR); + } + // 2. 父${table.classComment}不存在 + ${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField}); + if (parent${simpleClassName} == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS); + } + // 3. 递归校验父${table.classComment},如果父${table.classComment}是自己的子${table.classComment},则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + ${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}(); + if (Objects.equals(id, ${treeParentColumn.javaField})) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父${table.classComment} + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) { + break; + } + parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField}); + if (parent${simpleClassName} == null) { + break; + } + } + } + + private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) { + ${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField}); + if (${classNameVar} == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的${table.classComment} + if (id == null) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE); + } + if (!Objects.equals(${classNameVar}.getId(), id)) { + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE); + } + } + +#end + @Override + public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) { + return ${classNameVar}Mapper.selectById(id); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + @Override + public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) { + return ${classNameVar}Mapper.selectPage(pageReqVO); + } +#else + @Override + public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) { + return ${classNameVar}Mapper.selectList(listReqVO); + } +#end + +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subClassNameVar = $subClassNameVars.get($index)) + // ==================== 子表($subTable.classComment) ==================== + +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + @Override + public PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectPage(pageReqVO, ${subJoinColumn.javaField}); + } + +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + @Override + public List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + + #else + @Override + public ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) { + return ${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + + #end +#end +## 情况一:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + @Override + public ${subPrimaryColumn.javaType} create${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) { +## 特殊:一对一时,需要保证只有一条,不能重复插入 +#if ( !$subTable.subJoinMany) + // 校验是否已经存在 + if (${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subClassNameVar}.get${SubJoinColumnName}()) != null) { + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS); + } + // 插入 +#end + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar}); + return ${subClassNameVar}.getId(); + } + + @Override + public void update${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) { + // 校验存在 + validate${subSimpleClassName}Exists(${subClassNameVar}.getId()); + // 更新 + ${subClassNameVars.get($index)}Mapper.updateById(${subClassNameVar}); + } + + @Override + public void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id) { + // 校验存在 + validate${subSimpleClassName}Exists(id); + // 删除 + ${subClassNameVars.get($index)}Mapper.deleteById(id); + } + + @Override + public ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id) { + return ${subClassNameVars.get($index)}Mapper.selectById(id); + } + + private void validate${subSimpleClassName}Exists(${subPrimaryColumn.javaType} id) { + if (${subClassNameVar}Mapper.selectById(id) == null) { + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS); + } + } + +## 情况二:非 MASTER_ERP 时,支持批量的新增、修改操作 +#else + #if ( $subTable.subJoinMany) + private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { + list.forEach(o -> o.set$SubJoinColumnName(${subJoinColumn.javaField})); + ${subClassNameVars.get($index)}Mapper.insertBatch(list); + } + + private void update${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) { + delete${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + create${subSimpleClassName}List(${subJoinColumn.javaField}, list); + } + + #else + private void create${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) { + if (${subClassNameVar} == null) { + return; + } + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}); + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar}); + } + + private void update${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) { + if (${subClassNameVar} == null) { + return; + } + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField}); + ${subClassNameVar}.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + ${subClassNameVars.get($index)}Mapper.insertOrUpdate(${subClassNameVar}); + } + + #end +#end + private void delete${subSimpleClassName}By${SubJoinColumnName}(${primaryColumn.javaType} ${subJoinColumn.javaField}) { + ${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}(${subJoinColumn.javaField}); + } + +#end +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm new file mode 100644 index 0000000..bfd4600 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm @@ -0,0 +1,168 @@ +package ${basePackage}.module.${table.moduleName}.service.${table.businessName}; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import ${jakartaPackage}.annotation.Resource; + +import ${baseFrameworkPackage}.test.core.ut.BaseDbUnitTest; + +import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*; +import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO; +import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper; +import ${PageResultClassName}; + +import ${jakartaPackage}.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*; +import static ${baseFrameworkPackage}.test.core.util.AssertUtils.*; +import static ${baseFrameworkPackage}.test.core.util.RandomUtils.*; +import static ${LocalDateTimeUtilsClassName}.*; +import static ${ObjectUtilsClassName}.*; +import static ${DateUtilsClassName}.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +## 字段模板 +#macro(getPageCondition $VO) + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class, o -> { // 等会查询到 + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + o.set$JavaField(null); + #end + #end + }); + ${classNameVar}Mapper.insert(db${simpleClassName}); + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + // 测试 ${column.javaField} 不匹配 + ${classNameVar}Mapper.insert(cloneIgnoreId(db${simpleClassName}, o -> o.set$JavaField(null))); + #end + #end + // 准备参数 + ${sceneEnum.prefixClass}${table.className}${VO} reqVO = new ${sceneEnum.prefixClass}${table.className}${VO}(); + #foreach ($column in $columns) + #if (${column.listOperation}) + #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 + #if (${column.listOperationCondition} == "BETWEEN")## BETWEEN 的情况 + reqVO.set${JavaField}(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + #else + reqVO.set$JavaField(null); + #end + #end + #end +#end +/** + * {@link ${table.className}ServiceImpl} 的单元测试类 + * + * @author ${table.author} + */ +@Import(${table.className}ServiceImpl.class) +public class ${table.className}ServiceImplTest extends BaseDbUnitTest { + + @Resource + private ${table.className}ServiceImpl ${classNameVar}Service; + + @Resource + private ${table.className}Mapper ${classNameVar}Mapper; + + @Test + public void testCreate${simpleClassName}_success() { + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class).setId(null); + + // 调用 + ${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(createReqVO); + // 断言 + assertNotNull(${classNameVar}Id); + // 校验记录的属性是否正确 + ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(${classNameVar}Id); + assertPojoEquals(createReqVO, ${classNameVar}, "id"); + } + + @Test + public void testUpdate${simpleClassName}_success() { + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class); + ${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据 + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class, o -> { + o.setId(db${simpleClassName}.getId()); // 设置更新的 ID + }); + + // 调用 + ${classNameVar}Service.update${simpleClassName}(updateReqVO); + // 校验是否更新正确 + ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, ${classNameVar}); + } + + @Test + public void testUpdate${simpleClassName}_notExists() { + // 准备参数 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> ${classNameVar}Service.update${simpleClassName}(updateReqVO), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + + @Test + public void testDelete${simpleClassName}_success() { + // mock 数据 + ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class); + ${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据 + // 准备参数 + ${primaryColumn.javaType} id = db${simpleClassName}.getId(); + + // 调用 + ${classNameVar}Service.delete${simpleClassName}(id); + // 校验数据不存在了 + assertNull(${classNameVar}Mapper.selectById(id)); + } + + @Test + public void testDelete${simpleClassName}_notExists() { + // 准备参数 + ${primaryColumn.javaType} id = random${primaryColumn.javaType}Id(); + + // 调用, 并断言异常 + assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS); + } + +## 特殊:树表专属逻辑(树不需要分页接口) +#if ( $table.templateType != 2 ) + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGet${simpleClassName}Page() { + #getPageCondition("PageReqVO") + + // 调用 + PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(db${simpleClassName}, pageResult.getList().get(0)); + } +#else + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGet${simpleClassName}List() { + #getPageCondition("ListReqVO") + + // 调用 + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(db${simpleClassName}, list.get(0)); + } +#end + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/h2.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/h2.vm new file mode 100644 index 0000000..b22389b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/h2.vm @@ -0,0 +1,37 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-${table.moduleName}-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "${table.tableName.toLowerCase()}" ( +#foreach ($column in $columns) +#if (${column.javaType} == 'Long') + #set ($dataType='bigint') +#elseif (${column.javaType} == 'Integer') + #set ($dataType='int') +#elseif (${column.javaType} == 'Boolean') + #set ($dataType='bit') +#elseif (${column.javaType} == 'Date') + #set ($dataType='datetime') +#else + #set ($dataType='varchar') +#end + #if (${column.primaryKey})##处理主键 + "${column.javaField}"#if (${column.javaType} == 'String') ${dataType} NOT NULL#else ${dataType} NOT NULL GENERATED BY DEFAULT AS IDENTITY#end, + #else + #if (${column.columnName} == 'create_time') + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + #elseif (${column.columnName} == 'update_time') + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + #elseif (${column.columnName} == 'creator' || ${column.columnName} == 'updater') + "${column.columnName}" ${dataType} DEFAULT '', + #elseif (${column.columnName} == 'deleted') + "deleted" bit NOT NULL DEFAULT FALSE, + #elseif (${column.columnName} == 'tenantId') + "tenant_id" bigint NOT NULL DEFAULT 0, + #else + "${column.columnName.toLowerCase()}" ${dataType}#if (${column.nullable} == false) NOT NULL#end, + #end + #end +#end + PRIMARY KEY ("${primaryColumn.columnName.toLowerCase()}") +) COMMENT '${table.tableComment}'; + +-- 将该删表 SQL 语句,添加到 yudao-module-${table.moduleName}-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "${table.tableName}"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/sql.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/sql.vm new file mode 100644 index 0000000..41b107d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/sql.vm @@ -0,0 +1,28 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '${table.classComment}管理', '', 2, 0, ${table.parentMenuId}, + '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +#set ($functionNames = ['查询', '创建', '更新', '删除', '导出']) +#set ($functionOps = ['query', 'create', 'update', 'delete', 'export']) +#foreach ($functionName in $functionNames) +#set ($index = $foreach.count - 1) +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId, + '', '', '', 0 +); +#end \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm new file mode 100644 index 0000000..835c019 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm @@ -0,0 +1,141 @@ +import request from '@/utils/request' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// 创建${table.classComment} +export function create${simpleClassName}(data) { + return request({ + url: '${baseURL}/create', + method: 'post', + data: data + }) +} + +// 更新${table.classComment} +export function update${simpleClassName}(data) { + return request({ + url: '${baseURL}/update', + method: 'put', + data: data + }) +} + +// 删除${table.classComment} +export function delete${simpleClassName}(id) { + return request({ + url: '${baseURL}/delete?id=' + id, + method: 'delete' + }) +} + +// 获得${table.classComment} +export function get${simpleClassName}(id) { + return request({ + url: '${baseURL}/get?id=' + id, + method: 'get' + }) +} + +#if ( $table.templateType != 2 ) +// 获得${table.classComment}分页 +export function get${simpleClassName}Page(params) { + return request({ + url: '${baseURL}/page', + method: 'get', + params + }) +} +#else +// 获得${table.classComment}列表 +export function get${simpleClassName}List(params) { + return request({ + url: '${baseURL}/list', + method: 'get', + params + }) +} +#end +// 导出${table.classComment} Excel +export function export${simpleClassName}Excel(params) { + return request({ + url: '${baseURL}/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) + #set ($index = $foreach.count - 1) + #set ($subSimpleClassName = $subSimpleClassNames.get($index)) + #set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 + #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 + #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) + #set ($subClassNameVar = $subClassNameVars.get($index)) + +// ==================== 子表($subTable.classComment) ==================== + ## 情况一:MASTER_ERP 时,需要分查询页子表 + #if ($table.templateType == 11) + // 获得${subTable.classComment}分页 + export function get${subSimpleClassName}Page(params) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/page', + method: 'get', + params + }) + } + ## 情况二:非 MASTER_ERP 时,需要列表查询子表 + #else + #if ($subTable.subJoinMany) + // 获得${subTable.classComment}列表 + export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField}, + method: 'get' + }) + } + #else + // 获得${subTable.classComment} + export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=' + ${subJoinColumn.javaField}, + method: 'get' + }) + } + #end + #end + ## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 + #if ($table.templateType == 11) + // 新增${subTable.classComment} + export function create${subSimpleClassName}(data) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/create', + method: 'post', + data + }) + } + // 修改${subTable.classComment} + export function update${subSimpleClassName}(data) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/update', + method: 'post', + data + }) + } + // 删除${subTable.classComment} + export function delete${subSimpleClassName}(id) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/delete?id=' + id, + method: 'delete' + }) + } + // 获得${subTable.classComment} + export function get${subSimpleClassName}(id) { + return request({ + url: '${baseURL}/${subSimpleClassName_strikeCase}/get?id=' + id, + method: 'get' + }) + } + #end +#end \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm new file mode 100644 index 0000000..99aa91a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_erp.vue.vm @@ -0,0 +1,205 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm new file mode 100644 index 0000000..ca266be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_inner.vue.vm @@ -0,0 +1,2 @@ +## 主表的 normal 和 inner 使用相同的 form 表单 +#parse("codegen/vue/views/components/form_sub_normal.vue.vm") \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm new file mode 100644 index 0000000..48a404a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm @@ -0,0 +1,347 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm new file mode 100644 index 0000000..589736b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm @@ -0,0 +1,165 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm new file mode 100644 index 0000000..90b8e41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/components/list_sub_inner.vue.vm @@ -0,0 +1,4 @@ +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点: +## 1)inner 使用 list 不分页,erp 使用 page 分页 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持 +#parse("codegen/vue/views/components/list_sub_erp.vue.vm") \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm new file mode 100644 index 0000000..634d05d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/form.vue.vm @@ -0,0 +1,320 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm new file mode 100644 index 0000000..e2cf95b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm @@ -0,0 +1,340 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm new file mode 100644 index 0000000..c3044fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm @@ -0,0 +1,115 @@ +import request from '@/config/axios' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// ${table.classComment} VO +export interface ${simpleClassName}VO { +#foreach ($column in $columns) +#if ($column.createOperation || $column.updateOperation) +#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal") + ${column.javaField}: number // ${column.columnComment} +#elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime") + ${column.javaField}: Date // ${column.columnComment} +#else + ${column.javaField}: ${column.javaType.toLowerCase()} // ${column.columnComment} +#end +#end +#end +} + +// ${table.classComment} API +export const ${simpleClassName}Api = { +#if ( $table.templateType != 2 ) + // 查询${table.classComment}分页 + get${simpleClassName}Page: async (params: any) => { + return await request.get({ url: `${baseURL}/page`, params }) + }, +#else + // 查询${table.classComment}列表 + get${simpleClassName}List: async (params) => { + return await request.get({ url: `${baseURL}/list`, params }) + }, +#end + + // 查询${table.classComment}详情 + get${simpleClassName}: async (id: number) => { + return await request.get({ url: `${baseURL}/get?id=` + id }) + }, + + // 新增${table.classComment} + create${simpleClassName}: async (data: ${simpleClassName}VO) => { + return await request.post({ url: `${baseURL}/create`, data }) + }, + + // 修改${table.classComment} + update${simpleClassName}: async (data: ${simpleClassName}VO) => { + return await request.put({ url: `${baseURL}/update`, data }) + }, + + // 删除${table.classComment} + delete${simpleClassName}: async (id: number) => { + return await request.delete({ url: `${baseURL}/delete?id=` + id }) + }, + + // 导出${table.classComment} Excel + export${simpleClassName}: async (params) => { + return await request.download({ url: `${baseURL}/export-excel`, params }) + }, +## 特殊:主子表专属逻辑 +#foreach ($subTable in $subTables) +#set ($index = $foreach.count - 1) +#set ($subSimpleClassName = $subSimpleClassNames.get($index)) +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index)) +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) +#set ($subClassNameVar = $subClassNameVars.get($index)) + +// ==================== 子表($subTable.classComment) ==================== +## 情况一:MASTER_ERP 时,需要分查询页子表 +#if ( $table.templateType == 11 ) + + // 获得${subTable.classComment}分页 + get${subSimpleClassName}Page: async (params) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/page`, params }) + }, +## 情况二:非 MASTER_ERP 时,需要列表查询子表 +#else + #if ( $subTable.subJoinMany ) + + // 获得${subTable.classComment}列表 + get${subSimpleClassName}ListBy${SubJoinColumnName}: async (${subJoinColumn.javaField}) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} }) + }, + #else + + // 获得${subTable.classComment} + get${subSimpleClassName}By${SubJoinColumnName}: async (${subJoinColumn.javaField}) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} }) + }, + #end +#end +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作 +#if ( $table.templateType == 11 ) + // 新增${subTable.classComment} + create${subSimpleClassName}: async (data) => { + return await request.post({ url: `${baseURL}/${subSimpleClassName_strikeCase}/create`, data }) + }, + + // 修改${subTable.classComment} + update${subSimpleClassName}: async (data) => { + return await request.put({ url: `${baseURL}/${subSimpleClassName_strikeCase}/update`, data }) + }, + + // 删除${subTable.classComment} + delete${subSimpleClassName}: async (id: number) => { + return await request.delete({ url: `${baseURL}/${subSimpleClassName_strikeCase}/delete?id=` + id }) + }, + + // 获得${subTable.classComment} + get${subSimpleClassName}: async (id: number) => { + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get?id=` + id }) + }, +#end +#end +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm new file mode 100644 index 0000000..3996a9c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm @@ -0,0 +1,205 @@ +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm new file mode 100644 index 0000000..d8542c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm @@ -0,0 +1,2 @@ +## 主表的 normal 和 inner 使用相同的 form 表单 +#parse("codegen/vue3/views/components/form_sub_normal.vue.vm") \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm new file mode 100644 index 0000000..dbd0356 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm @@ -0,0 +1,362 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm new file mode 100644 index 0000000..3f0710e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm @@ -0,0 +1,184 @@ +#set ($subTable = $subTables.get($subIndex))##当前表 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm new file mode 100644 index 0000000..3fe6488 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm @@ -0,0 +1,4 @@ +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点: +## 1)inner 使用 list 不分页,erp 使用 page 分页 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持 +#parse("codegen/vue3/views/components/list_sub_erp.vue.vm") \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm new file mode 100644 index 0000000..8e3596b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm @@ -0,0 +1,301 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm new file mode 100644 index 0000000..361d379 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm @@ -0,0 +1,374 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/api/api.ts.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/api/api.ts.vm new file mode 100644 index 0000000..48cd542 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/api/api.ts.vm @@ -0,0 +1,46 @@ +import request from '@/config/axios' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +export interface ${simpleClassName}VO { + #foreach ($column in $columns) + #if ($column.createOperation || $column.updateOperation) + #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal") + ${column.javaField}: number + #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdatetime") + ${column.javaField}: Date + #else + ${column.javaField}: ${column.javaType.toLowerCase()} + #end + #end + #end +} + +// 查询${table.classComment}列表 +export const get${simpleClassName}Page = async (params) => { + return await request.get({ url: '${baseURL}/page', params }) +} + +// 查询${table.classComment}详情 +export const get${simpleClassName} = async (id: number) => { + return await request.get({ url: '${baseURL}/get?id=' + id }) +} + +// 新增${table.classComment} +export const create${simpleClassName} = async (data: ${simpleClassName}VO) => { + return await request.post({ url: '${baseURL}/create', data }) +} + +// 修改${table.classComment} +export const update${simpleClassName} = async (data: ${simpleClassName}VO) => { + return await request.put({ url: '${baseURL}/update', data }) +} + +// 删除${table.classComment} +export const delete${simpleClassName} = async (id: number) => { + return await request.delete({ url: '${baseURL}/delete?id=' + id }) +} + +// 导出${table.classComment} Excel +export const export${simpleClassName}Api = async (params) => { + return await request.download({ url: '${baseURL}/export-excel', params }) +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/data.ts.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/data.ts.vm new file mode 100644 index 0000000..ff4fa81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/data.ts.vm @@ -0,0 +1,124 @@ +import type { CrudSchema } from '@/hooks/web/useCrudSchemas' +import { dateFormatter } from '@/utils/formatTime' + +// 表单校验 +export const rules = reactive({ +#foreach ($column in $columns) +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 +#set($comment=$column.columnComment) + $column.javaField: [required], +#end +#end +}) + +// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/ +const crudSchemas = reactive([ +#foreach($column in $columns) +#if ($column.listOperation || $column.listOperationResult || $column.createOperation || $column.updateOperation) +#set ($dictType = $column.dictType) +#set ($javaField = $column.javaField) +#set ($javaType = $column.javaType) + { + label: '${column.columnComment}', + field: '${column.javaField}', +## ========= 字典部分 ========= + #if ("" != $dictType)## 有数据字典 + dictType: DICT_TYPE.$dictType.toUpperCase(), + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") + dictClass: 'number', + #elseif ($javaType == "String") + dictClass: 'string', + #elseif ($javaType == "Boolean") + dictClass: 'boolean', + #end + #end +## ========= Table 表格部分 ========= + #if (!$column.listOperationResult) + isTable: false, + #else + #if ($column.htmlType == "datetime") + formatter: dateFormatter, + #end + #end +## ========= Search 表格部分 ========= + #if ($column.listOperation) + isSearch: true, + #if ($column.htmlType == "datetime") + search: { + component: 'DatePicker', + componentProps: { + valueFormat: 'YYYY-MM-DD HH:mm:ss', + type: 'daterange', + defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] + } + }, + #end + #end +## ========= Form 表单部分 ========= + #if ((!$column.createOperation && !$column.updateOperation) || $column.primaryKey) + isForm: false, + #else + #if($column.htmlType == "imageUpload")## 图片上传 + form: { + component: 'UploadImg' + }, + #elseif($column.htmlType == "fileUpload")## 文件上传 + form: { + component: 'UploadFile' + }, + #elseif($column.htmlType == "editor")## 文本编辑器 + form: { + component: 'Editor', + componentProps: { + valueHtml: '', + height: 200 + } + }, + #elseif($column.htmlType == "select")## 下拉框 + form: { + component: 'SelectV2' + }, + #elseif($column.htmlType == "checkbox")## 多选框 + form: { + component: 'Checkbox' + }, + #elseif($column.htmlType == "radio")## 单选框 + form: { + component: 'Radio' + }, + #elseif($column.htmlType == "datetime")## 时间框 + form: { + component: 'DatePicker', + componentProps: { + type: 'datetime', + valueFormat: 'x' + } + }, + #elseif($column.htmlType == "textarea")## 文本框 + form: { + component: 'Input', + componentProps: { + type: 'textarea', + rows: 4 + }, + colProps: { + span: 24 + } + }, + #elseif(${javaType.toLowerCase()} == "long" || ${javaType.toLowerCase()} == "integer")## 文本框 + form: { + component: 'InputNumber', + value: 0 + }, + #end + #end + }, +#end +#end + { + label: '操作', + field: 'action', + isForm: false + } +]) +export const { allSchemas } = useCrudSchemas(crudSchemas) diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm new file mode 100644 index 0000000..52f20a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm @@ -0,0 +1,65 @@ + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/index.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/index.vue.vm new file mode 100644 index 0000000..6e8f140 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/index.vue.vm @@ -0,0 +1,85 @@ + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm new file mode 100644 index 0000000..b7f2651 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm @@ -0,0 +1,32 @@ +import { defHttp } from '@/utils/http/axios' +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") + +// 查询${table.classComment}列表 +export function get${simpleClassName}Page(params) { + return defHttp.get({ url: '${baseURL}/page', params }) +} + +// 查询${table.classComment}详情 +export function get${simpleClassName}(id: number) { + return defHttp.get({ url: `${baseURL}/get?id=${id}` }) +} + +// 新增${table.classComment} +export function create${simpleClassName}(data) { + return defHttp.post({ url: '${baseURL}/create', data }) +} + +// 修改${table.classComment} +export function update${simpleClassName}(data) { + return defHttp.put({ url: '${baseURL}/update', data }) +} + +// 删除${table.classComment} +export function delete${simpleClassName}(id: number) { + return defHttp.delete({ url: `${baseURL}/delete?id=${id}` }) +} + +// 导出${table.classComment} Excel +export function export${simpleClassName}(params) { + return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls') +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm new file mode 100644 index 0000000..92d3b2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm @@ -0,0 +1,236 @@ +import type {BasicColumn, FormSchema} from '@/components/Table' +import {useRender} from '@/components/Table' +import {DICT_TYPE, getDictOptions} from '@/utils/dict' + +export const columns: BasicColumn[] = [ +#foreach($column in $columns) +#if ($column.listOperationResult) + #set ($dictType=$column.dictType) + #set ($javaField = $column.javaField) + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment=$column.columnComment) +#if ($column.javaType == "LocalDateTime")## 时间类型 + { + title: '${comment}', + dataIndex: '${javaField}', + width: 180, + customRender: ({ text }) => { + return useRender.renderDate(text) + }, + }, +#elseif("" != $column.dictType)## 数据字典 + { + title: '${comment}', + dataIndex: '${javaField}', + width: 180, + customRender: ({ text }) => { + return useRender.renderDict(text, DICT_TYPE.$dictType.toUpperCase()) + }, + }, +#else + { + title: '${comment}', + dataIndex: '${javaField}', + width: 160, + }, +#end +#end +#end +] + +export const searchFormSchema: FormSchema[] = [ +#foreach($column in $columns) +#if ($column.listOperation) + #set ($dictType=$column.dictType) + #set ($javaField = $column.javaField) + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment=$column.columnComment) + { + label: '${comment}', + field: '${javaField}', + #if ($column.htmlType == "input") + component: 'Input', + #elseif ($column.htmlType == "select") + component: 'Select', + componentProps: { + #if ("" != $dictType)## 设置了 dictType 数据字典的情况 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()), + #else## 未设置 dictType 数据字典的情况 + options: [], + #end + }, + #elseif ($column.htmlType == "radio") + component: 'Radio', + componentProps: { + #if ("" != $dictType)## 设置了 dictType 数据字典的情况 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()), + #else## 未设置 dictType 数据字典的情况 + options: [], + #end + }, + #elseif($column.htmlType == "datetime") + component: 'RangePicker', + #end + colProps: { span: 8 }, + }, +#end +#end +] + +export const createFormSchema: FormSchema[] = [ + { + label: '编号', + field: 'id', + show: false, + component: 'Input', + }, +#foreach($column in $columns) +#if ($column.createOperation) + #set ($dictType = $column.dictType) + #set ($javaField = $column.javaField) + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + #set ($comment = $column.columnComment) +#if (!$column.primaryKey)## 忽略主键,不用在表单里 + { + label: '${comment}', + field: '${javaField}', + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 + required: true, + #end + #if ($column.htmlType == "input") + component: 'Input', + #elseif($column.htmlType == "imageUpload")## 图片上传 + component: 'FileUpload', + componentProps: { + fileType: 'image', + maxCount: 1, + }, + #elseif($column.htmlType == "fileUpload")## 文件上传 + component: 'FileUpload', + componentProps: { + fileType: 'file', + maxCount: 1, + }, + #elseif($column.htmlType == "editor")## 文本编辑器 + component: 'Editor', + #elseif($column.htmlType == "select")## 下拉框 + component: 'Select', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "checkbox")## 多选框 + component: 'Checkbox', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "radio")## 单选框 + component: 'RadioButtonGroup', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "datetime")## 时间框 + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + #elseif($column.htmlType == "textarea")## 文本域 + component: 'InputTextArea', + #end + }, +#end +#end +#end +] + +export const updateFormSchema: FormSchema[] = [ + { + label: '编号', + field: 'id', + show: false, + component: 'Input', + }, +#foreach($column in $columns) +#if ($column.updateOperation) +#set ($dictType = $column.dictType) +#set ($javaField = $column.javaField) +#set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set ($comment = $column.columnComment) + #if (!$column.primaryKey)## 忽略主键,不用在表单里 + { + label: '${comment}', + field: '${javaField}', + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 + required: true, + #end + #if ($column.htmlType == "input") + component: 'Input', + #elseif($column.htmlType == "imageUpload")## 图片上传 + component: 'FileUpload', + componentProps: { + fileType: 'image', + maxCount: 1, + }, + #elseif($column.htmlType == "fileUpload")## 文件上传 + component: 'FileUpload', + componentProps: { + fileType: 'file', + maxCount: 1, + }, + #elseif($column.htmlType == "editor")## 文本编辑器 + component: 'Editor', + #elseif($column.htmlType == "select")## 下拉框 + component: 'Select', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "checkbox")## 多选框 + component: 'Checkbox', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "radio")## 单选框 + component: 'RadioButtonGroup', + componentProps: { + #if ("" != $dictType)## 有数据字典 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number'), + #else##没数据字典 + options:[], + #end + }, + #elseif($column.htmlType == "datetime")## 时间框 + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + #elseif($column.htmlType == "textarea")## 文本域 + component: 'InputTextArea', + #end + }, + #end +#end +#end +] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm new file mode 100644 index 0000000..1804365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm @@ -0,0 +1,58 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm new file mode 100644 index 0000000..84ec4bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm @@ -0,0 +1,91 @@ + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/file/erweima.jpg b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/file/erweima.jpg new file mode 100644 index 0000000..1447283 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/main/resources/file/erweima.jpg differ diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java new file mode 100644 index 0000000..b8876f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.ftp; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.extra.ftp.FtpMode; +import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClientConfig; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class FtpFileClientTest { + + @Test + @Disabled + public void test() { + // 创建客户端 + FtpFileClientConfig config = new FtpFileClientConfig(); + config.setDomain("http://127.0.0.1:48080"); + config.setBasePath("/home/ftp"); + config.setHost("kanchai.club"); + config.setPort(221); + config.setUsername(""); + config.setPassword(""); + config.setMode(FtpMode.Passive.name()); + FtpFileClient client = new FtpFileClient(0L, config); + client.init(); + // 上传文件 + String path = IdUtil.fastSimpleUUID() + ".jpg"; + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + String fullPath = client.upload(content, path, "image/jpeg"); + System.out.println("访问地址:" + fullPath); + if (false) { + byte[] bytes = client.getContent(path); + System.out.println("文件内容:" + bytes); + } + if (false) { + client.delete(path); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java new file mode 100644 index 0000000..7c622a5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.local; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class LocalFileClientTest { + + @Test + @Disabled + public void test() { + // 创建客户端 + LocalFileClientConfig config = new LocalFileClientConfig(); + config.setDomain("http://127.0.0.1:48080"); + config.setBasePath("/Users/yunai/file_test"); + LocalFileClient client = new LocalFileClient(0L, config); + client.init(); + // 上传文件 + String path = IdUtil.fastSimpleUUID() + ".jpg"; + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + String fullPath = client.upload(content, path, "image/jpeg"); + System.out.println("访问地址:" + fullPath); + client.delete(path); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java new file mode 100644 index 0000000..1933e98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.s3; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import javax.validation.Validation; + +public class S3FileClientTest { + + @Test + @Disabled // MinIO,如果要集成测试,可以注释本行 + public void testMinIO() throws Exception { + S3FileClientConfig config = new S3FileClientConfig(); + // 配置成你自己的 + config.setAccessKey("admin"); + config.setAccessSecret("password"); + config.setBucket("yudaoyuanma"); + config.setDomain(null); + // 默认 9000 endpoint + config.setEndpoint("http://127.0.0.1:9000"); + + // 执行上传 + testExecuteUpload(config); + } + + @Test + @Disabled // 阿里云 OSS,如果要集成测试,可以注释本行 + public void testAliyun() throws Exception { + S3FileClientConfig config = new S3FileClientConfig(); + // 配置成你自己的 + config.setAccessKey(System.getenv("ALIYUN_ACCESS_KEY")); + config.setAccessSecret(System.getenv("ALIYUN_SECRET_KEY")); + config.setBucket("yunai-aoteman"); + config.setDomain(null); // 如果有自定义域名,则可以设置。http://ali-oss.iocoder.cn + // 默认北京的 endpoint + config.setEndpoint("oss-cn-beijing.aliyuncs.com"); + + // 执行上传 + testExecuteUpload(config); + } + + @Test + @Disabled // 腾讯云 COS,如果要集成测试,可以注释本行 + public void testQCloud() throws Exception { + S3FileClientConfig config = new S3FileClientConfig(); + // 配置成你自己的 + config.setAccessKey(System.getenv("QCLOUD_ACCESS_KEY")); + config.setAccessSecret(System.getenv("QCLOUD_SECRET_KEY")); + config.setBucket("aoteman-1255880240"); + config.setDomain(null); // 如果有自定义域名,则可以设置。http://tengxun-oss.iocoder.cn + // 默认上海的 endpoint + config.setEndpoint("cos.ap-shanghai.myqcloud.com"); + + // 执行上传 + testExecuteUpload(config); + } + + @Test + @Disabled // 七牛云存储,如果要集成测试,可以注释本行 + public void testQiniu() throws Exception { + S3FileClientConfig config = new S3FileClientConfig(); + // 配置成你自己的 +// config.setAccessKey(System.getenv("QINIU_ACCESS_KEY")); +// config.setAccessSecret(System.getenv("QINIU_SECRET_KEY")); + config.setAccessKey("b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8"); + config.setAccessSecret("kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP"); + config.setBucket("ruoyi-vue-pro"); + config.setDomain("http://test.yudao.iocoder.cn"); // 如果有自定义域名,则可以设置。http://static.yudao.iocoder.cn + // 默认上海的 endpoint + config.setEndpoint("s3-cn-south-1.qiniucs.com"); + + // 执行上传 + testExecuteUpload(config); + } + + @Test + @Disabled // 华为云存储,如果要集成测试,可以注释本行 + public void testHuaweiCloud() throws Exception { + S3FileClientConfig config = new S3FileClientConfig(); + // 配置成你自己的 +// config.setAccessKey(System.getenv("HUAWEI_CLOUD_ACCESS_KEY")); +// config.setAccessSecret(System.getenv("HUAWEI_CLOUD_SECRET_KEY")); + config.setBucket("yudao"); + config.setDomain(null); // 如果有自定义域名,则可以设置。 + // 默认上海的 endpoint + config.setEndpoint("obs.cn-east-3.myhuaweicloud.com"); + + // 执行上传 + testExecuteUpload(config); + } + + private void testExecuteUpload(S3FileClientConfig config) throws Exception { + // 校验配置 + ValidationUtils.validate(Validation.buildDefaultValidatorFactory().getValidator(), config); + // 创建 Client + S3FileClient client = new S3FileClient(0L, config); + client.init(); + // 上传文件 + String path = IdUtil.fastSimpleUUID() + ".jpg"; + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + String fullPath = client.upload(content, path, "image/jpeg"); + System.out.println("访问地址:" + fullPath); + // 读取文件 + if (true) { + byte[] bytes = client.getContent(path); + System.out.println("文件内容:" + bytes.length); + } + // 删除文件 + if (false) { + client.delete(path); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java new file mode 100644 index 0000000..1e00cf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.framework.file.core.sftp; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class SftpFileClientTest { + + @Test + @Disabled + public void test() { + // 创建客户端 + SftpFileClientConfig config = new SftpFileClientConfig(); + config.setDomain("http://127.0.0.1:48080"); + config.setBasePath("/home/ftp"); + config.setHost("kanchai.club"); + config.setPort(222); + config.setUsername(""); + config.setPassword(""); + SftpFileClient client = new SftpFileClient(0L, config); + client.init(); + // 上传文件 + String path = IdUtil.fastSimpleUUID() + ".jpg"; + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + String fullPath = client.upload(content, path, "image/jpeg"); + System.out.println("访问地址:" + fullPath); + if (false) { + byte[] bytes = client.getContent(path); + System.out.println("文件内容:" + bytes); + } + if (false) { + client.delete(path); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java new file mode 100644 index 0000000..a6de8d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.infra.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.generator.query.DefaultQuery; +import com.baomidou.mybatisplus.generator.config.DataSourceConfig; +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; + +import java.util.List; + +public class DefaultDatabaseQueryTest { + + public static void main(String[] args) { +// DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:oracle:thin:@127.0.0.1:1521:xe", +// "root", "123456").build(); + DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder("jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro", + "root", "123456").build(); +// StrategyConfig strategyConfig = new StrategyConfig.Builder().build(); + + ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null); + + DefaultQuery query = new DefaultQuery(builder); + + long time = System.currentTimeMillis(); + List tableInfos = query.queryTables(); + for (TableInfo tableInfo : tableInfos) { + if (StrUtil.startWithAny(tableInfo.getName().toLowerCase(), "act_", "flw_", "qrtz_")) { + continue; + } + System.out.println(String.format("CREATE SEQUENCE %s_seq MINVALUE 1;", tableInfo.getName())); +// System.out.println(String.format("DELETE FROM %s WHERE deleted = '1';", tableInfo.getName())); + } + System.out.println(tableInfos.size()); + System.out.println(System.currentTimeMillis() - time); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java new file mode 100644 index 0000000..c3987a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java @@ -0,0 +1,558 @@ +package cn.iocoder.yudao.module.infra.service.codegen; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder; +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine; +import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * {@link CodegenServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(CodegenServiceImpl.class) +public class CodegenServiceImplTest extends BaseDbUnitTest { + + @Resource + private CodegenServiceImpl codegenService; + + @Resource + private CodegenTableMapper codegenTableMapper; + @Resource + private CodegenColumnMapper codegenColumnMapper; + + @MockBean + private DatabaseTableService databaseTableService; + + @MockBean + private AdminUserApi userApi; + + @MockBean + private CodegenBuilder codegenBuilder; + @MockBean + private CodegenEngine codegenEngine; + + @MockBean + private CodegenProperties codegenProperties; + + @Test + public void testCreateCodegenList() { + // 准备参数 + Long userId = randomLongId(); + CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class, + o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai"))); + // mock 方法(TableInfo) + TableInfo tableInfo = mock(TableInfo.class); + when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) + .thenReturn(tableInfo); + when(tableInfo.getComment()).thenReturn("芋艿"); + // mock 方法(TableInfo fields) + TableField field01 = mock(TableField.class); + when(field01.getComment()).thenReturn("主键"); + TableField field02 = mock(TableField.class); + when(field02.getComment()).thenReturn("名字"); + List fields = Arrays.asList(field01, field02); + when(tableInfo.getFields()).thenReturn(fields); + // mock 方法(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class); + when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table); + // mock 方法(AdminUserRespDTO) + AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头")); + when(userApi.getUser(eq(userId))).thenReturn(user); + // mock 方法(CodegenColumnDO) + List columns = randomPojoList(CodegenColumnDO.class); + when(codegenBuilder.buildColumns(eq(table.getId()), same(fields))) + .thenReturn(columns); + // mock 方法(CodegenProperties) + when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType()); + + // 调用 + List result = codegenService.createCodegenList(userId, reqVO); + // 断言 + assertEquals(1, result.size()); + // 断言(CodegenTableDO) + CodegenTableDO dbTable = codegenTableMapper.selectList().get(0); + assertPojoEquals(table, dbTable); + assertEquals(1L, dbTable.getDataSourceConfigId()); + assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene()); + assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType()); + assertEquals("芋头", dbTable.getAuthor()); + // 断言(CodegenColumnDO) + List dbColumns = codegenColumnMapper.selectList(); + assertEquals(columns.size(), dbColumns.size()); + assertTrue(dbColumns.get(0).getPrimaryKey()); + for (int i = 0; i < dbColumns.size(); i++) { + assertPojoEquals(columns.get(i), dbColumns.get(i)); + } + } + + @Test + public void testValidateTableInfo() { + // 情况一 + assertServiceException(() -> codegenService.validateTableInfo(null), + CODEGEN_IMPORT_TABLE_NULL); + // 情况二 + TableInfo tableInfo = mock(TableInfo.class); + assertServiceException(() -> codegenService.validateTableInfo(tableInfo), + CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL); + // 情况三 + when(tableInfo.getComment()).thenReturn("芋艿"); + assertServiceException(() -> codegenService.validateTableInfo(tableInfo), + CODEGEN_IMPORT_COLUMNS_NULL); + // 情况四 + TableField field = mock(TableField.class); + when(field.getName()).thenReturn("name"); + when(tableInfo.getFields()).thenReturn(Collections.singletonList(field)); + assertServiceException(() -> codegenService.validateTableInfo(tableInfo), + CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName()); + } + + @Test + public void testUpdateCodegen_notExists() { + // 准备参数 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class); + // mock 方法 + + // 调用,并断言 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO), + CODEGEN_TABLE_NOT_EXISTS); + } + + @Test + public void testUpdateCodegen_sub_masterNotExists() { + // mock 数据 + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table); + // 准备参数 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, + o -> o.getTable().setId(table.getId()) + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())); + + // 调用,并断言 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO), + CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId()); + } + + @Test + public void testUpdateCodegen_sub_columnNotExists() { + // mock 数据 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class, + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(subTable); + // mock 数据(master) + CodegenTableDO masterTable = randomPojo(CodegenTableDO.class, + o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType()) + .setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(masterTable); + // 准备参数 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, + o -> o.getTable().setId(subTable.getId()) + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setMasterTableId(masterTable.getId())); + + // 调用,并断言 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO), + CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId()); + } + + @Test + public void testUpdateCodegen_success() { + // mock 数据 + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType()) + .setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table); + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column01); + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column02); + // 准备参数 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, + o -> o.getTable().setId(table.getId()) + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()) + .setScene(CodegenSceneEnum.ADMIN.getScene())); + CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class, + o -> o.setId(column01.getId()).setTableId(table.getId())); + CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class, + o -> o.setId(column02.getId()).setTableId(table.getId())); + updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02)); + + // 调用 + codegenService.updateCodegen(updateReqVO); + // 断言 + CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId()); + assertPojoEquals(updateReqVO.getTable(), dbTable); + List dbColumns = codegenColumnMapper.selectList(); + assertEquals(2, dbColumns.size()); + assertPojoEquals(columnVO01, dbColumns.get(0)); + assertPojoEquals(columnVO02, dbColumns.get(1)); + } + + @Test + @Disabled // TODO @芋艿:这个单测会随机性失败,需要定位下; + public void testSyncCodegenFromDB() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai") + .setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table); + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()) + .setColumnName("id")); + codegenColumnMapper.insert(column01); + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()) + .setColumnName("name")); + codegenColumnMapper.insert(column02); + // 准备参数 + Long tableId = table.getId(); + // mock 方法(TableInfo) + TableInfo tableInfo = mock(TableInfo.class); + when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) + .thenReturn(tableInfo); + when(tableInfo.getComment()).thenReturn("芋艿"); + // mock 方法(TableInfo fields) + TableField field01 = mock(TableField.class); + when(field01.getComment()).thenReturn("主键"); + TableField field03 = mock(TableField.class); + when(field03.getComment()).thenReturn("分类"); + List fields = Arrays.asList(field01, field03); + when(tableInfo.getFields()).thenReturn(fields); + when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) + .thenReturn(tableInfo); + // mock 方法(CodegenTableDO) + List newColumns = randomPojoList(CodegenColumnDO.class); + when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> { + assertEquals(2, tableFields.size()); + assertSame(tableInfo.getFields(), tableFields); + return true; + }))).thenReturn(newColumns); + + // 调用 + codegenService.syncCodegenFromDB(tableId); + // 断言 + List dbColumns = codegenColumnMapper.selectList(); + assertEquals(newColumns.size(), dbColumns.size()); + assertPojoEquals(newColumns.get(0), dbColumns.get(0)); + assertPojoEquals(newColumns.get(1), dbColumns.get(1)); + } + + @Test + public void testDeleteCodegen_notExists() { + assertServiceException(() -> codegenService.deleteCodegen(randomLongId()), + CODEGEN_TABLE_NOT_EXISTS); + } + + @Test + public void testDeleteCodegen_success() { + // mock 数据 + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table); + CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column); + // 准备参数 + Long tableId = table.getId(); + + // 调用 + codegenService.deleteCodegen(tableId); + // 断言 + assertNull(codegenTableMapper.selectById(tableId)); + assertEquals(0, codegenColumnMapper.selectList().size()); + } + + @Test + public void testGetCodegenTableList() { + // mock 数据 + CodegenTableDO table01 = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table01); + CodegenTableDO table02 = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(table02); + // 准备参数 + Long dataSourceConfigId = table01.getDataSourceConfigId(); + + // 调用 + List result = codegenService.getCodegenTableList(dataSourceConfigId); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(table01, result.get(0)); + } + + @Test + public void testGetCodegenTablePage() { + // mock 数据 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> { + o.setTableName("t_yunai"); + o.setTableComment("芋艿"); + o.setClassName("SystemYunai"); + o.setCreateTime(buildTime(2021, 3, 10)); + }).setScene(CodegenSceneEnum.ADMIN.getScene()); + codegenTableMapper.insert(tableDO); + // 测试 tableName 不匹配 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString()))); + // 测试 tableComment 不匹配 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString()))); + // 测试 className 不匹配 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString()))); + // 测试 createTime 不匹配 + codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10)))); + // 准备参数 + CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO(); + reqVO.setTableName("yunai"); + reqVO.setTableComment("芋"); + reqVO.setClassName("Yunai"); + reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31)); + + // 调用 + PageResult pageResult = codegenService.getCodegenTablePage(reqVO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(tableDO, pageResult.getList().get(0)); + } + + @Test + public void testGetCodegenTable() { + // mock 数据 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); + codegenTableMapper.insert(tableDO); + // 准备参数 + Long id = tableDO.getId(); + + // 调用 + CodegenTableDO result = codegenService.getCodegenTable(id); + // 断言 + assertPojoEquals(tableDO, result); + } + + @Test + public void testGetCodegenColumnListByTableId() { + // mock 数据 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class); + codegenColumnMapper.insert(column01); + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class); + codegenColumnMapper.insert(column02); + // 准备参数 + Long tableId = column01.getTableId(); + + // 调用 + List result = codegenService.getCodegenColumnListByTableId(tableId); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(column01, result.get(0)); + } + + @Test + public void testGenerationCodes_tableNotExists() { + assertServiceException(() -> codegenService.generationCodes(randomLongId()), + CODEGEN_TABLE_NOT_EXISTS); + } + + @Test + public void testGenerationCodes_columnNotExists() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); + codegenTableMapper.insert(table); + // 准备参数 + Long tableId = table.getId(); + + // 调用,并断言 + assertServiceException(() -> codegenService.generationCodes(tableId), + CODEGEN_COLUMN_NOT_EXISTS); + } + + @Test + public void testGenerationCodes_sub_tableNotExists() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); + codegenTableMapper.insert(table); + // mock 数据(CodegenColumnDO) + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column01); + // 准备参数 + Long tableId = table.getId(); + + // 调用,并断言 + assertServiceException(() -> codegenService.generationCodes(tableId), + CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE); + } + + @Test + public void testGenerationCodes_sub_columnNotExists() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); + codegenTableMapper.insert(table); + // mock 数据(CodegenColumnDO) + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column01); + // mock 数据(sub CodegenTableDO) + CodegenTableDO subTable = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setMasterTableId(table.getId())); + codegenTableMapper.insert(subTable); + // 准备参数 + Long tableId = table.getId(); + + // 调用,并断言 + assertServiceException(() -> codegenService.generationCodes(tableId), + CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId()); + } + + @Test + public void testGenerationCodes_one_success() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType())); + codegenTableMapper.insert(table); + // mock 数据(CodegenColumnDO) + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column01); + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column02); + // mock 执行生成 + Map codes = MapUtil.of(randomString(), randomString()); + when(codegenEngine.execute(eq(table), argThat(columns -> { + assertEquals(2, columns.size()); + assertEquals(column01, columns.get(0)); + assertEquals(column02, columns.get(1)); + return true; + }), isNull(), isNull())).thenReturn(codes); + // 准备参数 + Long tableId = table.getId(); + + // 调用 + Map result = codegenService.generationCodes(tableId); + // 断言 + assertSame(codes, result); + } + + @Test + public void testGenerationCodes_master_success() { + // mock 数据(CodegenTableDO) + CodegenTableDO table = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); + codegenTableMapper.insert(table); + // mock 数据(CodegenColumnDO) + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column01); + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); + codegenColumnMapper.insert(column02); + // mock 数据(sub CodegenTableDO) + CodegenTableDO subTable = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setMasterTableId(table.getId()) + .setSubJoinColumnId(1024L)); + codegenTableMapper.insert(subTable); + // mock 数据(sub CodegenColumnDO) + CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId())); + codegenColumnMapper.insert(subColumn01); + // mock 执行生成 + Map codes = MapUtil.of(randomString(), randomString()); + when(codegenEngine.execute(eq(table), argThat(columns -> { + assertEquals(2, columns.size()); + assertEquals(column01, columns.get(0)); + assertEquals(column02, columns.get(1)); + return true; + }), argThat(tables -> { + assertEquals(1, tables.size()); + assertPojoEquals(subTable, tables.get(0)); + return true; + }), argThat(columns -> { + assertEquals(1, columns.size()); + assertPojoEquals(subColumn01, columns.size()); + return true; + }))).thenReturn(codes); + // 准备参数 + Long tableId = table.getId(); + + // 调用 + Map result = codegenService.generationCodes(tableId); + // 断言 + assertSame(codes, result); + } + + @Test + public void testGetDatabaseTableList() { + // 准备参数 + Long dataSourceConfigId = randomLongId(); + String name = randomString(); + String comment = randomString(); + // mock 方法 + TableInfo tableInfo01 = mock(TableInfo.class); + when(tableInfo01.getName()).thenReturn("t_yunai"); + when(tableInfo01.getComment()).thenReturn("芋艿"); + TableInfo tableInfo02 = mock(TableInfo.class); + when(tableInfo02.getName()).thenReturn("t_yunai_02"); + when(tableInfo02.getComment()).thenReturn("芋艿_02"); + when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment))) + .thenReturn(ListUtil.toList(tableInfo01, tableInfo02)); + // mock 数据 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) + .setTableName("t_yunai_02") + .setDataSourceConfigId(dataSourceConfigId)); + codegenTableMapper.insert(tableDO); + + // 调用 + List result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment); + // 断言 + assertEquals(1, result.size()); + assertEquals("t_yunai", result.get(0).getName()); + assertEquals("芋艿", result.get(0).getComment()); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java new file mode 100644 index 0000000..7a26ea9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.IColumnType; +import org.apache.ibatis.type.JdbcType; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class CodegenBuilderTest extends BaseMockitoUnitTest { + + @InjectMocks + private CodegenBuilder codegenBuilder; + + @Test + public void testBuildTable() { + // 准备参数 + TableInfo tableInfo = mock(TableInfo.class); + // mock 方法 + when(tableInfo.getName()).thenReturn("system_user"); + when(tableInfo.getComment()).thenReturn("用户"); + + // 调用 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo); + // 断言 + assertEquals("system_user", table.getTableName()); + assertEquals("用户", table.getTableComment()); + assertEquals("system", table.getModuleName()); + assertEquals("user", table.getBusinessName()); + assertEquals("User", table.getClassName()); + assertEquals("用户", table.getClassComment()); + } + + @Test + public void testBuildColumns() { + // 准备参数 + Long tableId = randomLongId(); + TableField tableField = mock(TableField.class); + List tableFields = Collections.singletonList(tableField); + // mock 方法 + TableField.MetaInfo metaInfo = mock(TableField.MetaInfo.class); + when(tableField.getMetaInfo()).thenReturn(metaInfo); + when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT); + when(tableField.getComment()).thenReturn("编号"); + when(tableField.isKeyFlag()).thenReturn(true); + IColumnType columnType = mock(IColumnType.class); + when(tableField.getColumnType()).thenReturn(columnType); + when(columnType.getType()).thenReturn("Long"); + when(tableField.getName()).thenReturn("id2"); + when(tableField.getPropertyName()).thenReturn("id"); + + // 调用 + List columns = codegenBuilder.buildColumns(tableId, tableFields); + // 断言 + assertEquals(1, columns.size()); + CodegenColumnDO column = columns.get(0); + assertEquals(tableId, column.getTableId()); + assertEquals("id2", column.getColumnName()); + assertEquals("BIGINT", column.getDataType()); + assertEquals("编号", column.getColumnComment()); + assertFalse(column.getNullable()); + assertTrue(column.getPrimaryKey()); + assertEquals(1, column.getOrdinalPosition()); + assertEquals("Long", column.getJavaType()); + assertEquals("id", column.getJavaField()); + assertNull(column.getDictType()); + assertNotNull(column.getExample()); + assertFalse(column.getCreateOperation()); + assertTrue(column.getUpdateOperation()); + assertFalse(column.getListOperation()); + assertEquals("=", column.getListOperationCondition()); + assertTrue(column.getListOperationResult()); + assertEquals("input", column.getHtmlType()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java new file mode 100644 index 0000000..3c7390a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ZipUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link CodegenEngine} 的单元测试抽象基类 + * + * @author 芋道源码 + */ +public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { + + /** + * 测试文件资源目录 + */ + private String resourcesPath = ""; + + @InjectMocks + protected CodegenEngine codegenEngine; + + @Spy + protected CodegenProperties codegenProperties = new CodegenProperties() + .setBasePackage("cn.iocoder.yudao"); + + @BeforeEach + public void setUp() { + codegenEngine.setJakartaEnable(true); // 强制使用 jakarta,保证单测可以基于 jakarta 断言 + codegenEngine.initGlobalBindingMap(); + // 单测强制使用 + // 获取测试文件 resources 路径 + String absolutePath = FileUtil.getAbsolutePath("application-unit-test.yaml"); + // 系统不一样生成的文件也有差异,那就各自生成各自的 + resourcesPath = absolutePath.split("/target")[0] + "/src/test/resources/codegen/"; + } + + protected static CodegenTableDO getTable(String name) { + String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json"); + return JsonUtils.parseObject(content, "table", CodegenTableDO.class); + } + + protected static List getColumnList(String name) { + String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json"); + List list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class); + list.forEach(column -> { + if (column.getNullable() == null) { + column.setNullable(false); + } + if (column.getCreateOperation() == null) { + column.setCreateOperation(false); + } + if (column.getUpdateOperation() == null) { + column.setUpdateOperation(false); + } + if (column.getListOperation() == null) { + column.setListOperation(false); + } + if (column.getListOperationResult() == null) { + column.setListOperationResult(false); + } + }); + return list; + } + + @SuppressWarnings("rawtypes") + protected static void assertResult(Map result, String path) { + String assertContent = ResourceUtil.readUtf8Str("codegen/" + path + "/assert.json"); + List asserts = JsonUtils.parseArray(assertContent, HashMap.class); + assertEquals(asserts.size(), result.size()); + // 校验每个文件 + asserts.forEach(assertMap -> { + String contentPath = (String) assertMap.get("contentPath"); + String filePath = (String) assertMap.get("filePath"); + String content = ResourceUtil.readUtf8Str("codegen/" + path + "/" + contentPath); + assertEquals(content, result.get(filePath), filePath + ":不匹配"); + }); + } + + // ==================== 调试专用 ==================== + + /** + * 【调试使用】将生成的代码,写入到文件 + * + * @param result 生成的代码 + * @param path 写入文件的路径 + */ + protected void writeFile(Map result, String path) { + // 生成压缩包 + String[] paths = result.keySet().toArray(new String[0]); + ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipUtil.zip(outputStream, paths, ins); + // 写入文件 + FileUtil.writeBytes(outputStream.toByteArray(), path); + } + + /** + * 【调试使用】将生成的结果,写入到文件 + * + * @param result 生成的代码 + * @param basePath 写入文件的路径(绝对路径) + */ + protected void writeResult(Map result, String basePath) { + // 写入文件内容 + List> asserts = new ArrayList<>(); + result.forEach((filePath, fileContent) -> { + String lastFilePath = StrUtil.subAfter(filePath, '/', true); + String contentPath = StrUtil.subAfter(lastFilePath, '.', true) + + '/' + StrUtil.subBefore(lastFilePath, '.', true); + asserts.add(MapUtil.builder().put("filePath", filePath) + .put("contentPath", contentPath).build()); + FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath); + }); + // 写入 assert.json 文件 + FileUtil.writeUtf8String(JsonUtils.toJsonPrettyString(asserts), basePath + "/assert.json"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java new file mode 100644 index 0000000..94d24be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * {@link CodegenEngine} 的 Vue2 + Element UI 单元测试 + * + * @author 芋道源码 + */ +@Disabled +public class CodegenEngineVue2Test extends CodegenEngineAbstractTest { + + @Test + public void testExecute_vue2_one() { + // 准备参数 + CodegenTableDO table = getTable("student") + .setFrontType(CodegenFrontTypeEnum.VUE2.getType()) + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); + List columns = getColumnList("student"); + + // 调用 + Map result = codegenEngine.execute(table, columns, null, null); + // 生成测试文件 + //writeResult(result, resourcesPath + "/vue2_one"); + // 断言 + assertResult(result, "/vue2_one"); + } + + @Test + public void testExecute_vue2_tree() { + // 准备参数 + CodegenTableDO table = getTable("category") + .setFrontType(CodegenFrontTypeEnum.VUE2.getType()) + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); + List columns = getColumnList("category"); + + // 调用 + Map result = codegenEngine.execute(table, columns, null, null); + // 生成测试文件 + //writeResult(result, resourcesPath + "/vue2_tree"); + // 断言 + assertResult(result, "/vue2_tree"); +// writeFile(result, "/Users/yunai/test/demo66.zip"); + } + + @Test + public void testExecute_vue2_master_normal() { + testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vue2_master_normal"); + } + + @Test + public void testExecute_vue2_master_erp() { + testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vue2_master_erp"); + } + + @Test + public void testExecute_vue2_master_inner() { + testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vue2_master_inner"); + } + + private void testExecute_vue2_master(CodegenTemplateTypeEnum templateType, + String path) { + // 准备参数 + CodegenTableDO table = getTable("student") + .setFrontType(CodegenFrontTypeEnum.VUE2.getType()) + .setTemplateType(templateType.getType()); + List columns = getColumnList("student"); + // 准备参数(子表) + CodegenTableDO contactTable = getTable("contact") + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setFrontType(CodegenFrontTypeEnum.VUE2.getType()) + .setSubJoinColumnId(100L).setSubJoinMany(true); + List contactColumns = getColumnList("contact"); + // 准备参数(班主任) + CodegenTableDO teacherTable = getTable("teacher") + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setFrontType(CodegenFrontTypeEnum.VUE2.getType()) + .setSubJoinColumnId(200L).setSubJoinMany(false); + List teacherColumns = getColumnList("teacher"); + + // 调用 + Map result = codegenEngine.execute(table, columns, + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); + // 生成测试文件 + //writeResult(result, resourcesPath + path); + // 断言 + assertResult(result, path); +// writeFile(result, "/Users/yunai/test/demo11.zip"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java new file mode 100644 index 0000000..4684db7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.infra.service.codegen.inner; + +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * {@link CodegenEngine} 的 Vue2 + Element Plus 单元测试 + * + * @author 芋道源码 + */ +@Disabled +public class CodegenEngineVue3Test extends CodegenEngineAbstractTest { + + @Test + public void testExecute_vue3_one() { + // 准备参数 + CodegenTableDO table = getTable("student") + .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); + List columns = getColumnList("student"); + + // 调用 + Map result = codegenEngine.execute(table, columns, null, null); + // 生成测试文件 + //writeResult(result, resourcesPath + "/vue3_one"); + // 断言 + assertResult(result, "/vue3_one"); + } + + @Test + public void testExecute_vue3_tree() { + // 准备参数 + CodegenTableDO table = getTable("category") + .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); + List columns = getColumnList("category"); + + // 调用 + Map result = codegenEngine.execute(table, columns, null, null); + // 生成测试文件 + //writeResult(result, resourcesPath + "/vue3_tree"); + // 断言 + assertResult(result, "/vue3_tree"); +// writeFile(result, "/Users/yunai/test/demo66.zip"); + } + + @Test + public void testExecute_vue3_master_normal() { + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "/vue3_master_normal"); + } + + @Test + public void testExecute_vue3_master_erp() { + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "/vue3_master_erp"); + } + + @Test + public void testExecute_vue3_master_inner() { + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "/vue3_master_inner"); + } + + private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType, + String path) { + // 准备参数 + CodegenTableDO table = getTable("student") + .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) + .setTemplateType(templateType.getType()); + List columns = getColumnList("student"); + // 准备参数(子表) + CodegenTableDO contactTable = getTable("contact") + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) + .setSubJoinColumnId(100L).setSubJoinMany(true); + List contactColumns = getColumnList("contact"); + // 准备参数(班主任) + CodegenTableDO teacherTable = getTable("teacher") + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) + .setFrontType(CodegenFrontTypeEnum.VUE3.getType()) + .setSubJoinColumnId(200L).setSubJoinMany(false); + List teacherColumns = getColumnList("teacher"); + + // 调用 + Map result = codegenEngine.execute(table, columns, + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); + // 生成测试文件 + //writeResult(result, resourcesPath + path); + // 断言 + assertResult(result, path); + // writeFile(result, "/Users/yunai/test/demo11.zip"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImplTest.java new file mode 100644 index 0000000..1c1f1f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/config/ConfigServiceImplTest.java @@ -0,0 +1,219 @@ +package cn.iocoder.yudao.module.infra.service.config; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.config.vo.ConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.config.ConfigMapper; +import cn.iocoder.yudao.module.infra.enums.config.ConfigTypeEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; + +@Import(ConfigServiceImpl.class) +public class ConfigServiceImplTest extends BaseDbUnitTest { + + @Resource + private ConfigServiceImpl configService; + + @Resource + private ConfigMapper configMapper; + + @Test + public void testCreateConfig_success() { + // 准备参数 + ConfigSaveReqVO reqVO = randomPojo(ConfigSaveReqVO.class) + .setId(null); // 防止 id 被赋值,导致唯一性校验失败 + + // 调用 + Long configId = configService.createConfig(reqVO); + // 断言 + assertNotNull(configId); + // 校验记录的属性是否正确 + ConfigDO config = configMapper.selectById(configId); + assertPojoEquals(reqVO, config, "id"); + assertEquals(ConfigTypeEnum.CUSTOM.getType(), config.getType()); + } + + @Test + public void testUpdateConfig_success() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(); + configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ConfigSaveReqVO reqVO = randomPojo(ConfigSaveReqVO.class, o -> { + o.setId(dbConfig.getId()); // 设置更新的 ID + }); + + // 调用 + configService.updateConfig(reqVO); + // 校验是否更新正确 + ConfigDO config = configMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, config); + } + + @Test + public void testDeleteConfig_success() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(o -> { + o.setType(ConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型 + }); + configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbConfig.getId(); + + // 调用 + configService.deleteConfig(id); + // 校验数据不存在了 + assertNull(configMapper.selectById(id)); + } + + @Test + public void testDeleteConfig_canNotDeleteSystemType() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(o -> { + o.setType(ConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除 + }); + configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbConfig.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE); + } + + @Test + public void testValidateConfigExists_success() { + // mock 数据 + ConfigDO dbConfigDO = randomConfigDO(); + configMapper.insert(dbConfigDO);// @Sql: 先插入出一条存在的数据 + + // 调用成功 + configService.validateConfigExists(dbConfigDO.getId()); + } + + @Test + public void testValidateConfigExist_notExists() { + assertServiceException(() -> configService.validateConfigExists(randomLongId()), CONFIG_NOT_EXISTS); + } + + @Test + public void testValidateConfigKeyUnique_success() { + // 调用,成功 + configService.validateConfigKeyUnique(randomLongId(), randomString()); + } + + @Test + public void testValidateConfigKeyUnique_keyDuplicateForCreate() { + // 准备参数 + String key = randomString(); + // mock 数据 + configMapper.insert(randomConfigDO(o -> o.setConfigKey(key))); + + // 调用,校验异常 + assertServiceException(() -> configService.validateConfigKeyUnique(null, key), + CONFIG_KEY_DUPLICATE); + } + + @Test + public void testValidateConfigKeyUnique_keyDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String key = randomString(); + // mock 数据 + configMapper.insert(randomConfigDO(o -> o.setConfigKey(key))); + + // 调用,校验异常 + assertServiceException(() -> configService.validateConfigKeyUnique(id, key), + CONFIG_KEY_DUPLICATE); + } + + @Test + public void testGetConfigPage() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(o -> { // 等会查询到 + o.setName("芋艿"); + o.setConfigKey("yunai"); + o.setType(ConfigTypeEnum.SYSTEM.getType()); + o.setCreateTime(buildTime(2021, 2, 1)); + }); + configMapper.insert(dbConfig); + // 测试 name 不匹配 + configMapper.insert(cloneIgnoreId(dbConfig, o -> o.setName("土豆"))); + // 测试 key 不匹配 + configMapper.insert(cloneIgnoreId(dbConfig, o -> o.setConfigKey("tudou"))); + // 测试 type 不匹配 + configMapper.insert(cloneIgnoreId(dbConfig, o -> o.setType(ConfigTypeEnum.CUSTOM.getType()))); + // 测试 createTime 不匹配 + configMapper.insert(cloneIgnoreId(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1)))); + // 准备参数 + ConfigPageReqVO reqVO = new ConfigPageReqVO(); + reqVO.setName("艿"); + reqVO.setKey("nai"); + reqVO.setType(ConfigTypeEnum.SYSTEM.getType()); + reqVO.setCreateTime(buildBetweenTime(2021, 1, 15, 2021, 2, 15)); + + // 调用 + PageResult pageResult = configService.getConfigPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbConfig, pageResult.getList().get(0)); + } + + @Test + public void testGetConfig() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(); + configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbConfig.getId(); + + // 调用 + ConfigDO config = configService.getConfig(id); + // 断言 + assertNotNull(config); + assertPojoEquals(dbConfig, config); + } + + @Test + public void testGetConfigByKey() { + // mock 数据 + ConfigDO dbConfig = randomConfigDO(); + configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + String key = dbConfig.getConfigKey(); + + // 调用 + ConfigDO config = configService.getConfigByKey(key); + // 断言 + assertNotNull(config); + assertPojoEquals(dbConfig, config); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static ConfigDO randomConfigDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setType(randomEle(ConfigTypeEnum.values()).getType()); // 保证 key 的范围 + }; + return RandomUtils.randomPojo(ConfigDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java new file mode 100644 index 0000000..1c34679 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java @@ -0,0 +1,208 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.crypto.symmetric.AES; +import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler; +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.stubbing.Answer; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +/** + * {@link DataSourceConfigServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(DataSourceConfigServiceImpl.class) +public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { + + @Resource + private DataSourceConfigServiceImpl dataSourceConfigService; + + @Resource + private DataSourceConfigMapper dataSourceConfigMapper; + + @MockBean + private AES aes; + + @MockBean + private DynamicDataSourceProperties dynamicDataSourceProperties; + + @BeforeEach + public void setUp() { + // mock 一个空实现的 StringEncryptor,避免 EncryptTypeHandler 报错 + ReflectUtil.setFieldValue(EncryptTypeHandler.class, "aes", aes); + when(aes.encryptBase64(anyString())).then((Answer) invocation -> invocation.getArgument(0)); + when(aes.decryptStr(anyString())).then((Answer) invocation -> invocation.getArgument(0)); + + // mock DynamicDataSourceProperties + when(dynamicDataSourceProperties.getPrimary()).thenReturn("primary"); + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setUrl("http://localhost:3306"); + dataSourceProperty.setUsername("yunai"); + dataSourceProperty.setPassword("tudou"); + when(dynamicDataSourceProperties.getDatasource()).thenReturn(MapUtil.of("primary", dataSourceProperty)); + } + + @Test + public void testCreateDataSourceConfig_success() { + try (MockedStatic databaseUtilsMock = mockStatic(JdbcUtils.class)) { + // 准备参数 + DataSourceConfigSaveReqVO reqVO = randomPojo(DataSourceConfigSaveReqVO.class) + .setId(null); // 避免 id 被设置 + // mock 方法 + databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()), + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); + + // 调用 + Long dataSourceConfigId = dataSourceConfigService.createDataSourceConfig(reqVO); + // 断言 + assertNotNull(dataSourceConfigId); + // 校验记录的属性是否正确 + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(dataSourceConfigId); + assertPojoEquals(reqVO, dataSourceConfig, "id"); + } + } + + @Test + public void testUpdateDataSourceConfig_success() { + try (MockedStatic databaseUtilsMock = mockStatic(JdbcUtils.class)) { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DataSourceConfigSaveReqVO reqVO = randomPojo(DataSourceConfigSaveReqVO.class, o -> { + o.setId(dbDataSourceConfig.getId()); // 设置更新的 ID + }); + // mock 方法 + databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()), + eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); + + // 调用 + dataSourceConfigService.updateDataSourceConfig(reqVO); + // 校验是否更新正确 + DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, dataSourceConfig); + } + } + + @Test + public void testUpdateDataSourceConfig_notExists() { + // 准备参数 + DataSourceConfigSaveReqVO reqVO = randomPojo(DataSourceConfigSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> dataSourceConfigService.updateDataSourceConfig(reqVO), DATA_SOURCE_CONFIG_NOT_EXISTS); + } + + @Test + public void testDeleteDataSourceConfig_success() { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDataSourceConfig.getId(); + + // 调用 + dataSourceConfigService.deleteDataSourceConfig(id); + // 校验数据不存在了 + assertNull(dataSourceConfigMapper.selectById(id)); + } + + @Test + public void testDeleteDataSourceConfig_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> dataSourceConfigService.deleteDataSourceConfig(id), DATA_SOURCE_CONFIG_NOT_EXISTS); + } + + @Test // 测试使用 password 查询,可以查询到数据 + public void testSelectPassword() { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + + // 调用 + DataSourceConfigDO result = dataSourceConfigMapper.selectOne(DataSourceConfigDO::getPassword, + EncryptTypeHandler.encrypt(dbDataSourceConfig.getPassword())); + assertPojoEquals(dbDataSourceConfig, result); + } + + @Test + public void testGetDataSourceConfig_master() { + // 准备参数 + Long id = 0L; + // mock 方法 + + // 调用 + DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(id); + // 断言 + assertEquals(id, dataSourceConfig.getId()); + assertEquals("primary", dataSourceConfig.getName()); + assertEquals("http://localhost:3306", dataSourceConfig.getUrl()); + assertEquals("yunai", dataSourceConfig.getUsername()); + assertEquals("tudou", dataSourceConfig.getPassword()); + } + + @Test + public void testGetDataSourceConfig_normal() { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDataSourceConfig.getId(); + + // 调用 + DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(id); + // 断言 + assertPojoEquals(dbDataSourceConfig, dataSourceConfig); + } + + @Test + public void testGetDataSourceConfigList() { + // mock 数据 + DataSourceConfigDO dbDataSourceConfig = randomPojo(DataSourceConfigDO.class); + dataSourceConfigMapper.insert(dbDataSourceConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + + // 调用 + List dataSourceConfigList = dataSourceConfigService.getDataSourceConfigList(); + // 断言 + assertEquals(2, dataSourceConfigList.size()); + // master + assertEquals(0L, dataSourceConfigList.get(0).getId()); + assertEquals("primary", dataSourceConfigList.get(0).getName()); + assertEquals("http://localhost:3306", dataSourceConfigList.get(0).getUrl()); + assertEquals("yunai", dataSourceConfigList.get(0).getUsername()); + assertEquals("tudou", dataSourceConfigList.get(0).getPassword()); + // normal + assertPojoEquals(dbDataSourceConfig, dataSourceConfigList.get(1)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImplTest.java new file mode 100644 index 0000000..6ce8c7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImplTest.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.infra.service.db; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; +import com.baomidou.mybatisplus.generator.config.po.TableField; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.DbColumnType; +import org.apache.ibatis.type.JdbcType; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@Import(DatabaseTableServiceImpl.class) +public class DatabaseTableServiceImplTest extends BaseDbUnitTest { + + @Resource + private DatabaseTableServiceImpl databaseTableService; + + @MockBean + private DataSourceConfigService dataSourceConfigService; + + @Test + public void testGetTableList() { + // 准备参数 + Long dataSourceConfigId = randomLongId(); + // mock 方法 + DataSourceConfigDO dataSourceConfig = new DataSourceConfigDO().setUsername("sa").setPassword("") + .setUrl("jdbc:h2:mem:testdb"); + when(dataSourceConfigService.getDataSourceConfig(eq(dataSourceConfigId))) + .thenReturn(dataSourceConfig); + + // 调用 + List tables = databaseTableService.getTableList(dataSourceConfigId, + "config", "参数"); + // 断言 + assertEquals(1, tables.size()); + assertTableInfo(tables.get(0)); + } + + @Test + public void testGetTable() { + // 准备参数 + Long dataSourceConfigId = randomLongId(); + // mock 方法 + DataSourceConfigDO dataSourceConfig = new DataSourceConfigDO().setUsername("sa").setPassword("") + .setUrl("jdbc:h2:mem:testdb"); + when(dataSourceConfigService.getDataSourceConfig(eq(dataSourceConfigId))) + .thenReturn(dataSourceConfig); + + // 调用 + TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, "infra_config"); + // 断言 + assertTableInfo(tableInfo); + } + + private void assertTableInfo(TableInfo tableInfo) { + assertEquals("infra_config", tableInfo.getName()); + assertEquals("参数配置表", tableInfo.getComment()); + assertEquals(13, tableInfo.getFields().size()); + // id 字段 + TableField idField = tableInfo.getFields().get(0); + assertEquals("id", idField.getName()); + assertEquals(JdbcType.BIGINT, idField.getMetaInfo().getJdbcType()); + assertEquals("编号", idField.getComment()); + assertFalse(idField.getMetaInfo().isNullable()); + assertTrue(idField.isKeyFlag()); + assertTrue(idField.isKeyIdentityFlag()); + assertEquals(DbColumnType.LONG, idField.getColumnType()); + assertEquals("id", idField.getPropertyName()); + // name 字段 + TableField nameField = tableInfo.getFields().get(3); + assertEquals("name", nameField.getName()); + assertEquals(JdbcType.VARCHAR, nameField.getMetaInfo().getJdbcType()); + assertEquals("名字", nameField.getComment()); + assertFalse(nameField.getMetaInfo().isNullable()); + assertFalse(nameField.isKeyFlag()); + assertFalse(nameField.isKeyIdentityFlag()); + assertEquals(DbColumnType.STRING, nameField.getColumnType()); + assertEquals("name", nameField.getPropertyName()); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java new file mode 100644 index 0000000..ba0c8b1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java @@ -0,0 +1,281 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientFactory; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; +import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; +import lombok.Data; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +/** + * {@link FileConfigServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(FileConfigServiceImpl.class) +public class FileConfigServiceImplTest extends BaseDbUnitTest { + + @Resource + private FileConfigServiceImpl fileConfigService; + + @Resource + private FileConfigMapper fileConfigMapper; + + @MockBean + private Validator validator; + @MockBean + private FileClientFactory fileClientFactory; + + @Test + public void testCreateFileConfig_success() { + // 准备参数 + Map config = MapUtil.builder().put("basePath", "/yunai") + .put("domain", "https://www.iocoder.cn").build(); + FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class, + o -> o.setStorage(FileStorageEnum.LOCAL.getStorage()).setConfig(config)) + .setId(null); // 避免 id 被赋值 + + // 调用 + Long fileConfigId = fileConfigService.createFileConfig(reqVO); + // 断言 + assertNotNull(fileConfigId); + // 校验记录的属性是否正确 + FileConfigDO fileConfig = fileConfigMapper.selectById(fileConfigId); + assertPojoEquals(reqVO, fileConfig, "id", "config"); + assertFalse(fileConfig.getMaster()); + assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); + assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); + // 验证 cache + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfigId)); + } + + @Test + public void testUpdateFileConfig_success() { + // mock 数据 + FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class, o -> o.setStorage(FileStorageEnum.LOCAL.getStorage()) + .setConfig(new LocalFileClientConfig().setBasePath("/yunai").setDomain("https://www.iocoder.cn"))); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class, o -> { + o.setId(dbFileConfig.getId()); // 设置更新的 ID + o.setStorage(FileStorageEnum.LOCAL.getStorage()); + Map config = MapUtil.builder().put("basePath", "/yunai2") + .put("domain", "https://doc.iocoder.cn").build(); + o.setConfig(config); + }); + + // 调用 + fileConfigService.updateFileConfig(reqVO); + // 校验是否更新正确 + FileConfigDO fileConfig = fileConfigMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, fileConfig, "config"); + assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); + assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); + // 验证 cache + assertNull(fileConfigService.getClientCache().getIfPresent(fileConfig.getId())); + } + + @Test + public void testUpdateFileConfig_notExists() { + // 准备参数 + FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> fileConfigService.updateFileConfig(reqVO), FILE_CONFIG_NOT_EXISTS); + } + + @Test + public void testUpdateFileConfigMaster_success() { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + FileConfigDO masterFileConfig = randomFileConfigDO().setMaster(true); + fileConfigMapper.insert(masterFileConfig);// @Sql: 先插入出一条存在的数据 + + // 调用 + fileConfigService.updateFileConfigMaster(dbFileConfig.getId()); + // 断言数据 + assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); + assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); + // 验证 cache + assertNull(fileConfigService.getClientCache().getIfPresent(0L)); + } + + @Test + public void testUpdateFileConfigMaster_notExists() { + // 调用, 并断言异常 + assertServiceException(() -> fileConfigService.updateFileConfigMaster(randomLongId()), FILE_CONFIG_NOT_EXISTS); + } + + @Test + public void testDeleteFileConfig_success() { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbFileConfig.getId(); + + // 调用 + fileConfigService.deleteFileConfig(id); + // 校验数据不存在了 + assertNull(fileConfigMapper.selectById(id)); + // 验证 cache + assertNull(fileConfigService.getClientCache().getIfPresent(id)); + } + + @Test + public void testDeleteFileConfig_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_NOT_EXISTS); + } + + @Test + public void testDeleteFileConfig_master() { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(true); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbFileConfig.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_DELETE_FAIL_MASTER); + } + + @Test + public void testGetFileConfigPage() { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码") + .setStorage(FileStorageEnum.LOCAL.getStorage()); + dbFileConfig.setCreateTime(LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN));// 等会查询到 + fileConfigMapper.insert(dbFileConfig); + // 测试 name 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码"))); + // 测试 storage 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage()))); + // 测试 createTime 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(LocalDateTimeUtil.parse("2020-11-23", DatePattern.NORM_DATE_PATTERN)))); + // 准备参数 + FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); + reqVO.setName("芋道"); + reqVO.setStorage(FileStorageEnum.LOCAL.getStorage()); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2020, 1, 1), + buildTime(2020, 1, 24)})); + + // 调用 + PageResult pageResult = fileConfigService.getFileConfigPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); + } + + @Test + public void testFileConfig() throws Exception { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbFileConfig.getId(); + // mock 获得 Client + FileClient fileClient = mock(FileClient.class); + when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); + when(fileClient.upload(any(), any(), any())).thenReturn("https://www.iocoder.cn"); + + // 调用,并断言 + assertEquals("https://www.iocoder.cn", fileConfigService.testFileConfig(id)); + } + + @Test + public void testGetFileConfig() { + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbFileConfig.getId(); + + // 调用,并断言 + assertPojoEquals(dbFileConfig, fileConfigService.getFileConfig(id)); + } + + @Test + public void testGetFileClient() { + // mock 数据 + FileConfigDO fileConfig = randomFileConfigDO().setMaster(false); + fileConfigMapper.insert(fileConfig); + // 准备参数 + Long id = fileConfig.getId(); + // mock 获得 Client + FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); + when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); + + // 调用,并断言 + assertSame(fileClient, fileConfigService.getFileClient(id)); + // 断言缓存 + verify(fileClientFactory).createOrUpdateFileClient(eq(id), eq(fileConfig.getStorage()), + eq(fileConfig.getConfig())); + } + + @Test + public void testGetMasterFileClient() { + // mock 数据 + FileConfigDO fileConfig = randomFileConfigDO().setMaster(true); + fileConfigMapper.insert(fileConfig); + // 准备参数 + Long id = fileConfig.getId(); + // mock 获得 Client + FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); + when(fileClientFactory.getFileClient(eq(fileConfig.getId()))).thenReturn(fileClient); + + // 调用,并断言 + assertSame(fileClient, fileConfigService.getMasterFileClient()); + // 断言缓存 + verify(fileClientFactory).createOrUpdateFileClient(eq(fileConfig.getId()), eq(fileConfig.getStorage()), + eq(fileConfig.getConfig())); + } + + private FileConfigDO randomFileConfigDO() { + return randomPojo(FileConfigDO.class).setStorage(randomEle(FileStorageEnum.values()).getStorage()) + .setConfig(new EmptyFileClientConfig()); + } + + @Data + public static class EmptyFileClientConfig implements FileClientConfig, Serializable { + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java new file mode 100644 index 0000000..dff95c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java @@ -0,0 +1,143 @@ +package cn.iocoder.yudao.module.infra.service.file; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +@Import({FileServiceImpl.class}) +public class FileServiceImplTest extends BaseDbUnitTest { + + @Resource + private FileService fileService; + + @Resource + private FileMapper fileMapper; + + @MockBean + private FileConfigService fileConfigService; + + @Test + public void testGetFilePage() { + // mock 数据 + FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 + o.setPath("yunai"); + o.setType("image/jpg"); + o.setCreateTime(buildTime(2021, 1, 15)); + }); + fileMapper.insert(dbFile); + // 测试 path 不匹配 + fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou"))); + // 测试 type 不匹配 + fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { + o.setType("image/png"); + })); + // 测试 createTime 不匹配 + fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { + o.setCreateTime(buildTime(2020, 1, 15)); + })); + // 准备参数 + FilePageReqVO reqVO = new FilePageReqVO(); + reqVO.setPath("yunai"); + reqVO.setType("jp"); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 1, 10), buildTime(2021, 1, 20)})); + + // 调用 + PageResult pageResult = fileService.getFilePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + AssertUtils.assertPojoEquals(dbFile, pageResult.getList().get(0)); + } + + @Test + public void testCreateFile_success() throws Exception { + // 准备参数 + String path = randomString(); + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + // mock Master 文件客户端 + FileClient client = mock(FileClient.class); + when(fileConfigService.getMasterFileClient()).thenReturn(client); + String url = randomString(); + when(client.upload(same(content), same(path), eq("image/jpeg"))).thenReturn(url); + when(client.getId()).thenReturn(10L); + String name = "单测文件名"; + // 调用 + String result = fileService.createFile(name, path, content); + // 断言 + assertEquals(result, url); + // 校验数据 + FileDO file = fileMapper.selectOne(FileDO::getPath, path); + assertEquals(10L, file.getConfigId()); + assertEquals(path, file.getPath()); + assertEquals(url, file.getUrl()); + assertEquals("image/jpeg", file.getType()); + assertEquals(content.length, file.getSize()); + } + + @Test + public void testDeleteFile_success() throws Exception { + // mock 数据 + FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("tudou.jpg")); + fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 + // mock Master 文件客户端 + FileClient client = mock(FileClient.class); + when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); + // 准备参数 + Long id = dbFile.getId(); + + // 调用 + fileService.deleteFile(id); + // 校验数据不存在了 + assertNull(fileMapper.selectById(id)); + // 校验调用 + verify(client).delete(eq("tudou.jpg")); + } + + @Test + public void testDeleteFile_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS); + } + + @Test + public void testGetFileContent() throws Exception { + // 准备参数 + Long configId = 10L; + String path = "tudou.jpg"; + // mock 方法 + FileClient client = mock(FileClient.class); + when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); + byte[] content = new byte[]{}; + when(client.getContent(eq("tudou.jpg"))).thenReturn(content); + + // 调用 + byte[] result = fileService.getFileContent(configId, path); + // 断言 + assertSame(result, content); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImplTest.java new file mode 100644 index 0000000..c916cf5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImplTest.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper; +import cn.iocoder.yudao.module.infra.enums.job.JobLogStatusEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Import(JobLogServiceImpl.class) +public class JobLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private JobLogServiceImpl jobLogService; + @Resource + private JobLogMapper jobLogMapper; + + @Test + public void testCreateJobLog() { + // 准备参数 + JobLogDO reqVO = randomPojo(JobLogDO.class, o -> o.setExecuteIndex(1)); + + // 调用 + Long id = jobLogService.createJobLog(reqVO.getJobId(), reqVO.getBeginTime(), + reqVO.getHandlerName(), reqVO.getHandlerParam(), reqVO.getExecuteIndex()); + // 断言 + assertNotNull(id); + // 校验记录的属性是否正确 + JobLogDO job = jobLogMapper.selectById(id); + assertEquals(JobLogStatusEnum.RUNNING.getStatus(), job.getStatus()); + } + + @Test + public void testUpdateJobLogResultAsync_success() { + // mock 数据 + JobLogDO log = randomPojo(JobLogDO.class, o -> { + o.setExecuteIndex(1); + o.setStatus(JobLogStatusEnum.RUNNING.getStatus()); + }); + jobLogMapper.insert(log); + // 准备参数 + Long logId = log.getId(); + LocalDateTime endTime = randomLocalDateTime(); + Integer duration = randomInteger(); + boolean success = true; + String result = randomString(); + + // 调用 + jobLogService.updateJobLogResultAsync(logId, endTime, duration, success, result); + // 校验记录的属性是否正确 + JobLogDO dbLog = jobLogMapper.selectById(log.getId()); + assertEquals(endTime, dbLog.getEndTime()); + assertEquals(duration, dbLog.getDuration()); + assertEquals(JobLogStatusEnum.SUCCESS.getStatus(), dbLog.getStatus()); + assertEquals(result, dbLog.getResult()); + } + + @Test + public void testUpdateJobLogResultAsync_failure() { + // mock 数据 + JobLogDO log = randomPojo(JobLogDO.class, o -> { + o.setExecuteIndex(1); + o.setStatus(JobLogStatusEnum.RUNNING.getStatus()); + }); + jobLogMapper.insert(log); + // 准备参数 + Long logId = log.getId(); + LocalDateTime endTime = randomLocalDateTime(); + Integer duration = randomInteger(); + boolean success = false; + String result = randomString(); + + // 调用 + jobLogService.updateJobLogResultAsync(logId, endTime, duration, success, result); + // 校验记录的属性是否正确 + JobLogDO dbLog = jobLogMapper.selectById(log.getId()); + assertEquals(endTime, dbLog.getEndTime()); + assertEquals(duration, dbLog.getDuration()); + assertEquals(JobLogStatusEnum.FAILURE.getStatus(), dbLog.getStatus()); + assertEquals(result, dbLog.getResult()); + } + + @Test + public void testCleanJobLog() { + // mock 数据 + JobLogDO log01 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3)))) + .setExecuteIndex(1); + jobLogMapper.insert(log01); + JobLogDO log02 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1)))) + .setExecuteIndex(1); + jobLogMapper.insert(log02); + // 准备参数 + Integer exceedDay = 2; + Integer deleteLimit = 1; + + // 调用 + Integer count = jobLogService.cleanJobLog(exceedDay, deleteLimit); + // 断言 + assertEquals(1, count); + List logs = jobLogMapper.selectList(); + assertEquals(1, logs.size()); + assertEquals(log02, logs.get(0)); + } + + @Test + public void testGetJobLog() { + // mock 数据 + JobLogDO dbJobLog = randomPojo(JobLogDO.class, o -> o.setExecuteIndex(1)); + jobLogMapper.insert(dbJobLog); + // 准备参数 + Long id = dbJobLog.getId(); + + // 调用 + JobLogDO jobLog = jobLogService.getJobLog(id); + // 断言 + assertPojoEquals(dbJobLog, jobLog); + } + + @Test + public void testGetJobPage() { + // mock 数据 + JobLogDO dbJobLog = randomPojo(JobLogDO.class, o -> { + o.setExecuteIndex(1); + o.setHandlerName("handlerName 单元测试"); + o.setStatus(JobLogStatusEnum.SUCCESS.getStatus()); + o.setBeginTime(buildTime(2021, 1, 8)); + o.setEndTime(buildTime(2021, 1, 8)); + }); + jobLogMapper.insert(dbJobLog); + // 测试 jobId 不匹配 + jobLogMapper.insert(cloneIgnoreId(dbJobLog, o -> o.setJobId(randomLongId()))); + // 测试 handlerName 不匹配 + jobLogMapper.insert(cloneIgnoreId(dbJobLog, o -> o.setHandlerName(randomString()))); + // 测试 beginTime 不匹配 + jobLogMapper.insert(cloneIgnoreId(dbJobLog, o -> o.setBeginTime(buildTime(2021, 1, 7)))); + // 测试 endTime 不匹配 + jobLogMapper.insert(cloneIgnoreId(dbJobLog, o -> o.setEndTime(buildTime(2021, 1, 9)))); + // 测试 status 不匹配 + jobLogMapper.insert(cloneIgnoreId(dbJobLog, o -> o.setStatus(JobLogStatusEnum.FAILURE.getStatus()))); + // 准备参数 + JobLogPageReqVO reqVo = new JobLogPageReqVO(); + reqVo.setJobId(dbJobLog.getJobId()); + reqVo.setHandlerName("单元"); + reqVo.setBeginTime(dbJobLog.getBeginTime()); + reqVo.setEndTime(dbJobLog.getEndTime()); + reqVo.setStatus(JobLogStatusEnum.SUCCESS.getStatus()); + + // 调用 + PageResult pageResult = jobLogService.getJobLogPage(reqVo); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbJobLog, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java new file mode 100644 index 0000000..204c59e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java @@ -0,0 +1,257 @@ +package cn.iocoder.yudao.module.infra.service.job; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; +import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper; +import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum; +import cn.iocoder.yudao.module.infra.job.job.JobLogCleanJob; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.quartz.SchedulerException; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; + +@Import(JobServiceImpl.class) +public class JobServiceImplTest extends BaseDbUnitTest { + + @Resource + private JobServiceImpl jobService; + @Resource + private JobMapper jobMapper; + @MockBean + private SchedulerManager schedulerManager; + + @MockBean + private JobLogCleanJob jobLogCleanJob; + + @Test + public void testCreateJob_cronExpressionValid() { + // 准备参数。Cron 表达式为 String 类型,默认随机字符串。 + JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class); + + // 调用,并断言异常 + assertServiceException(() -> jobService.createJob(reqVO), JOB_CRON_EXPRESSION_VALID); + } + + @Test + public void testCreateJob_jobHandlerExists() throws SchedulerException { + // 准备参数 指定 Cron 表达式 + JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *")); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); + + // 调用 + jobService.createJob(reqVO); + // 调用,并断言异常 + assertServiceException(() -> jobService.createJob(reqVO), JOB_HANDLER_EXISTS); + } + } + + @Test + public void testCreateJob_success() throws SchedulerException { + // 准备参数 指定 Cron 表达式 + JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *")) + .setId(null); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); + + // 调用 + Long jobId = jobService.createJob(reqVO); + // 断言 + assertNotNull(jobId); + // 校验记录的属性是否正确 + JobDO job = jobMapper.selectById(jobId); + assertPojoEquals(reqVO, job, "id"); + assertEquals(JobStatusEnum.NORMAL.getStatus(), job.getStatus()); + // 校验调用 + verify(schedulerManager).addJob(eq(job.getId()), eq(job.getHandlerName()), eq(job.getHandlerParam()), + eq(job.getCronExpression()), eq(reqVO.getRetryCount()), eq(reqVO.getRetryInterval())); + } + } + + @Test + public void testUpdateJob_jobNotExists(){ + // 准备参数 + JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *")); + + // 调用,并断言异常 + assertServiceException(() -> jobService.updateJob(reqVO), JOB_NOT_EXISTS); + } + + @Test + public void testUpdateJob_onlyNormalStatus(){ + // mock 数据 + JobDO job = randomPojo(JobDO.class, o -> o.setStatus(JobStatusEnum.INIT.getStatus())); + jobMapper.insert(job); + // 准备参数 + JobSaveReqVO updateReqVO = randomPojo(JobSaveReqVO.class, o -> { + o.setId(job.getId()); + o.setCronExpression("0 0/1 * * * ? *"); + }); + + // 调用,并断言异常 + assertServiceException(() -> jobService.updateJob(updateReqVO), + JOB_UPDATE_ONLY_NORMAL_STATUS); + } + + @Test + public void testUpdateJob_success() throws SchedulerException { + // mock 数据 + JobDO job = randomPojo(JobDO.class, o -> o.setStatus(JobStatusEnum.NORMAL.getStatus())); + jobMapper.insert(job); + // 准备参数 + JobSaveReqVO updateReqVO = randomPojo(JobSaveReqVO.class, o -> { + o.setId(job.getId()); + o.setCronExpression("0 0/1 * * * ? *"); + }); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(updateReqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); + + // 调用 + jobService.updateJob(updateReqVO); + // 校验记录的属性是否正确 + JobDO updateJob = jobMapper.selectById(updateReqVO.getId()); + assertPojoEquals(updateReqVO, updateJob); + // 校验调用 + verify(schedulerManager).updateJob(eq(job.getHandlerName()), eq(updateReqVO.getHandlerParam()), + eq(updateReqVO.getCronExpression()), eq(updateReqVO.getRetryCount()), eq(updateReqVO.getRetryInterval())); + } + } + + @Test + public void testUpdateJobStatus_changeStatusInvalid() { + // 调用,并断言异常 + assertServiceException(() -> jobService.updateJobStatus(1L, JobStatusEnum.INIT.getStatus()), + JOB_CHANGE_STATUS_INVALID); + } + + @Test + public void testUpdateJobStatus_changeStatusEquals() { + // mock 数据 + JobDO job = randomPojo(JobDO.class, o -> o.setStatus(JobStatusEnum.NORMAL.getStatus())); + jobMapper.insert(job); + + // 调用,并断言异常 + assertServiceException(() -> jobService.updateJobStatus(job.getId(), job.getStatus()), + JOB_CHANGE_STATUS_EQUALS); + } + + @Test + public void testUpdateJobStatus_stopSuccess() throws SchedulerException { + // mock 数据 + JobDO job = randomPojo(JobDO.class, o -> o.setStatus(JobStatusEnum.NORMAL.getStatus())); + jobMapper.insert(job); + + // 调用 + jobService.updateJobStatus(job.getId(), JobStatusEnum.STOP.getStatus()); + // 校验记录的属性是否正确 + JobDO dbJob = jobMapper.selectById(job.getId()); + assertEquals(JobStatusEnum.STOP.getStatus(), dbJob.getStatus()); + // 校验调用 + verify(schedulerManager).pauseJob(eq(job.getHandlerName())); + } + + @Test + public void testUpdateJobStatus_normalSuccess() throws SchedulerException { + // mock 数据 + JobDO job = randomPojo(JobDO.class, o -> o.setStatus(JobStatusEnum.STOP.getStatus())); + jobMapper.insert(job); + + // 调用 + jobService.updateJobStatus(job.getId(), JobStatusEnum.NORMAL.getStatus()); + // 校验记录的属性是否正确 + JobDO dbJob = jobMapper.selectById(job.getId()); + assertEquals(JobStatusEnum.NORMAL.getStatus(), dbJob.getStatus()); + // 校验调用 + verify(schedulerManager).resumeJob(eq(job.getHandlerName())); + } + + @Test + public void testTriggerJob_success() throws SchedulerException { + // mock 数据 + JobDO job = randomPojo(JobDO.class); + jobMapper.insert(job); + + // 调用 + jobService.triggerJob(job.getId()); + // 校验调用 + verify(schedulerManager).triggerJob(eq(job.getId()), + eq(job.getHandlerName()), eq(job.getHandlerParam())); + } + + @Test + public void testDeleteJob_success() throws SchedulerException { + // mock 数据 + JobDO job = randomPojo(JobDO.class); + jobMapper.insert(job); + + // 调用 + jobService.deleteJob(job.getId()); + // 校验不存在 + assertNull(jobMapper.selectById(job.getId())); + // 校验调用 + verify(schedulerManager).deleteJob(eq(job.getHandlerName())); + } + + @Test + public void testGetJobPage() { + // mock 数据 + JobDO dbJob = randomPojo(JobDO.class, o -> { + o.setName("定时任务测试"); + o.setHandlerName("handlerName 单元测试"); + o.setStatus(JobStatusEnum.INIT.getStatus()); + }); + jobMapper.insert(dbJob); + // 测试 name 不匹配 + jobMapper.insert(cloneIgnoreId(dbJob, o -> o.setName("土豆"))); + // 测试 status 不匹配 + jobMapper.insert(cloneIgnoreId(dbJob, o -> o.setStatus(JobStatusEnum.NORMAL.getStatus()))); + // 测试 handlerName 不匹配 + jobMapper.insert(cloneIgnoreId(dbJob, o -> o.setHandlerName(randomString()))); + // 准备参数 + JobPageReqVO reqVo = new JobPageReqVO(); + reqVo.setName("定时"); + reqVo.setStatus(JobStatusEnum.INIT.getStatus()); + reqVo.setHandlerName("单元"); + + // 调用 + PageResult pageResult = jobService.getJobPage(reqVo); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbJob, pageResult.getList().get(0)); + } + + @Test + public void testGetJob() { + // mock 数据 + JobDO dbJob = randomPojo(JobDO.class); + jobMapper.insert(dbJob); + // 调用 + JobDO job = jobService.getJob(dbJob.getId()); + // 断言 + assertPojoEquals(dbJob, job); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java new file mode 100644 index 0000000..02362c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiAccessLogMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Import(ApiAccessLogServiceImpl.class) +public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private ApiAccessLogServiceImpl apiAccessLogService; + + @Resource + private ApiAccessLogMapper apiAccessLogMapper; + + @Test + public void testGetApiAccessLogPage() { + ApiAccessLogDO apiAccessLogDO = randomPojo(ApiAccessLogDO.class, o -> { + o.setUserId(2233L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setApplicationName("yudao-test"); + o.setRequestUrl("foo"); + o.setBeginTime(buildTime(2021, 3, 13)); + o.setDuration(1000); + o.setResultCode(GlobalErrorCodeConstants.SUCCESS.getCode()); + }); + apiAccessLogMapper.insert(apiAccessLogDO); + // 测试 userId 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setUserId(3344L))); + // 测试 userType 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 applicationName 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setApplicationName("test"))); + // 测试 requestUrl 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setRequestUrl("bar"))); + // 测试 beginTime 不匹配:构造一个早期时间 2021-02-06 00:00:00 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setBeginTime(buildTime(2021, 2, 6)))); + // 测试 duration 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setDuration(100))); + // 测试 resultCode 不匹配 + apiAccessLogMapper.insert(cloneIgnoreId(apiAccessLogDO, o -> o.setResultCode(2))); + // 准备参数 + ApiAccessLogPageReqVO reqVO = new ApiAccessLogPageReqVO(); + reqVO.setUserId(2233L); + reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); + reqVO.setApplicationName("yudao-test"); + reqVO.setRequestUrl("foo"); + reqVO.setBeginTime(buildBetweenTime(2021, 3, 13, 2021, 3, 13)); + reqVO.setDuration(1000); + reqVO.setResultCode(GlobalErrorCodeConstants.SUCCESS.getCode()); + + // 调用 + PageResult pageResult = apiAccessLogService.getApiAccessLogPage(reqVO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(apiAccessLogDO, pageResult.getList().get(0)); + } + + @Test + public void testCleanJobLog() { + // mock 数据 + ApiAccessLogDO log01 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3)))); + apiAccessLogMapper.insert(log01); + ApiAccessLogDO log02 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1)))); + apiAccessLogMapper.insert(log02); + // 准备参数 + Integer exceedDay = 2; + Integer deleteLimit = 1; + + // 调用 + Integer count = apiAccessLogService.cleanAccessLog(exceedDay, deleteLimit); + // 断言 + assertEquals(1, count); + List logs = apiAccessLogMapper.selectList(); + assertEquals(1, logs.size()); + assertEquals(log02, logs.get(0)); + } + + @Test + public void testCreateApiAccessLog() { + // 准备参数 + ApiAccessLogCreateReqDTO createDTO = randomPojo(ApiAccessLogCreateReqDTO.class); + + // 调用 + apiAccessLogService.createApiAccessLog(createDTO); + // 断言 + ApiAccessLogDO apiAccessLogDO = apiAccessLogMapper.selectOne(null); + assertPojoEquals(createDTO, apiAccessLogDO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java new file mode 100644 index 0000000..ba9b93b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.infra.service.logger; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; +import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; +import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper; +import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.List; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_NOT_FOUND; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_LOG_PROCESSED; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Import(ApiErrorLogServiceImpl.class) +public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private ApiErrorLogServiceImpl apiErrorLogService; + + @Resource + private ApiErrorLogMapper apiErrorLogMapper; + + @Test + public void testGetApiErrorLogPage() { + // mock 数据 + ApiErrorLogDO apiErrorLogDO = randomPojo(ApiErrorLogDO.class, o -> { + o.setUserId(2233L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setApplicationName("yudao-test"); + o.setRequestUrl("foo"); + o.setExceptionTime(buildTime(2021, 3, 13)); + o.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); + }); + apiErrorLogMapper.insert(apiErrorLogDO); + // 测试 userId 不匹配 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L))); + // 测试 userType 不匹配 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 applicationName 不匹配 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setApplicationName("test"))); + // 测试 requestUrl 不匹配 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setRequestUrl("bar"))); + // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setExceptionTime(buildTime(2021, 2, 6)))); + // 测试 progressStatus 不匹配 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus()))); + // 准备参数 + ApiErrorLogPageReqVO reqVO = new ApiErrorLogPageReqVO(); + reqVO.setUserId(2233L); + reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); + reqVO.setApplicationName("yudao-test"); + reqVO.setRequestUrl("foo"); + reqVO.setExceptionTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31)); + reqVO.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); + + // 调用 + PageResult pageResult = apiErrorLogService.getApiErrorLogPage(reqVO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(apiErrorLogDO, pageResult.getList().get(0)); + } + + @Test + public void testCreateApiErrorLog() { + // 准备参数 + ApiErrorLogCreateReqDTO createDTO = randomPojo(ApiErrorLogCreateReqDTO.class); + + // 调用 + apiErrorLogService.createApiErrorLog(createDTO); + // 断言 + ApiErrorLogDO apiErrorLogDO = apiErrorLogMapper.selectOne(null); + assertPojoEquals(createDTO, apiErrorLogDO); + assertEquals(ApiErrorLogProcessStatusEnum.INIT.getStatus(), apiErrorLogDO.getProcessStatus()); + } + + @Test + public void testUpdateApiErrorLogProcess_success() { + // 准备参数 + ApiErrorLogDO apiErrorLogDO = randomPojo(ApiErrorLogDO.class, + o -> o.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus())); + apiErrorLogMapper.insert(apiErrorLogDO); + // 准备参数 + Long id = apiErrorLogDO.getId(); + Integer processStatus = randomEle(ApiErrorLogProcessStatusEnum.values()).getStatus(); + Long processUserId = randomLongId(); + + // 调用 + apiErrorLogService.updateApiErrorLogProcess(id, processStatus, processUserId); + // 断言 + ApiErrorLogDO dbApiErrorLogDO = apiErrorLogMapper.selectById(apiErrorLogDO.getId()); + assertEquals(processStatus, dbApiErrorLogDO.getProcessStatus()); + assertEquals(processUserId, dbApiErrorLogDO.getProcessUserId()); + assertNotNull(dbApiErrorLogDO.getProcessTime()); + } + + @Test + public void testUpdateApiErrorLogProcess_processed() { + // 准备参数 + ApiErrorLogDO apiErrorLogDO = randomPojo(ApiErrorLogDO.class, + o -> o.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus())); + apiErrorLogMapper.insert(apiErrorLogDO); + // 准备参数 + Long id = apiErrorLogDO.getId(); + Integer processStatus = randomEle(ApiErrorLogProcessStatusEnum.values()).getStatus(); + Long processUserId = randomLongId(); + + // 调用,并断言异常 + assertServiceException(() -> + apiErrorLogService.updateApiErrorLogProcess(id, processStatus, processUserId), + API_ERROR_LOG_PROCESSED); + } + + @Test + public void testUpdateApiErrorLogProcess_notFound() { + // 准备参数 + Long id = randomLongId(); + Integer processStatus = randomEle(ApiErrorLogProcessStatusEnum.values()).getStatus(); + Long processUserId = randomLongId(); + + // 调用,并断言异常 + assertServiceException(() -> + apiErrorLogService.updateApiErrorLogProcess(id, processStatus, processUserId), + API_ERROR_LOG_NOT_FOUND); + } + + @Test + public void testCleanJobLog() { + // mock 数据 + ApiErrorLogDO log01 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3)))); + apiErrorLogMapper.insert(log01); + ApiErrorLogDO log02 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1)))); + apiErrorLogMapper.insert(log02); + // 准备参数 + Integer exceedDay = 2; + Integer deleteLimit = 1; + + // 调用 + Integer count = apiErrorLogService.cleanErrorLog(exceedDay, deleteLimit); + // 断言 + assertEquals(1, count); + List logs = apiErrorLogMapper.selectList(); + assertEquals(1, logs.size()); + assertEquals(log02, logs.get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..3dfadda --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,48 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis-plus: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json new file mode 100644 index 0000000..033c048 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json @@ -0,0 +1,52 @@ +{ + "table": { + "id": 10, + "scene" : 1, + "parentMenuId" : 888, + "tableName" : "infra_category", + "tableComment" : "分类表", + "moduleName" : "infra", + "businessName" : "demo", + "className" : "InfraCategory", + "classComment" : "分类", + "author" : "芋道源码", + "treeParentColumnId" : 22, + "treeNameColumnId" : 11 + }, + "columns": [ { + "columnName" : "id", + "dataType" : "BIGINT", + "columnComment" : "编号", + "primaryKey" : true, + "javaType" : "Long", + "javaField" : "id", + "example" : "1024", + "updateOperation" : true, + "listOperationResult" : true + }, { + "id" : 11, + "columnName" : "name", + "dataType" : "VARCHAR", + "columnComment" : "名字", + "javaType" : "String", + "javaField" : "name", + "example" : "芋头", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "LIKE", + "listOperationResult" : true, + "htmlType" : "input" + }, { + "id" : 22, + "columnName" : "description", + "dataType" : "VARCHAR", + "columnComment" : "父编号", + "javaType" : "Long", + "javaField" : "parentId", + "example" : "2048", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true + } ] +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json new file mode 100644 index 0000000..74f92cd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json @@ -0,0 +1,143 @@ +{ + "table": { + "scene" : 1, + "tableName" : "infra_student_contact", + "tableComment" : "学生联系人表", + "moduleName" : "infra", + "businessName" : "demo", + "className" : "InfraStudentContact", + "classComment" : "学生联系人", + "author" : "芋道源码" + }, + "columns": [ { + "columnName" : "id", + "dataType" : "BIGINT", + "columnComment" : "编号", + "primaryKey" : true, + "javaType" : "Long", + "javaField" : "id", + "example" : "1024", + "updateOperation" : true, + "listOperationResult" : true + }, { + "id" : 100, + "columnName" : "student_id", + "dataType" : "BIGINT", + "columnComment" : "学生编号", + "javaType" : "Long", + "javaField" : "studentId", + "example" : "2048", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true + }, { + "columnName" : "name", + "dataType" : "VARCHAR", + "columnComment" : "名字", + "javaType" : "String", + "javaField" : "name", + "example" : "芋头", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "LIKE", + "listOperationResult" : true, + "htmlType" : "input" + }, { + "columnName" : "description", + "dataType" : "VARCHAR", + "columnComment" : "简介", + "javaType" : "String", + "javaField" : "description", + "example" : "我是介绍", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "textarea" + }, { + "columnName" : "birthday", + "dataType" : "DATE", + "columnComment" : "出生日期", + "javaType" : "LocalDateTime", + "javaField" : "birthday", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "datetime" + }, { + "columnName" : "sex", + "dataType" : "INTEGER", + "columnComment" : "性别", + "javaType" : "Integer", + "javaField" : "sex", + "dictType" : "system_user_sex", + "example" : "1", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "select" + }, { + "columnName" : "enabled", + "dataType" : "BOOLEAN", + "columnComment" : "是否有效", + "javaType" : "Boolean", + "javaField" : "enabled", + "dictType" : "infra_boolean_string", + "example" : "true", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "radio" + }, { + "columnName" : "avatar", + "dataType" : "VARCHAR", + "columnComment" : "头像", + "javaType" : "String", + "javaField" : "avatar", + "example" : "https://www.iocoder.cn/1.png", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "imageUpload" + }, { + "columnName" : "video", + "dataType" : "VARCHAR", + "columnComment" : "附件", + "nullable" : true, + "javaType" : "String", + "javaField" : "video", + "example" : "https://www.iocoder.cn/1.mp4", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "fileUpload" + }, { + "columnName" : "memo", + "dataType" : "VARCHAR", + "columnComment" : "备注", + "javaType" : "String", + "javaField" : "memo", + "example" : "我是备注", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "editor" + }, { + "columnName" : "create_time", + "dataType" : "DATE", + "columnComment" : "创建时间", + "nullable" : true, + "javaType" : "LocalDateTime", + "javaField" : "createTime", + "listOperation" : true, + "listOperationCondition" : "BETWEEN", + "listOperationResult" : true, + "htmlType" : "datetime" + } ] +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json new file mode 100644 index 0000000..efe8af4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json @@ -0,0 +1,134 @@ +{ + "table": { + "id": 1, + "scene" : 1, + "parentMenuId" : 888, + "tableName" : "infra_student", + "tableComment" : "学生表", + "moduleName" : "infra", + "businessName" : "demo", + "className" : "InfraStudent", + "classComment" : "学生", + "author" : "芋道源码" + }, + "columns": [ { + "id" : 100, + "columnName" : "id", + "dataType" : "BIGINT", + "columnComment" : "编号", + "primaryKey" : true, + "javaType" : "Long", + "javaField" : "id", + "example" : "1024", + "updateOperation" : true, + "listOperationResult" : true + }, { + "columnName" : "name", + "dataType" : "VARCHAR", + "columnComment" : "名字", + "javaType" : "String", + "javaField" : "name", + "example" : "芋头", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "LIKE", + "listOperationResult" : true, + "htmlType" : "input" + }, { + "columnName" : "description", + "dataType" : "VARCHAR", + "columnComment" : "简介", + "javaType" : "String", + "javaField" : "description", + "example" : "我是介绍", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "textarea" + }, { + "columnName" : "birthday", + "dataType" : "DATE", + "columnComment" : "出生日期", + "javaType" : "LocalDateTime", + "javaField" : "birthday", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "datetime" + }, { + "columnName" : "sex", + "dataType" : "INTEGER", + "columnComment" : "性别", + "javaType" : "Integer", + "javaField" : "sex", + "dictType" : "system_user_sex", + "example" : "1", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "select" + }, { + "columnName" : "enabled", + "dataType" : "BOOLEAN", + "columnComment" : "是否有效", + "javaType" : "Boolean", + "javaField" : "enabled", + "dictType" : "infra_boolean_string", + "example" : "true", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "radio" + }, { + "columnName" : "avatar", + "dataType" : "VARCHAR", + "columnComment" : "头像", + "javaType" : "String", + "javaField" : "avatar", + "example" : "https://www.iocoder.cn/1.png", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "imageUpload" + }, { + "columnName" : "video", + "dataType" : "VARCHAR", + "columnComment" : "附件", + "javaType" : "String", + "javaField" : "video", + "example" : "https://www.iocoder.cn/1.mp4", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "fileUpload" + }, { + "columnName" : "memo", + "dataType" : "VARCHAR", + "columnComment" : "备注", + "javaType" : "String", + "javaField" : "memo", + "example" : "我是备注", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "editor" + }, { + "columnName" : "create_time", + "dataType" : "DATE", + "columnComment" : "创建时间", + "nullable" : true, + "javaType" : "LocalDateTime", + "javaField" : "createTime", + "listOperation" : true, + "listOperationCondition" : "BETWEEN", + "listOperationResult" : true, + "htmlType" : "datetime" + } ] +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json new file mode 100644 index 0000000..4d93518 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json @@ -0,0 +1,143 @@ +{ + "table": { + "scene" : 1, + "tableName" : "infra_student_teacher", + "tableComment" : "学生班主任表", + "moduleName" : "infra", + "businessName" : "demo", + "className" : "InfraStudentTeacher", + "classComment" : "学生班主任", + "author" : "芋道源码" + }, + "columns": [ { + "columnName" : "id", + "dataType" : "BIGINT", + "columnComment" : "编号", + "primaryKey" : true, + "javaType" : "Long", + "javaField" : "id", + "example" : "1024", + "updateOperation" : true, + "listOperationResult" : true + }, { + "id" : 200, + "columnName" : "student_id", + "dataType" : "BIGINT", + "columnComment" : "学生编号", + "javaType" : "Long", + "javaField" : "studentId", + "example" : "2048", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true + }, { + "columnName" : "name", + "dataType" : "VARCHAR", + "columnComment" : "名字", + "javaType" : "String", + "javaField" : "name", + "example" : "芋头", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "LIKE", + "listOperationResult" : true, + "htmlType" : "input" + }, { + "columnName" : "description", + "dataType" : "VARCHAR", + "columnComment" : "简介", + "javaType" : "String", + "javaField" : "description", + "example" : "我是介绍", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "textarea" + }, { + "columnName" : "birthday", + "dataType" : "DATE", + "columnComment" : "出生日期", + "javaType" : "LocalDateTime", + "javaField" : "birthday", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "datetime" + }, { + "columnName" : "sex", + "dataType" : "INTEGER", + "columnComment" : "性别", + "javaType" : "Integer", + "javaField" : "sex", + "dictType" : "system_user_sex", + "example" : "1", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "select" + }, { + "columnName" : "enabled", + "dataType" : "BOOLEAN", + "columnComment" : "是否有效", + "javaType" : "Boolean", + "javaField" : "enabled", + "dictType" : "infra_boolean_string", + "example" : "true", + "createOperation" : true, + "updateOperation" : true, + "listOperation" : true, + "listOperationCondition" : "=", + "listOperationResult" : true, + "htmlType" : "radio" + }, { + "columnName" : "avatar", + "dataType" : "VARCHAR", + "columnComment" : "头像", + "javaType" : "String", + "javaField" : "avatar", + "example" : "https://www.iocoder.cn/1.png", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "imageUpload" + }, { + "columnName" : "video", + "dataType" : "VARCHAR", + "columnComment" : "附件", + "nullable" : true, + "javaType" : "String", + "javaField" : "video", + "example" : "https://www.iocoder.cn/1.mp4", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "fileUpload" + }, { + "columnName" : "memo", + "dataType" : "VARCHAR", + "columnComment" : "备注", + "javaType" : "String", + "javaField" : "memo", + "example" : "我是备注", + "createOperation" : true, + "updateOperation" : true, + "listOperationResult" : true, + "htmlType" : "editor" + }, { + "columnName" : "create_time", + "dataType" : "DATE", + "columnComment" : "创建时间", + "nullable" : true, + "javaType" : "LocalDateTime", + "javaField" : "createTime", + "listOperation" : true, + "listOperationCondition" : "BETWEEN", + "listOperationResult" : true, + "htmlType" : "datetime" + } ] +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/assert.json new file mode 100644 index 0000000..8edb8e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/assert.json @@ -0,0 +1,73 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue" +}, { + "contentPath": "js/index", + "filePath": "yudao-ui-admin-vue2/src/api/infra/demo/index.js" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentTeacherForm.vue" +}, { + "contentPath" : "vue/StudentContactList", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentContactList.vue" +}, { + "contentPath" : "vue/StudentTeacherList", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentTeacherList.vue" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..d3201de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,6 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); +ErrorCode STUDENT_CONTACT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生联系人不存在"); +ErrorCode STUDENT_TEACHER_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任不存在"); +ErrorCode STUDENT_TEACHER_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任已存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactMapper new file mode 100644 index 0000000..ca662d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(InfraStudentContactDO::getStudentId, studentId) + .orderByDesc(InfraStudentContactDO::getId)); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentController new file mode 100644 index 0000000..d6f2018 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentController @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/page") + @Operation(summary = "获得学生联系人分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactPage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactPage(pageReqVO, studentId)); + } + + @PostMapping("/student-contact/create") + @Operation(summary = "创建学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) { + return success(studentService.createStudentContact(studentContact)); + } + + @PutMapping("/student-contact/update") + @Operation(summary = "更新学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) { + studentService.updateStudentContact(studentContact); + return success(true); + } + + @DeleteMapping("/student-contact/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudentContact(@RequestParam("id") Long id) { + studentService.deleteStudentContact(id); + return success(true); + } + + @GetMapping("/student-contact/get") + @Operation(summary = "获得学生联系人") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentContact(@RequestParam("id") Long id) { + return success(studentService.getStudentContact(id)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/page") + @Operation(summary = "获得学生班主任分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentTeacherPage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherPage(pageReqVO, studentId)); + } + + @PostMapping("/student-teacher/create") + @Operation(summary = "创建学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) { + return success(studentService.createStudentTeacher(studentTeacher)); + } + + @PutMapping("/student-teacher/update") + @Operation(summary = "更新学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) { + studentService.updateStudentTeacher(studentTeacher); + return success(true); + } + + @DeleteMapping("/student-teacher/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudentTeacher(@RequestParam("id") Long id) { + studentService.deleteStudentTeacher(id); + return success(true); + } + + @GetMapping("/student-teacher/get") + @Operation(summary = "获得学生班主任") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacher(@RequestParam("id") Long id) { + return success(studentService.getStudentTeacher(id)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..eaadf74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentSaveReqVO @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentService new file mode 100644 index 0000000..7df090d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentService @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生联系人分页 + */ + PageResult getStudentContactPage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生联系人 + * + * @param studentContact 创建信息 + * @return 编号 + */ + Long createStudentContact(@Valid InfraStudentContactDO studentContact); + + /** + * 更新学生联系人 + * + * @param studentContact 更新信息 + */ + void updateStudentContact(@Valid InfraStudentContactDO studentContact); + + /** + * 删除学生联系人 + * + * @param id 编号 + */ + void deleteStudentContact(Long id); + + /** + * 获得学生联系人 + * + * @param id 编号 + * @return 学生联系人 + */ + InfraStudentContactDO getStudentContact(Long id); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生班主任分页 + */ + PageResult getStudentTeacherPage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生班主任 + * + * @param studentTeacher 创建信息 + * @return 编号 + */ + Long createStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher); + + /** + * 更新学生班主任 + * + * @param studentTeacher 更新信息 + */ + void updateStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher); + + /** + * 删除学生班主任 + * + * @param id 编号 + */ + void deleteStudentTeacher(Long id); + + /** + * 获得学生班主任 + * + * @param id 编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacher(Long id); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImpl new file mode 100644 index 0000000..793b2dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImpl @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + // 返回 + return student.getId(); + } + + @Override + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public PageResult getStudentContactPage(PageParam pageReqVO, Long studentId) { + return studentContactMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createStudentContact(InfraStudentContactDO studentContact) { + studentContactMapper.insert(studentContact); + return studentContact.getId(); + } + + @Override + public void updateStudentContact(InfraStudentContactDO studentContact) { + // 校验存在 + validateStudentContactExists(studentContact.getId()); + // 更新 + studentContactMapper.updateById(studentContact); + } + + @Override + public void deleteStudentContact(Long id) { + // 校验存在 + validateStudentContactExists(id); + // 删除 + studentContactMapper.deleteById(id); + } + + @Override + public InfraStudentContactDO getStudentContact(Long id) { + return studentContactMapper.selectById(id); + } + + private void validateStudentContactExists(Long id) { + if (studentContactMapper.selectById(id) == null) { + throw exception(STUDENT_CONTACT_NOT_EXISTS); + } + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public PageResult getStudentTeacherPage(PageParam pageReqVO, Long studentId) { + return studentTeacherMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createStudentTeacher(InfraStudentTeacherDO studentTeacher) { + // 校验是否已经存在 + if (studentTeacherMapper.selectByStudentId(studentTeacher.getStudentId()) != null) { + throw exception(STUDENT_TEACHER_EXISTS); + } + // 插入 + studentTeacherMapper.insert(studentTeacher); + return studentTeacher.getId(); + } + + @Override + public void updateStudentTeacher(InfraStudentTeacherDO studentTeacher) { + // 校验存在 + validateStudentTeacherExists(studentTeacher.getId()); + // 更新 + studentTeacherMapper.updateById(studentTeacher); + } + + @Override + public void deleteStudentTeacher(Long id) { + // 校验存在 + validateStudentTeacherExists(id); + // 删除 + studentTeacherMapper.deleteById(id); + } + + @Override + public InfraStudentTeacherDO getStudentTeacher(Long id) { + return studentTeacherMapper.selectById(id); + } + + private void validateStudentTeacherExists(Long id) { + if (studentTeacherMapper.selectById(id) == null) { + throw exception(STUDENT_TEACHER_NOT_EXISTS); + } + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..994212d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(InfraStudentTeacherDO::getStudentId, studentId) + .orderByDesc(InfraStudentTeacherDO::getId)); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/js/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/js/index new file mode 100644 index 0000000..211d95e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/js/index @@ -0,0 +1,141 @@ +import request from '@/utils/request' + +// 创建学生 +export function createStudent(data) { + return request({ + url: '/infra/student/create', + method: 'post', + data: data + }) +} + +// 更新学生 +export function updateStudent(data) { + return request({ + url: '/infra/student/update', + method: 'put', + data: data + }) +} + +// 删除学生 +export function deleteStudent(id) { + return request({ + url: '/infra/student/delete?id=' + id, + method: 'delete' + }) +} + +// 获得学生 +export function getStudent(id) { + return request({ + url: '/infra/student/get?id=' + id, + method: 'get' + }) +} + +// 获得学生分页 +export function getStudentPage(params) { + return request({ + url: '/infra/student/page', + method: 'get', + params + }) +} +// 导出学生 Excel +export function exportStudentExcel(params) { + return request({ + url: '/infra/student/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} + +// ==================== 子表(学生联系人) ==================== + + // 获得学生联系人分页 + export function getStudentContactPage(params) { + return request({ + url: '/infra/student/student-contact/page', + method: 'get', + params + }) + } + // 新增学生联系人 + export function createStudentContact(data) { + return request({ + url: `/infra/student/student-contact/create`, + method: 'post', + data + }) + } + + // 修改学生联系人 + export function updateStudentContact(data) { + return request({ + url: `/infra/student/student-contact/update`, + method: 'post', + data + }) + } + + // 删除学生联系人 + export function deleteStudentContact(id) { + return request({ + url: `/infra/student/student-contact/delete?id=` + id, + method: 'delete' + }) + } + + // 获得学生联系人 + export function getStudentContact(id) { + return request({ + url: `/infra/student/student-contact/get?id=` + id, + method: 'get' + }) + } + +// ==================== 子表(学生班主任) ==================== + + // 获得学生班主任分页 + export function getStudentTeacherPage(params) { + return request({ + url: '/infra/student/student-teacher/page', + method: 'get', + params + }) + } + // 新增学生班主任 + export function createStudentTeacher(data) { + return request({ + url: `/infra/student/student-teacher/create`, + method: 'post', + data + }) + } + + // 修改学生班主任 + export function updateStudentTeacher(data) { + return request({ + url: `/infra/student/student-teacher/update`, + method: 'post', + data + }) + } + + // 删除学生班主任 + export function deleteStudentTeacher(id) { + return request({ + url: `/infra/student/student-teacher/delete?id=` + id, + method: 'delete' + }) + } + + // 获得学生班主任 + export function getStudentTeacher(id) { + return request({ + url: `/infra/student/student-teacher/get?id=` + id, + method: 'get' + }) + } \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactForm new file mode 100644 index 0000000..de3b0a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactForm @@ -0,0 +1,151 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactList new file mode 100644 index 0000000..00f1ce0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentContactList @@ -0,0 +1,129 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentForm new file mode 100644 index 0000000..d89e506 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentForm @@ -0,0 +1,149 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherForm new file mode 100644 index 0000000..874a03b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherForm @@ -0,0 +1,151 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherList new file mode 100644 index 0000000..7d561a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/StudentTeacherList @@ -0,0 +1,129 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/index new file mode 100644 index 0000000..9c7588f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/vue/index @@ -0,0 +1,233 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_erp/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/assert.json new file mode 100644 index 0000000..8edb8e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/assert.json @@ -0,0 +1,73 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue" +}, { + "contentPath": "js/index", + "filePath": "yudao-ui-admin-vue2/src/api/infra/demo/index.js" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentTeacherForm.vue" +}, { + "contentPath" : "vue/StudentContactList", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentContactList.vue" +}, { + "contentPath" : "vue/StudentTeacherList", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentTeacherList.vue" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactMapper new file mode 100644 index 0000000..35bbd53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default List selectListByStudentId(Long studentId) { + return selectList(InfraStudentContactDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentController new file mode 100644 index 0000000..b9a587b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentController @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/list-by-student-id") + @Operation(summary = "获得学生联系人列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactListByStudentId(studentId)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/get-by-student-id") + @Operation(summary = "获得学生班主任") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherByStudentId(studentId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..faa491d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentSaveReqVO @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + + @Schema(description = "学生联系人列表") + private List studentContacts; + + @Schema(description = "学生班主任") + private InfraStudentTeacherDO studentTeacher; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentService new file mode 100644 index 0000000..afa7d22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentService @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人列表 + * + * @param studentId 学生编号 + * @return 学生联系人列表 + */ + List getStudentContactListByStudentId(Long studentId); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任 + * + * @param studentId 学生编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImpl new file mode 100644 index 0000000..c57cba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImpl @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + + // 插入子表 + createStudentContactList(student.getId(), createReqVO.getStudentContacts()); + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher()); + // 返回 + return student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + + // 更新子表 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts()); + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public List getStudentContactListByStudentId(Long studentId) { + return studentContactMapper.selectListByStudentId(studentId); + } + + private void createStudentContactList(Long studentId, List list) { + list.forEach(o -> o.setStudentId(studentId)); + studentContactMapper.insertBatch(list); + } + + private void updateStudentContactList(Long studentId, List list) { + deleteStudentContactByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createStudentContactList(studentId, list); + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) { + return studentTeacherMapper.selectByStudentId(studentId); + } + + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacherMapper.insert(studentTeacher); + } + + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + studentTeacherMapper.insertOrUpdate(studentTeacher); + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..0521bba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default InfraStudentTeacherDO selectByStudentId(Long studentId) { + return selectOne(InfraStudentTeacherDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/js/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/js/index new file mode 100644 index 0000000..b4e6ac5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/js/index @@ -0,0 +1,74 @@ +import request from '@/utils/request' + +// 创建学生 +export function createStudent(data) { + return request({ + url: '/infra/student/create', + method: 'post', + data: data + }) +} + +// 更新学生 +export function updateStudent(data) { + return request({ + url: '/infra/student/update', + method: 'put', + data: data + }) +} + +// 删除学生 +export function deleteStudent(id) { + return request({ + url: '/infra/student/delete?id=' + id, + method: 'delete' + }) +} + +// 获得学生 +export function getStudent(id) { + return request({ + url: '/infra/student/get?id=' + id, + method: 'get' + }) +} + +// 获得学生分页 +export function getStudentPage(params) { + return request({ + url: '/infra/student/page', + method: 'get', + params + }) +} +// 导出学生 Excel +export function exportStudentExcel(params) { + return request({ + url: '/infra/student/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} + +// ==================== 子表(学生联系人) ==================== + + // 获得学生联系人列表 + export function getStudentContactListByStudentId(studentId) { + return request({ + url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId, + method: 'get' + }) + } + +// ==================== 子表(学生班主任) ==================== + + // 获得学生班主任 + export function getStudentTeacherByStudentId(studentId) { + return request({ + url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId, + method: 'get' + }) + } + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactForm new file mode 100644 index 0000000..c953bfa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactForm @@ -0,0 +1,177 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactList new file mode 100644 index 0000000..c0a8710 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentContactList @@ -0,0 +1,89 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentForm new file mode 100644 index 0000000..6d93b61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentForm @@ -0,0 +1,180 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherForm new file mode 100644 index 0000000..0dac19b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherForm @@ -0,0 +1,127 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherList new file mode 100644 index 0000000..9f57274 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/StudentTeacherList @@ -0,0 +1,93 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/index new file mode 100644 index 0000000..ddeafdf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/vue/index @@ -0,0 +1,222 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_inner/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/assert.json new file mode 100644 index 0000000..6f94535 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/assert.json @@ -0,0 +1,67 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue" +}, { + "contentPath": "js/index", + "filePath": "yudao-ui-admin-vue2/src/api/infra/demo/index.js" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/components/StudentTeacherForm.vue" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactMapper new file mode 100644 index 0000000..35bbd53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default List selectListByStudentId(Long studentId) { + return selectList(InfraStudentContactDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentController new file mode 100644 index 0000000..b9a587b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentController @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/list-by-student-id") + @Operation(summary = "获得学生联系人列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactListByStudentId(studentId)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/get-by-student-id") + @Operation(summary = "获得学生班主任") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherByStudentId(studentId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..faa491d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentSaveReqVO @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + + @Schema(description = "学生联系人列表") + private List studentContacts; + + @Schema(description = "学生班主任") + private InfraStudentTeacherDO studentTeacher; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentService new file mode 100644 index 0000000..afa7d22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentService @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人列表 + * + * @param studentId 学生编号 + * @return 学生联系人列表 + */ + List getStudentContactListByStudentId(Long studentId); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任 + * + * @param studentId 学生编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImpl new file mode 100644 index 0000000..c57cba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImpl @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + + // 插入子表 + createStudentContactList(student.getId(), createReqVO.getStudentContacts()); + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher()); + // 返回 + return student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + + // 更新子表 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts()); + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public List getStudentContactListByStudentId(Long studentId) { + return studentContactMapper.selectListByStudentId(studentId); + } + + private void createStudentContactList(Long studentId, List list) { + list.forEach(o -> o.setStudentId(studentId)); + studentContactMapper.insertBatch(list); + } + + private void updateStudentContactList(Long studentId, List list) { + deleteStudentContactByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createStudentContactList(studentId, list); + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) { + return studentTeacherMapper.selectByStudentId(studentId); + } + + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacherMapper.insert(studentTeacher); + } + + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + studentTeacherMapper.insertOrUpdate(studentTeacher); + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..0521bba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default InfraStudentTeacherDO selectByStudentId(Long studentId) { + return selectOne(InfraStudentTeacherDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/js/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/js/index new file mode 100644 index 0000000..b4e6ac5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/js/index @@ -0,0 +1,74 @@ +import request from '@/utils/request' + +// 创建学生 +export function createStudent(data) { + return request({ + url: '/infra/student/create', + method: 'post', + data: data + }) +} + +// 更新学生 +export function updateStudent(data) { + return request({ + url: '/infra/student/update', + method: 'put', + data: data + }) +} + +// 删除学生 +export function deleteStudent(id) { + return request({ + url: '/infra/student/delete?id=' + id, + method: 'delete' + }) +} + +// 获得学生 +export function getStudent(id) { + return request({ + url: '/infra/student/get?id=' + id, + method: 'get' + }) +} + +// 获得学生分页 +export function getStudentPage(params) { + return request({ + url: '/infra/student/page', + method: 'get', + params + }) +} +// 导出学生 Excel +export function exportStudentExcel(params) { + return request({ + url: '/infra/student/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} + +// ==================== 子表(学生联系人) ==================== + + // 获得学生联系人列表 + export function getStudentContactListByStudentId(studentId) { + return request({ + url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId, + method: 'get' + }) + } + +// ==================== 子表(学生班主任) ==================== + + // 获得学生班主任 + export function getStudentTeacherByStudentId(studentId) { + return request({ + url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId, + method: 'get' + }) + } + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentContactForm new file mode 100644 index 0000000..c953bfa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentContactForm @@ -0,0 +1,177 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentForm new file mode 100644 index 0000000..6d93b61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentForm @@ -0,0 +1,180 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentTeacherForm new file mode 100644 index 0000000..0dac19b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/StudentTeacherForm @@ -0,0 +1,127 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/index new file mode 100644 index 0000000..4607581 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/vue/index @@ -0,0 +1,205 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_master_normal/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/assert.json new file mode 100644 index 0000000..5a37c37 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/assert.json @@ -0,0 +1,49 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue" +}, { + "contentPath": "js/index", + "filePath": "yudao-ui-admin-vue2/src/api/infra/demo/index.js" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/StudentForm.vue" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentController new file mode 100644 index 0000000..3796982 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentController @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..43e7f14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentSaveReqVO @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentService new file mode 100644 index 0000000..c4a0e17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentService @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImpl new file mode 100644 index 0000000..2292a66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImpl @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + + @Override + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + // 返回 + return student.getId(); + } + + @Override + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + } + + @Override + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/js/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/js/index new file mode 100644 index 0000000..44db468 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/js/index @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 创建学生 +export function createStudent(data) { + return request({ + url: '/infra/student/create', + method: 'post', + data: data + }) +} + +// 更新学生 +export function updateStudent(data) { + return request({ + url: '/infra/student/update', + method: 'put', + data: data + }) +} + +// 删除学生 +export function deleteStudent(id) { + return request({ + url: '/infra/student/delete?id=' + id, + method: 'delete' + }) +} + +// 获得学生 +export function getStudent(id) { + return request({ + url: '/infra/student/get?id=' + id, + method: 'get' + }) +} + +// 获得学生分页 +export function getStudentPage(params) { + return request({ + url: '/infra/student/page', + method: 'get', + params + }) +} +// 导出学生 Excel +export function exportStudentExcel(params) { + return request({ + url: '/infra/student/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/StudentForm new file mode 100644 index 0000000..d89e506 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/StudentForm @@ -0,0 +1,149 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/index new file mode 100644 index 0000000..4607581 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/vue/index @@ -0,0 +1,205 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_one/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/assert.json new file mode 100644 index 0000000..a7d2f56 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/assert.json @@ -0,0 +1,49 @@ +[ { + "contentPath" : "java/InfraCategoryListReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryListReqVO.java" +}, { + "contentPath" : "java/InfraCategoryRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryRespVO.java" +}, { + "contentPath" : "java/InfraCategorySaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategorySaveReqVO.java" +}, { + "contentPath" : "java/InfraCategoryController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraCategoryController.java" +}, { + "contentPath" : "java/InfraCategoryDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraCategoryDO.java" +}, { + "contentPath" : "java/InfraCategoryMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraCategoryMapper.java" +}, { + "contentPath" : "xml/InfraCategoryMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraCategoryMapper.xml" +}, { + "contentPath" : "java/InfraCategoryServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImpl.java" +}, { + "contentPath" : "java/InfraCategoryService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryService.java" +}, { + "contentPath" : "java/InfraCategoryServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue" +}, { + "contentPath": "js/index", + "filePath": "yudao-ui-admin-vue2/src/api/infra/demo/index.js" +}, { + "contentPath" : "vue/CategoryForm", + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/CategoryForm.vue" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..36df675 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,8 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 分类 TODO 补充编号 ========== +ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(TODO 补充编号, "分类不存在"); +ErrorCode CATEGORY_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子分类,无法删除"); +ErrorCode CATEGORY_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级分类不存在"); +ErrorCode CATEGORY_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父分类"); +ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该名字的分类"); +ErrorCode CATEGORY_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子InfraCategory为父InfraCategory"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryController new file mode 100644 index 0000000..a7b2f81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryController @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraCategoryService; + +@Tag(name = "管理后台 - 分类") +@RestController +@RequestMapping("/infra/category") +@Validated +public class InfraCategoryController { + + @Resource + private InfraCategoryService categoryService; + + @PostMapping("/create") + @Operation(summary = "创建分类") + @PreAuthorize("@ss.hasPermission('infra:category:create')") + public CommonResult createCategory(@Valid @RequestBody InfraCategorySaveReqVO createReqVO) { + return success(categoryService.createCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新分类") + @PreAuthorize("@ss.hasPermission('infra:category:update')") + public CommonResult updateCategory(@Valid @RequestBody InfraCategorySaveReqVO updateReqVO) { + categoryService.updateCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:category:delete')") + public CommonResult deleteCategory(@RequestParam("id") Long id) { + categoryService.deleteCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:category:query')") + public CommonResult getCategory(@RequestParam("id") Long id) { + InfraCategoryDO category = categoryService.getCategory(id); + return success(BeanUtils.toBean(category, InfraCategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得分类列表") + @PreAuthorize("@ss.hasPermission('infra:category:query')") + public CommonResult> getCategoryList(@Valid InfraCategoryListReqVO listReqVO) { + List list = categoryService.getCategoryList(listReqVO); + return success(BeanUtils.toBean(list, InfraCategoryRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出分类 Excel") + @PreAuthorize("@ss.hasPermission('infra:category:export')") + @OperateLog(type = EXPORT) + public void exportCategoryExcel(@Valid InfraCategoryListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = categoryService.getCategoryList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "分类.xls", "数据", InfraCategoryRespVO.class, + BeanUtils.toBean(list, InfraCategoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryDO new file mode 100644 index 0000000..9bf21c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryDO @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 分类 DO + * + * @author 芋道源码 + */ +@TableName("infra_category") +@KeySequence("infra_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraCategoryDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 父编号 + */ + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryListReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryListReqVO new file mode 100644 index 0000000..e5c6f18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryListReqVO @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +@Schema(description = "管理后台 - 分类列表 Request VO") +@Data +public class InfraCategoryListReqVO { + + @Schema(description = "名字", example = "芋头") + private String name; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryMapper new file mode 100644 index 0000000..9dadbf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryMapper @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraCategoryMapper extends BaseMapperX { + + default List selectList(InfraCategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(InfraCategoryDO::getName, reqVO.getName()) + .orderByDesc(InfraCategoryDO::getId)); + } + + default InfraCategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(InfraCategoryDO::getParentId, parentId, InfraCategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(InfraCategoryDO::getParentId, parentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryRespVO new file mode 100644 index 0000000..6325d86 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryRespVO @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 分类 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraCategoryRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @ExcelProperty("父编号") + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategorySaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategorySaveReqVO new file mode 100644 index 0000000..3c03b97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategorySaveReqVO @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; + +@Schema(description = "管理后台 - 分类新增/修改 Request VO") +@Data +public class InfraCategorySaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "父编号不能为空") + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryService new file mode 100644 index 0000000..9d0ae1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryService @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 分类 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraCategoryService { + + /** + * 创建分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCategory(@Valid InfraCategorySaveReqVO createReqVO); + + /** + * 更新分类 + * + * @param updateReqVO 更新信息 + */ + void updateCategory(@Valid InfraCategorySaveReqVO updateReqVO); + + /** + * 删除分类 + * + * @param id 编号 + */ + void deleteCategory(Long id); + + /** + * 获得分类 + * + * @param id 编号 + * @return 分类 + */ + InfraCategoryDO getCategory(Long id); + + /** + * 获得分类列表 + * + * @param listReqVO 查询条件 + * @return 分类列表 + */ + List getCategoryList(InfraCategoryListReqVO listReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImpl new file mode 100644 index 0000000..351568b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImpl @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraCategoryServiceImpl implements InfraCategoryService { + + @Resource + private InfraCategoryMapper categoryMapper; + + @Override + public Long createCategory(InfraCategorySaveReqVO createReqVO) { + // 校验父编号的有效性 + validateParentCategory(null, createReqVO.getParentId()); + // 校验名字的唯一性 + validateCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + InfraCategoryDO category = BeanUtils.toBean(createReqVO, InfraCategoryDO.class); + categoryMapper.insert(category); + // 返回 + return category.getId(); + } + + @Override + public void updateCategory(InfraCategorySaveReqVO updateReqVO) { + // 校验存在 + validateCategoryExists(updateReqVO.getId()); + // 校验父编号的有效性 + validateParentCategory(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验名字的唯一性 + validateCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + InfraCategoryDO updateObj = BeanUtils.toBean(updateReqVO, InfraCategoryDO.class); + categoryMapper.updateById(updateObj); + } + + @Override + public void deleteCategory(Long id) { + // 校验存在 + validateCategoryExists(id); + // 校验是否有子分类 + if (categoryMapper.selectCountByParentId(id) > 0) { + throw exception(CATEGORY_EXITS_CHILDREN); + } + // 删除 + categoryMapper.deleteById(id); + } + + private void validateCategoryExists(Long id) { + if (categoryMapper.selectById(id) == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + } + + private void validateParentCategory(Long id, Long parentId) { + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父分类 + if (Objects.equals(id, parentId)) { + throw exception(CATEGORY_PARENT_ERROR); + } + // 2. 父分类不存在 + CategoryDO parentCategory = categoryMapper.selectById(parentId); + if (parentCategory == null) { + throw exception(CATEGORY_PARENT_NOT_EXITS); + } + // 3. 递归校验父分类,如果父分类是自己的子分类,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentCategory.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(CATEGORY_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父分类 + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentCategory = categoryMapper.selectById(parentId); + if (parentCategory == null) { + break; + } + } + } + + private void validateCategoryNameUnique(Long id, Long parentId, String name) { + CategoryDO category = categoryMapper.selectByParentIdAndName(parentId, name); + if (category == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的分类 + if (id == null) { + throw exception(CATEGORY_NAME_DUPLICATE); + } + if (!Objects.equals(category.getId(), id)) { + throw exception(CATEGORY_NAME_DUPLICATE); + } + } + + @Override + public InfraCategoryDO getCategory(Long id) { + return categoryMapper.selectById(id); + } + + @Override + public List getCategoryList(InfraCategoryListReqVO listReqVO) { + return categoryMapper.selectList(listReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImplTest new file mode 100644 index 0000000..efb70fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImplTest @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraCategoryServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraCategoryServiceImpl.class) +public class InfraCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraCategoryServiceImpl categoryService; + + @Resource + private InfraCategoryMapper categoryMapper; + + @Test + public void testCreateCategory_success() { + // 准备参数 + InfraCategorySaveReqVO createReqVO = randomPojo(InfraCategorySaveReqVO.class).setId(null); + + // 调用 + Long categoryId = categoryService.createCategory(createReqVO); + // 断言 + assertNotNull(categoryId); + // 校验记录的属性是否正确 + InfraCategoryDO category = categoryMapper.selectById(categoryId); + assertPojoEquals(createReqVO, category, "id"); + } + + @Test + public void testUpdateCategory_success() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class, o -> { + o.setId(dbCategory.getId()); // 设置更新的 ID + }); + + // 调用 + categoryService.updateCategory(updateReqVO); + // 校验是否更新正确 + InfraCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, category); + } + + @Test + public void testUpdateCategory_notExists() { + // 准备参数 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteCategory_success() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCategory.getId(); + + // 调用 + categoryService.deleteCategory(id); + // 校验数据不存在了 + assertNull(categoryMapper.selectById(id)); + } + + @Test + public void testDeleteCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCategoryList() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class, o -> { // 等会查询到 + o.setName(null); + }); + categoryMapper.insert(dbCategory); + // 测试 name 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName(null))); + // 准备参数 + InfraCategoryListReqVO reqVO = new InfraCategoryListReqVO(); + reqVO.setName(null); + + // 调用 + List list = categoryService.getCategoryList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbCategory, list.get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/js/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/js/index new file mode 100644 index 0000000..1e6ffdc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/js/index @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 创建分类 +export function createCategory(data) { + return request({ + url: '/infra/category/create', + method: 'post', + data: data + }) +} + +// 更新分类 +export function updateCategory(data) { + return request({ + url: '/infra/category/update', + method: 'put', + data: data + }) +} + +// 删除分类 +export function deleteCategory(id) { + return request({ + url: '/infra/category/delete?id=' + id, + method: 'delete' + }) +} + +// 获得分类 +export function getCategory(id) { + return request({ + url: '/infra/category/get?id=' + id, + method: 'get' + }) +} + +// 获得分类列表 +export function getCategoryList(params) { + return request({ + url: '/infra/category/list', + method: 'get', + params + }) +} +// 导出分类 Excel +export function exportCategoryExcel(params) { + return request({ + url: '/infra/category/export-excel', + method: 'get', + params, + responseType: 'blob' + }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/h2 new file mode 100644 index 0000000..4141766 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/h2 @@ -0,0 +1,10 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_category" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '分类表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_category"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/sql new file mode 100644 index 0000000..8140948 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '分类管理', '', 2, 0, 888, + 'category', '', 'infra/demo/index', 0, 'InfraCategory' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类查询', 'infra:category:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类创建', 'infra:category:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类更新', 'infra:category:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类删除', 'infra:category:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类导出', 'infra:category:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/CategoryForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/CategoryForm new file mode 100644 index 0000000..7fa06e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/CategoryForm @@ -0,0 +1,130 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/index new file mode 100644 index 0000000..88da682 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/vue/index @@ -0,0 +1,161 @@ + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/xml/InfraCategoryMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/xml/InfraCategoryMapper new file mode 100644 index 0000000..025ac85 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue2_tree/xml/InfraCategoryMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/assert.json new file mode 100644 index 0000000..0937ba9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/assert.json @@ -0,0 +1,73 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/index.vue" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue" +}, { + "contentPath" : "vue/StudentContactList", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactList.vue" +}, { + "contentPath" : "vue/StudentTeacherList", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherList.vue" +}, { + "contentPath" : "ts/index", + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..d3201de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,6 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); +ErrorCode STUDENT_CONTACT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生联系人不存在"); +ErrorCode STUDENT_TEACHER_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任不存在"); +ErrorCode STUDENT_TEACHER_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任已存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactMapper new file mode 100644 index 0000000..ca662d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentContactMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(InfraStudentContactDO::getStudentId, studentId) + .orderByDesc(InfraStudentContactDO::getId)); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentController new file mode 100644 index 0000000..d6f2018 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentController @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/page") + @Operation(summary = "获得学生联系人分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactPage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactPage(pageReqVO, studentId)); + } + + @PostMapping("/student-contact/create") + @Operation(summary = "创建学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) { + return success(studentService.createStudentContact(studentContact)); + } + + @PutMapping("/student-contact/update") + @Operation(summary = "更新学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) { + studentService.updateStudentContact(studentContact); + return success(true); + } + + @DeleteMapping("/student-contact/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生联系人") + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudentContact(@RequestParam("id") Long id) { + studentService.deleteStudentContact(id); + return success(true); + } + + @GetMapping("/student-contact/get") + @Operation(summary = "获得学生联系人") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentContact(@RequestParam("id") Long id) { + return success(studentService.getStudentContact(id)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/page") + @Operation(summary = "获得学生班主任分页") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentTeacherPage(PageParam pageReqVO, + @RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherPage(pageReqVO, studentId)); + } + + @PostMapping("/student-teacher/create") + @Operation(summary = "创建学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) { + return success(studentService.createStudentTeacher(studentTeacher)); + } + + @PutMapping("/student-teacher/update") + @Operation(summary = "更新学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) { + studentService.updateStudentTeacher(studentTeacher); + return success(true); + } + + @DeleteMapping("/student-teacher/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除学生班主任") + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudentTeacher(@RequestParam("id") Long id) { + studentService.deleteStudentTeacher(id); + return success(true); + } + + @GetMapping("/student-teacher/get") + @Operation(summary = "获得学生班主任") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacher(@RequestParam("id") Long id) { + return success(studentService.getStudentTeacher(id)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..eaadf74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentSaveReqVO @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentService new file mode 100644 index 0000000..7df090d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentService @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生联系人分页 + */ + PageResult getStudentContactPage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生联系人 + * + * @param studentContact 创建信息 + * @return 编号 + */ + Long createStudentContact(@Valid InfraStudentContactDO studentContact); + + /** + * 更新学生联系人 + * + * @param studentContact 更新信息 + */ + void updateStudentContact(@Valid InfraStudentContactDO studentContact); + + /** + * 删除学生联系人 + * + * @param id 编号 + */ + void deleteStudentContact(Long id); + + /** + * 获得学生联系人 + * + * @param id 编号 + * @return 学生联系人 + */ + InfraStudentContactDO getStudentContact(Long id); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任分页 + * + * @param pageReqVO 分页查询 + * @param studentId 学生编号 + * @return 学生班主任分页 + */ + PageResult getStudentTeacherPage(PageParam pageReqVO, Long studentId); + + /** + * 创建学生班主任 + * + * @param studentTeacher 创建信息 + * @return 编号 + */ + Long createStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher); + + /** + * 更新学生班主任 + * + * @param studentTeacher 更新信息 + */ + void updateStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher); + + /** + * 删除学生班主任 + * + * @param id 编号 + */ + void deleteStudentTeacher(Long id); + + /** + * 获得学生班主任 + * + * @param id 编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacher(Long id); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImpl new file mode 100644 index 0000000..793b2dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImpl @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + // 返回 + return student.getId(); + } + + @Override + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public PageResult getStudentContactPage(PageParam pageReqVO, Long studentId) { + return studentContactMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createStudentContact(InfraStudentContactDO studentContact) { + studentContactMapper.insert(studentContact); + return studentContact.getId(); + } + + @Override + public void updateStudentContact(InfraStudentContactDO studentContact) { + // 校验存在 + validateStudentContactExists(studentContact.getId()); + // 更新 + studentContactMapper.updateById(studentContact); + } + + @Override + public void deleteStudentContact(Long id) { + // 校验存在 + validateStudentContactExists(id); + // 删除 + studentContactMapper.deleteById(id); + } + + @Override + public InfraStudentContactDO getStudentContact(Long id) { + return studentContactMapper.selectById(id); + } + + private void validateStudentContactExists(Long id) { + if (studentContactMapper.selectById(id) == null) { + throw exception(STUDENT_CONTACT_NOT_EXISTS); + } + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public PageResult getStudentTeacherPage(PageParam pageReqVO, Long studentId) { + return studentTeacherMapper.selectPage(pageReqVO, studentId); + } + + @Override + public Long createStudentTeacher(InfraStudentTeacherDO studentTeacher) { + // 校验是否已经存在 + if (studentTeacherMapper.selectByStudentId(studentTeacher.getStudentId()) != null) { + throw exception(STUDENT_TEACHER_EXISTS); + } + // 插入 + studentTeacherMapper.insert(studentTeacher); + return studentTeacher.getId(); + } + + @Override + public void updateStudentTeacher(InfraStudentTeacherDO studentTeacher) { + // 校验存在 + validateStudentTeacherExists(studentTeacher.getId()); + // 更新 + studentTeacherMapper.updateById(studentTeacher); + } + + @Override + public void deleteStudentTeacher(Long id) { + // 校验存在 + validateStudentTeacherExists(id); + // 删除 + studentTeacherMapper.deleteById(id); + } + + @Override + public InfraStudentTeacherDO getStudentTeacher(Long id) { + return studentTeacherMapper.selectById(id); + } + + private void validateStudentTeacherExists(Long id) { + if (studentTeacherMapper.selectById(id) == null) { + throw exception(STUDENT_TEACHER_NOT_EXISTS); + } + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..994212d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentTeacherMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long studentId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(InfraStudentTeacherDO::getStudentId, studentId) + .orderByDesc(InfraStudentTeacherDO::getId)); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/ts/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/ts/index new file mode 100644 index 0000000..2fe87b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/ts/index @@ -0,0 +1,95 @@ +import request from '@/config/axios' + +export interface StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生分页 +export const getStudentPage = async (params) => { + return await request.get({ url: `/infra/student/page`, params }) +} + +// 查询学生详情 +export const getStudent = async (id: number) => { + return await request.get({ url: `/infra/student/get?id=` + id }) +} + +// 新增学生 +export const createStudent = async (data: StudentVO) => { + return await request.post({ url: `/infra/student/create`, data }) +} + +// 修改学生 +export const updateStudent = async (data: StudentVO) => { + return await request.put({ url: `/infra/student/update`, data }) +} + +// 删除学生 +export const deleteStudent = async (id: number) => { + return await request.delete({ url: `/infra/student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportStudent = async (params) => { + return await request.download({ url: `/infra/student/export-excel`, params }) +} + +// ==================== 子表(学生联系人) ==================== + +// 获得学生联系人分页 +export const getStudentContactPage = async (params) => { + return await request.get({ url: `/infra/student/student-contact/page`, params }) +} +// 新增学生联系人 +export const createStudentContact = async (data) => { + return await request.post({ url: `/infra/student/student-contact/create`, data }) +} + +// 修改学生联系人 +export const updateStudentContact = async (data) => { + return await request.put({ url: `/infra/student/student-contact/update`, data }) +} + +// 删除学生联系人 +export const deleteStudentContact = async (id: number) => { + return await request.delete({ url: `/infra/student/student-contact/delete?id=` + id }) +} + +// 获得学生联系人 +export const getStudentContact = async (id: number) => { + return await request.get({ url: `/infra/student/student-contact/get?id=` + id }) +} + +// ==================== 子表(学生班主任) ==================== + +// 获得学生班主任分页 +export const getStudentTeacherPage = async (params) => { + return await request.get({ url: `/infra/student/student-teacher/page`, params }) +} +// 新增学生班主任 +export const createStudentTeacher = async (data) => { + return await request.post({ url: `/infra/student/student-teacher/create`, data }) +} + +// 修改学生班主任 +export const updateStudentTeacher = async (data) => { + return await request.put({ url: `/infra/student/student-teacher/update`, data }) +} + +// 删除学生班主任 +export const deleteStudentTeacher = async (id: number) => { + return await request.delete({ url: `/infra/student/student-teacher/delete?id=` + id }) +} + +// 获得学生班主任 +export const getStudentTeacher = async (id: number) => { + return await request.get({ url: `/infra/student/student-teacher/get?id=` + id }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactForm new file mode 100644 index 0000000..4a13935 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactForm @@ -0,0 +1,155 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactList new file mode 100644 index 0000000..eada66a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentContactList @@ -0,0 +1,146 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentForm new file mode 100644 index 0000000..0dabcb5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentForm @@ -0,0 +1,152 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherForm new file mode 100644 index 0000000..f93c21c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherForm @@ -0,0 +1,155 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherList new file mode 100644 index 0000000..1eba0a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/StudentTeacherList @@ -0,0 +1,146 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/index new file mode 100644 index 0000000..9d15146 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/vue/index @@ -0,0 +1,278 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_erp/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/assert.json new file mode 100644 index 0000000..0937ba9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/assert.json @@ -0,0 +1,73 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/index.vue" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue" +}, { + "contentPath" : "vue/StudentContactList", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactList.vue" +}, { + "contentPath" : "vue/StudentTeacherList", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherList.vue" +}, { + "contentPath" : "ts/index", + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactMapper new file mode 100644 index 0000000..35bbd53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentContactMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default List selectListByStudentId(Long studentId) { + return selectList(InfraStudentContactDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentController new file mode 100644 index 0000000..b9a587b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentController @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/list-by-student-id") + @Operation(summary = "获得学生联系人列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactListByStudentId(studentId)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/get-by-student-id") + @Operation(summary = "获得学生班主任") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherByStudentId(studentId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..faa491d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentSaveReqVO @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + + @Schema(description = "学生联系人列表") + private List studentContacts; + + @Schema(description = "学生班主任") + private InfraStudentTeacherDO studentTeacher; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentService new file mode 100644 index 0000000..afa7d22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentService @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人列表 + * + * @param studentId 学生编号 + * @return 学生联系人列表 + */ + List getStudentContactListByStudentId(Long studentId); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任 + * + * @param studentId 学生编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImpl new file mode 100644 index 0000000..c57cba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImpl @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + + // 插入子表 + createStudentContactList(student.getId(), createReqVO.getStudentContacts()); + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher()); + // 返回 + return student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + + // 更新子表 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts()); + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public List getStudentContactListByStudentId(Long studentId) { + return studentContactMapper.selectListByStudentId(studentId); + } + + private void createStudentContactList(Long studentId, List list) { + list.forEach(o -> o.setStudentId(studentId)); + studentContactMapper.insertBatch(list); + } + + private void updateStudentContactList(Long studentId, List list) { + deleteStudentContactByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createStudentContactList(studentId, list); + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) { + return studentTeacherMapper.selectByStudentId(studentId); + } + + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacherMapper.insert(studentTeacher); + } + + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + studentTeacherMapper.insertOrUpdate(studentTeacher); + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..0521bba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentTeacherMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default InfraStudentTeacherDO selectByStudentId(Long studentId) { + return selectOne(InfraStudentTeacherDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/ts/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/ts/index new file mode 100644 index 0000000..6112800 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/ts/index @@ -0,0 +1,57 @@ +import request from '@/config/axios' + +export interface StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生分页 +export const getStudentPage = async (params) => { + return await request.get({ url: `/infra/student/page`, params }) +} + +// 查询学生详情 +export const getStudent = async (id: number) => { + return await request.get({ url: `/infra/student/get?id=` + id }) +} + +// 新增学生 +export const createStudent = async (data: StudentVO) => { + return await request.post({ url: `/infra/student/create`, data }) +} + +// 修改学生 +export const updateStudent = async (data: StudentVO) => { + return await request.put({ url: `/infra/student/update`, data }) +} + +// 删除学生 +export const deleteStudent = async (id: number) => { + return await request.delete({ url: `/infra/student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportStudent = async (params) => { + return await request.download({ url: `/infra/student/export-excel`, params }) +} + +// ==================== 子表(学生联系人) ==================== + +// 获得学生联系人列表 +export const getStudentContactListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班主任) ==================== + +// 获得学生班主任 +export const getStudentTeacherByStudentId = async (studentId) => { + return await request.get({ url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactForm new file mode 100644 index 0000000..55ca994 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactForm @@ -0,0 +1,174 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactList new file mode 100644 index 0000000..d0e89da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentContactList @@ -0,0 +1,72 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentForm new file mode 100644 index 0000000..d8e7bc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentForm @@ -0,0 +1,184 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherForm new file mode 100644 index 0000000..b22a480 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherForm @@ -0,0 +1,122 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherList b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherList new file mode 100644 index 0000000..e510adc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/StudentTeacherList @@ -0,0 +1,76 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/index new file mode 100644 index 0000000..ee7c05f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/vue/index @@ -0,0 +1,267 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_inner/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/assert.json new file mode 100644 index 0000000..60e7f47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/assert.json @@ -0,0 +1,67 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentContactDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java" +}, { + "contentPath" : "java/InfraStudentTeacherDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "java/InfraStudentContactMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java" +}, { + "contentPath" : "java/InfraStudentTeacherMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/index.vue" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "vue/StudentContactForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue" +}, { + "contentPath" : "vue/StudentTeacherForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue" +}, { + "contentPath" : "ts/index", + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactDO new file mode 100644 index 0000000..17c668e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生联系人 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_contact") +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentContactDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactMapper new file mode 100644 index 0000000..35bbd53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentContactMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生联系人 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentContactMapper extends BaseMapperX { + + default List selectListByStudentId(Long studentId) { + return selectList(InfraStudentContactDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentContactDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentController new file mode 100644 index 0000000..b9a587b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentController @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + + // ==================== 子表(学生联系人) ==================== + + @GetMapping("/student-contact/list-by-student-id") + @Operation(summary = "获得学生联系人列表") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentContactListByStudentId(studentId)); + } + + // ==================== 子表(学生班主任) ==================== + + @GetMapping("/student-teacher/get-by-student-id") + @Operation(summary = "获得学生班主任") + @Parameter(name = "studentId", description = "学生编号") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) { + return success(studentService.getStudentTeacherByStudentId(studentId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..faa491d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentSaveReqVO @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + + @Schema(description = "学生联系人列表") + private List studentContacts; + + @Schema(description = "学生班主任") + private InfraStudentTeacherDO studentTeacher; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentService new file mode 100644 index 0000000..afa7d22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentService @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + + // ==================== 子表(学生联系人) ==================== + + /** + * 获得学生联系人列表 + * + * @param studentId 学生编号 + * @return 学生联系人列表 + */ + List getStudentContactListByStudentId(Long studentId); + + // ==================== 子表(学生班主任) ==================== + + /** + * 获得学生班主任 + * + * @param studentId 学生编号 + * @return 学生班主任 + */ + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImpl new file mode 100644 index 0000000..c57cba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImpl @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + @Resource + private InfraStudentContactMapper studentContactMapper; + @Resource + private InfraStudentTeacherMapper studentTeacherMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + + // 插入子表 + createStudentContactList(student.getId(), createReqVO.getStudentContacts()); + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher()); + // 返回 + return student.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + + // 更新子表 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts()); + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + + // 删除子表 + deleteStudentContactByStudentId(id); + deleteStudentTeacherByStudentId(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + + // ==================== 子表(学生联系人) ==================== + + @Override + public List getStudentContactListByStudentId(Long studentId) { + return studentContactMapper.selectListByStudentId(studentId); + } + + private void createStudentContactList(Long studentId, List list) { + list.forEach(o -> o.setStudentId(studentId)); + studentContactMapper.insertBatch(list); + } + + private void updateStudentContactList(Long studentId, List list) { + deleteStudentContactByStudentId(studentId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createStudentContactList(studentId, list); + } + + private void deleteStudentContactByStudentId(Long studentId) { + studentContactMapper.deleteByStudentId(studentId); + } + + // ==================== 子表(学生班主任) ==================== + + @Override + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) { + return studentTeacherMapper.selectByStudentId(studentId); + } + + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacherMapper.insert(studentTeacher); + } + + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) { + if (studentTeacher == null) { + return; + } + studentTeacher.setStudentId(studentId); + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新 + studentTeacherMapper.insertOrUpdate(studentTeacher); + } + + private void deleteStudentTeacherByStudentId(Long studentId) { + studentTeacherMapper.deleteByStudentId(studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherDO new file mode 100644 index 0000000..c19cf9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherDO @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生班主任 DO + * + * @author 芋道源码 + */ +@TableName("infra_student_teacher") +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentTeacherDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 学生编号 + */ + private Long studentId; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherMapper new file mode 100644 index 0000000..0521bba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentTeacherMapper @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 学生班主任 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentTeacherMapper extends BaseMapperX { + + default InfraStudentTeacherDO selectByStudentId(Long studentId) { + return selectOne(InfraStudentTeacherDO::getStudentId, studentId); + } + + default int deleteByStudentId(Long studentId) { + return delete(InfraStudentTeacherDO::getStudentId, studentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/ts/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/ts/index new file mode 100644 index 0000000..6112800 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/ts/index @@ -0,0 +1,57 @@ +import request from '@/config/axios' + +export interface StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生分页 +export const getStudentPage = async (params) => { + return await request.get({ url: `/infra/student/page`, params }) +} + +// 查询学生详情 +export const getStudent = async (id: number) => { + return await request.get({ url: `/infra/student/get?id=` + id }) +} + +// 新增学生 +export const createStudent = async (data: StudentVO) => { + return await request.post({ url: `/infra/student/create`, data }) +} + +// 修改学生 +export const updateStudent = async (data: StudentVO) => { + return await request.put({ url: `/infra/student/update`, data }) +} + +// 删除学生 +export const deleteStudent = async (id: number) => { + return await request.delete({ url: `/infra/student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportStudent = async (params) => { + return await request.download({ url: `/infra/student/export-excel`, params }) +} + +// ==================== 子表(学生联系人) ==================== + +// 获得学生联系人列表 +export const getStudentContactListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班主任) ==================== + +// 获得学生班主任 +export const getStudentTeacherByStudentId = async (studentId) => { + return await request.get({ url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentContactForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentContactForm new file mode 100644 index 0000000..55ca994 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentContactForm @@ -0,0 +1,174 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentForm new file mode 100644 index 0000000..d8e7bc3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentForm @@ -0,0 +1,184 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentTeacherForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentTeacherForm new file mode 100644 index 0000000..b22a480 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/StudentTeacherForm @@ -0,0 +1,122 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/index new file mode 100644 index 0000000..b115b13 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/vue/index @@ -0,0 +1,252 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_master_normal/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/assert.json new file mode 100644 index 0000000..5a0eebd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/assert.json @@ -0,0 +1,49 @@ +[ { + "contentPath" : "java/InfraStudentPageReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java" +}, { + "contentPath" : "java/InfraStudentRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java" +}, { + "contentPath" : "java/InfraStudentSaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java" +}, { + "contentPath" : "java/InfraStudentController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java" +}, { + "contentPath" : "java/InfraStudentDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java" +}, { + "contentPath" : "java/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java" +}, { + "contentPath" : "xml/InfraStudentMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml" +}, { + "contentPath" : "java/InfraStudentServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java" +}, { + "contentPath" : "java/InfraStudentService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java" +}, { + "contentPath" : "java/InfraStudentServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/index.vue" +}, { + "contentPath" : "vue/StudentForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue" +}, { + "contentPath" : "ts/index", + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..f8be662 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,3 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 学生 TODO 补充编号 ========== +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentController new file mode 100644 index 0000000..3796982 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentController @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService; + +@Tag(name = "管理后台 - 学生") +@RestController +@RequestMapping("/infra/student") +@Validated +public class InfraStudentController { + + @Resource + private InfraStudentService studentService; + + @PostMapping("/create") + @Operation(summary = "创建学生") + @PreAuthorize("@ss.hasPermission('infra:student:create')") + public CommonResult createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) { + return success(studentService.createStudent(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新学生") + @PreAuthorize("@ss.hasPermission('infra:student:update')") + public CommonResult updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) { + studentService.updateStudent(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除学生") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:student:delete')") + public CommonResult deleteStudent(@RequestParam("id") Long id) { + studentService.deleteStudent(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得学生") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult getStudent(@RequestParam("id") Long id) { + InfraStudentDO student = studentService.getStudent(id); + return success(BeanUtils.toBean(student, InfraStudentRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得学生分页") + @PreAuthorize("@ss.hasPermission('infra:student:query')") + public CommonResult> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) { + PageResult pageResult = studentService.getStudentPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出学生 Excel") + @PreAuthorize("@ss.hasPermission('infra:student:export')") + @OperateLog(type = EXPORT) + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = studentService.getStudentPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class, + BeanUtils.toBean(list, InfraStudentRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentDO new file mode 100644 index 0000000..b0d4bd2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentDO @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 学生 DO + * + * @author 芋道源码 + */ +@TableName("infra_student") +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraStudentDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 简介 + */ + private String description; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 性别 + * + * 枚举 {@link TODO system_user_sex 对应的类} + */ + private Integer sex; + /** + * 是否有效 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean enabled; + /** + * 头像 + */ + private String avatar; + /** + * 附件 + */ + private String video; + /** + * 备注 + */ + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentMapper new file mode 100644 index 0000000..34e70a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentMapper @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 学生 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraStudentMapper extends BaseMapperX { + + default PageResult selectPage(InfraStudentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(InfraStudentDO::getName, reqVO.getName()) + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday()) + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex()) + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled()) + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InfraStudentDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentPageReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentPageReqVO new file mode 100644 index 0000000..41a3730 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentPageReqVO @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 学生分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InfraStudentPageReqVO extends PageParam { + + @Schema(description = "名字", example = "芋头") + private String name; + + @Schema(description = "出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", example = "1") + private Integer sex; + + @Schema(description = "是否有效", example = "true") + private Boolean enabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentRespVO new file mode 100644 index 0000000..c41a550 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentRespVO @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 学生 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraStudentRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @ExcelProperty("简介") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("出生日期") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "性别", converter = DictConvert.class) + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty(value = "是否有效", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @ExcelProperty("头像") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @ExcelProperty("附件") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @ExcelProperty("备注") + private String memo; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentSaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentSaveReqVO new file mode 100644 index 0000000..43e7f14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentSaveReqVO @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 学生新增/修改 Request VO") +@Data +public class InfraStudentSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍") + @NotEmpty(message = "简介不能为空") + private String description; + + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "出生日期不能为空") + private LocalDateTime birthday; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "性别不能为空") + private Integer sex; + + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否有效不能为空") + private Boolean enabled; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotEmpty(message = "头像不能为空") + private String avatar; + + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4") + @NotEmpty(message = "附件不能为空") + private String video; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注") + @NotEmpty(message = "备注不能为空") + private String memo; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentService new file mode 100644 index 0000000..c4a0e17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentService @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 学生 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraStudentService { + + /** + * 创建学生 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO); + + /** + * 更新学生 + * + * @param updateReqVO 更新信息 + */ + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO); + + /** + * 删除学生 + * + * @param id 编号 + */ + void deleteStudent(Long id); + + /** + * 获得学生 + * + * @param id 编号 + * @return 学生 + */ + InfraStudentDO getStudent(Long id); + + /** + * 获得学生分页 + * + * @param pageReqVO 分页查询 + * @return 学生分页 + */ + PageResult getStudentPage(InfraStudentPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImpl new file mode 100644 index 0000000..2292a66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImpl @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 学生 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraStudentServiceImpl implements InfraStudentService { + + @Resource + private InfraStudentMapper studentMapper; + + @Override + public Long createStudent(InfraStudentSaveReqVO createReqVO) { + // 插入 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class); + studentMapper.insert(student); + // 返回 + return student.getId(); + } + + @Override + public void updateStudent(InfraStudentSaveReqVO updateReqVO) { + // 校验存在 + validateStudentExists(updateReqVO.getId()); + // 更新 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class); + studentMapper.updateById(updateObj); + } + + @Override + public void deleteStudent(Long id) { + // 校验存在 + validateStudentExists(id); + // 删除 + studentMapper.deleteById(id); + } + + private void validateStudentExists(Long id) { + if (studentMapper.selectById(id) == null) { + throw exception(STUDENT_NOT_EXISTS); + } + } + + @Override + public InfraStudentDO getStudent(Long id) { + return studentMapper.selectById(id); + } + + @Override + public PageResult getStudentPage(InfraStudentPageReqVO pageReqVO) { + return studentMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImplTest new file mode 100644 index 0000000..b5f4bf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImplTest @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraStudentServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraStudentServiceImpl.class) +public class InfraStudentServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraStudentServiceImpl studentService; + + @Resource + private InfraStudentMapper studentMapper; + + @Test + public void testCreateStudent_success() { + // 准备参数 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null); + + // 调用 + Long studentId = studentService.createStudent(createReqVO); + // 断言 + assertNotNull(studentId); + // 校验记录的属性是否正确 + InfraStudentDO student = studentMapper.selectById(studentId); + assertPojoEquals(createReqVO, student, "id"); + } + + @Test + public void testUpdateStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> { + o.setId(dbStudent.getId()); // 设置更新的 ID + }); + + // 调用 + studentService.updateStudent(updateReqVO); + // 校验是否更新正确 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, student); + } + + @Test + public void testUpdateStudent_notExists() { + // 准备参数 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS); + } + + @Test + public void testDeleteStudent_success() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class); + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbStudent.getId(); + + // 调用 + studentService.deleteStudent(id); + // 校验数据不存在了 + assertNull(studentMapper.selectById(id)); + } + + @Test + public void testDeleteStudent_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetStudentPage() { + // mock 数据 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到 + o.setName(null); + o.setBirthday(null); + o.setSex(null); + o.setEnabled(null); + o.setCreateTime(null); + }); + studentMapper.insert(dbStudent); + // 测试 name 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null))); + // 测试 birthday 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null))); + // 测试 sex 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null))); + // 测试 enabled 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null))); + // 测试 createTime 不匹配 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null))); + // 准备参数 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO(); + reqVO.setName(null); + reqVO.setBirthday(null); + reqVO.setSex(null); + reqVO.setEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = studentService.getStudentPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbStudent, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/h2 new file mode 100644 index 0000000..6c1875f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/h2 @@ -0,0 +1,17 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_student" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" varchar NOT NULL, + "birthday" varchar NOT NULL, + "sex" int NOT NULL, + "enabled" bit NOT NULL, + "avatar" varchar NOT NULL, + "video" varchar NOT NULL, + "memo" varchar NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY ("id") +) COMMENT '学生表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_student"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/sql new file mode 100644 index 0000000..83df279 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '学生管理', '', 2, 0, 888, + 'student', '', 'infra/demo/index', 0, 'InfraStudent' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生查询', 'infra:student:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生创建', 'infra:student:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生更新', 'infra:student:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生删除', 'infra:student:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '学生导出', 'infra:student:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/ts/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/ts/index new file mode 100644 index 0000000..8cdf254 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/ts/index @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +export interface StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生分页 +export const getStudentPage = async (params) => { + return await request.get({ url: `/infra/student/page`, params }) +} + +// 查询学生详情 +export const getStudent = async (id: number) => { + return await request.get({ url: `/infra/student/get?id=` + id }) +} + +// 新增学生 +export const createStudent = async (data: StudentVO) => { + return await request.post({ url: `/infra/student/create`, data }) +} + +// 修改学生 +export const updateStudent = async (data: StudentVO) => { + return await request.put({ url: `/infra/student/update`, data }) +} + +// 删除学生 +export const deleteStudent = async (id: number) => { + return await request.delete({ url: `/infra/student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportStudent = async (params) => { + return await request.download({ url: `/infra/student/export-excel`, params }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/StudentForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/StudentForm new file mode 100644 index 0000000..0dabcb5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/StudentForm @@ -0,0 +1,152 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/index new file mode 100644 index 0000000..b115b13 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/vue/index @@ -0,0 +1,252 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/xml/InfraStudentMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/xml/InfraStudentMapper new file mode 100644 index 0000000..155aa5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_one/xml/InfraStudentMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/assert.json b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/assert.json new file mode 100644 index 0000000..357df00 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/assert.json @@ -0,0 +1,49 @@ +[ { + "contentPath" : "java/InfraCategoryListReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryListReqVO.java" +}, { + "contentPath" : "java/InfraCategoryRespVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryRespVO.java" +}, { + "contentPath" : "java/InfraCategorySaveReqVO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategorySaveReqVO.java" +}, { + "contentPath" : "java/InfraCategoryController", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraCategoryController.java" +}, { + "contentPath" : "java/InfraCategoryDO", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraCategoryDO.java" +}, { + "contentPath" : "java/InfraCategoryMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraCategoryMapper.java" +}, { + "contentPath" : "xml/InfraCategoryMapper", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraCategoryMapper.xml" +}, { + "contentPath" : "java/InfraCategoryServiceImpl", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImpl.java" +}, { + "contentPath" : "java/InfraCategoryService", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryService.java" +}, { + "contentPath" : "java/InfraCategoryServiceImplTest", + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImplTest.java" +}, { + "contentPath" : "java/ErrorCodeConstants_手动操作", + "filePath" : "yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java" +}, { + "contentPath" : "sql/sql", + "filePath" : "sql/sql.sql" +}, { + "contentPath" : "sql/h2", + "filePath" : "sql/h2.sql" +}, { + "contentPath" : "vue/index", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/index.vue" +}, { + "contentPath" : "vue/CategoryForm", + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/CategoryForm.vue" +}, { + "contentPath" : "ts/index", + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts" +} ] \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/ErrorCodeConstants_手动操作 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/ErrorCodeConstants_手动操作 new file mode 100644 index 0000000..36df675 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/ErrorCodeConstants_手动操作 @@ -0,0 +1,8 @@ +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! +// ========== 分类 TODO 补充编号 ========== +ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(TODO 补充编号, "分类不存在"); +ErrorCode CATEGORY_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子分类,无法删除"); +ErrorCode CATEGORY_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级分类不存在"); +ErrorCode CATEGORY_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父分类"); +ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该名字的分类"); +ErrorCode CATEGORY_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子InfraCategory为父InfraCategory"); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryController b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryController new file mode 100644 index 0000000..a7b2f81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryController @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo; + +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.constraints.*; +import javax.validation.*; +import javax.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.module.infra.service.demo.InfraCategoryService; + +@Tag(name = "管理后台 - 分类") +@RestController +@RequestMapping("/infra/category") +@Validated +public class InfraCategoryController { + + @Resource + private InfraCategoryService categoryService; + + @PostMapping("/create") + @Operation(summary = "创建分类") + @PreAuthorize("@ss.hasPermission('infra:category:create')") + public CommonResult createCategory(@Valid @RequestBody InfraCategorySaveReqVO createReqVO) { + return success(categoryService.createCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新分类") + @PreAuthorize("@ss.hasPermission('infra:category:update')") + public CommonResult updateCategory(@Valid @RequestBody InfraCategorySaveReqVO updateReqVO) { + categoryService.updateCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:category:delete')") + public CommonResult deleteCategory(@RequestParam("id") Long id) { + categoryService.deleteCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:category:query')") + public CommonResult getCategory(@RequestParam("id") Long id) { + InfraCategoryDO category = categoryService.getCategory(id); + return success(BeanUtils.toBean(category, InfraCategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得分类列表") + @PreAuthorize("@ss.hasPermission('infra:category:query')") + public CommonResult> getCategoryList(@Valid InfraCategoryListReqVO listReqVO) { + List list = categoryService.getCategoryList(listReqVO); + return success(BeanUtils.toBean(list, InfraCategoryRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出分类 Excel") + @PreAuthorize("@ss.hasPermission('infra:category:export')") + @OperateLog(type = EXPORT) + public void exportCategoryExcel(@Valid InfraCategoryListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = categoryService.getCategoryList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "分类.xls", "数据", InfraCategoryRespVO.class, + BeanUtils.toBean(list, InfraCategoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryDO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryDO new file mode 100644 index 0000000..9bf21c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryDO @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.infra.dal.dataobject.demo; + +import lombok.*; +import java.util.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 分类 DO + * + * @author 芋道源码 + */ +@TableName("infra_category") +@KeySequence("infra_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InfraCategoryDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名字 + */ + private String name; + /** + * 父编号 + */ + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryListReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryListReqVO new file mode 100644 index 0000000..e5c6f18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryListReqVO @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +@Schema(description = "管理后台 - 分类列表 Request VO") +@Data +public class InfraCategoryListReqVO { + + @Schema(description = "名字", example = "芋头") + private String name; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryMapper new file mode 100644 index 0000000..9dadbf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryMapper @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.infra.dal.mysql.demo; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; + +/** + * 分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InfraCategoryMapper extends BaseMapperX { + + default List selectList(InfraCategoryListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(InfraCategoryDO::getName, reqVO.getName()) + .orderByDesc(InfraCategoryDO::getId)); + } + + default InfraCategoryDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(InfraCategoryDO::getParentId, parentId, InfraCategoryDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(InfraCategoryDO::getParentId, parentId); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryRespVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryRespVO new file mode 100644 index 0000000..6325d86 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryRespVO @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 分类 Response VO") +@Data +@ExcelIgnoreUnannotated +public class InfraCategoryRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @ExcelProperty("名字") + private String name; + + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @ExcelProperty("父编号") + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategorySaveReqVO b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategorySaveReqVO new file mode 100644 index 0000000..3c03b97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategorySaveReqVO @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; + +@Schema(description = "管理后台 - 分类新增/修改 Request VO") +@Data +public class InfraCategorySaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头") + @NotEmpty(message = "名字不能为空") + private String name; + + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "父编号不能为空") + private Long parentId; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryService b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryService new file mode 100644 index 0000000..9d0ae1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryService @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 分类 Service 接口 + * + * @author 芋道源码 + */ +public interface InfraCategoryService { + + /** + * 创建分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCategory(@Valid InfraCategorySaveReqVO createReqVO); + + /** + * 更新分类 + * + * @param updateReqVO 更新信息 + */ + void updateCategory(@Valid InfraCategorySaveReqVO updateReqVO); + + /** + * 删除分类 + * + * @param id 编号 + */ + void deleteCategory(Long id); + + /** + * 获得分类 + * + * @param id 编号 + * @return 分类 + */ + InfraCategoryDO getCategory(Long id); + + /** + * 获得分类列表 + * + * @param listReqVO 查询条件 + * @return 分类列表 + */ + List getCategoryList(InfraCategoryListReqVO listReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImpl b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImpl new file mode 100644 index 0000000..351568b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImpl @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; + +/** + * 分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InfraCategoryServiceImpl implements InfraCategoryService { + + @Resource + private InfraCategoryMapper categoryMapper; + + @Override + public Long createCategory(InfraCategorySaveReqVO createReqVO) { + // 校验父编号的有效性 + validateParentCategory(null, createReqVO.getParentId()); + // 校验名字的唯一性 + validateCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + InfraCategoryDO category = BeanUtils.toBean(createReqVO, InfraCategoryDO.class); + categoryMapper.insert(category); + // 返回 + return category.getId(); + } + + @Override + public void updateCategory(InfraCategorySaveReqVO updateReqVO) { + // 校验存在 + validateCategoryExists(updateReqVO.getId()); + // 校验父编号的有效性 + validateParentCategory(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验名字的唯一性 + validateCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + InfraCategoryDO updateObj = BeanUtils.toBean(updateReqVO, InfraCategoryDO.class); + categoryMapper.updateById(updateObj); + } + + @Override + public void deleteCategory(Long id) { + // 校验存在 + validateCategoryExists(id); + // 校验是否有子分类 + if (categoryMapper.selectCountByParentId(id) > 0) { + throw exception(CATEGORY_EXITS_CHILDREN); + } + // 删除 + categoryMapper.deleteById(id); + } + + private void validateCategoryExists(Long id) { + if (categoryMapper.selectById(id) == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + } + + private void validateParentCategory(Long id, Long parentId) { + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父分类 + if (Objects.equals(id, parentId)) { + throw exception(CATEGORY_PARENT_ERROR); + } + // 2. 父分类不存在 + CategoryDO parentCategory = categoryMapper.selectById(parentId); + if (parentCategory == null) { + throw exception(CATEGORY_PARENT_NOT_EXITS); + } + // 3. 递归校验父分类,如果父分类是自己的子分类,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentCategory.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(CATEGORY_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父分类 + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentCategory = categoryMapper.selectById(parentId); + if (parentCategory == null) { + break; + } + } + } + + private void validateCategoryNameUnique(Long id, Long parentId, String name) { + CategoryDO category = categoryMapper.selectByParentIdAndName(parentId, name); + if (category == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的分类 + if (id == null) { + throw exception(CATEGORY_NAME_DUPLICATE); + } + if (!Objects.equals(category.getId(), id)) { + throw exception(CATEGORY_NAME_DUPLICATE); + } + } + + @Override + public InfraCategoryDO getCategory(Long id) { + return categoryMapper.selectById(id); + } + + @Override + public List getCategoryList(InfraCategoryListReqVO listReqVO) { + return categoryMapper.selectList(listReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImplTest b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImplTest new file mode 100644 index 0000000..efb70fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImplTest @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.infra.service.demo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*; +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO; +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InfraCategoryServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InfraCategoryServiceImpl.class) +public class InfraCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private InfraCategoryServiceImpl categoryService; + + @Resource + private InfraCategoryMapper categoryMapper; + + @Test + public void testCreateCategory_success() { + // 准备参数 + InfraCategorySaveReqVO createReqVO = randomPojo(InfraCategorySaveReqVO.class).setId(null); + + // 调用 + Long categoryId = categoryService.createCategory(createReqVO); + // 断言 + assertNotNull(categoryId); + // 校验记录的属性是否正确 + InfraCategoryDO category = categoryMapper.selectById(categoryId); + assertPojoEquals(createReqVO, category, "id"); + } + + @Test + public void testUpdateCategory_success() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class, o -> { + o.setId(dbCategory.getId()); // 设置更新的 ID + }); + + // 调用 + categoryService.updateCategory(updateReqVO); + // 校验是否更新正确 + InfraCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, category); + } + + @Test + public void testUpdateCategory_notExists() { + // 准备参数 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteCategory_success() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCategory.getId(); + + // 调用 + categoryService.deleteCategory(id); + // 校验数据不存在了 + assertNull(categoryMapper.selectById(id)); + } + + @Test + public void testDeleteCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCategoryList() { + // mock 数据 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class, o -> { // 等会查询到 + o.setName(null); + }); + categoryMapper.insert(dbCategory); + // 测试 name 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName(null))); + // 准备参数 + InfraCategoryListReqVO reqVO = new InfraCategoryListReqVO(); + reqVO.setName(null); + + // 调用 + List list = categoryService.getCategoryList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbCategory, list.get(0)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/h2 b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/h2 new file mode 100644 index 0000000..4141766 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/h2 @@ -0,0 +1,10 @@ +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "infra_category" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "description" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '分类表'; + +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "infra_category"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/sql new file mode 100644 index 0000000..8140948 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/sql/sql @@ -0,0 +1,55 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '分类管理', '', 2, 0, 888, + 'category', '', 'infra/demo/index', 0, 'InfraCategory' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类查询', 'infra:category:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类创建', 'infra:category:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类更新', 'infra:category:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类删除', 'infra:category:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '分类导出', 'infra:category:export', 3, 5, @parentId, + '', '', '', 0 +); \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/ts/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/ts/index new file mode 100644 index 0000000..453c885 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/ts/index @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface CategoryVO { + id: number + name: string + parentId: number +} + +// 查询分类列表 +export const getCategoryList = async (params) => { + return await request.get({ url: `/infra/category/list`, params }) +} + +// 查询分类详情 +export const getCategory = async (id: number) => { + return await request.get({ url: `/infra/category/get?id=` + id }) +} + +// 新增分类 +export const createCategory = async (data: CategoryVO) => { + return await request.post({ url: `/infra/category/create`, data }) +} + +// 修改分类 +export const updateCategory = async (data: CategoryVO) => { + return await request.put({ url: `/infra/category/update`, data }) +} + +// 删除分类 +export const deleteCategory = async (id: number) => { + return await request.delete({ url: `/infra/category/delete?id=` + id }) +} + +// 导出分类 Excel +export const exportCategory = async (params) => { + return await request.download({ url: `/infra/category/export-excel`, params }) +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/CategoryForm b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/CategoryForm new file mode 100644 index 0000000..8e139fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/CategoryForm @@ -0,0 +1,114 @@ + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/index b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/index new file mode 100644 index 0000000..46902e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/vue/index @@ -0,0 +1,185 @@ + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/xml/InfraCategoryMapper b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/xml/InfraCategoryMapper new file mode 100644 index 0000000..025ac85 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/windows10/vue3_tree/xml/InfraCategoryMapper @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..58345ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,11 @@ +DELETE FROM "infra_config"; +DELETE FROM "infra_file_config"; +DELETE FROM "infra_file"; +DELETE FROM "infra_job"; +DELETE FROM "infra_job_log"; +DELETE FROM "infra_api_access_log"; +DELETE FROM "infra_api_error_log"; +DELETE FROM "infra_file_config"; +DELETE FROM "infra_data_source_config"; +DELETE FROM "infra_codegen_table"; +DELETE FROM "infra_codegen_column"; diff --git a/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..d4b19c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,216 @@ + +CREATE TABLE IF NOT EXISTS "infra_config" ( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', + "category" varchar(50) NOT NULL, + "type" tinyint NOT NULL, + "name" varchar(100) NOT NULL DEFAULT '' COMMENT '名字', + "config_key" varchar(100) NOT NULL DEFAULT '', + "value" varchar(500) NOT NULL DEFAULT '', + "visible" bit NOT NULL, + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '参数配置表'; + +CREATE TABLE IF NOT EXISTS "infra_file_config" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "storage" tinyint NOT NULL, + "remark" varchar(255), + "master" bit(1) NOT NULL, + "config" varchar(4096) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '文件配置表'; + +CREATE TABLE IF NOT EXISTS "infra_file" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "config_id" bigint NOT NULL, + "name" varchar(256), + "path" varchar(512), + "url" varchar(1024), + "type" varchar(63) DEFAULT NULL, + "size" bigint NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '文件表'; + +CREATE TABLE IF NOT EXISTS "infra_job" ( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '任务编号', + "name" varchar(32) NOT NULL COMMENT '任务名称', + "status" tinyint(4) NOT NULL COMMENT '任务状态', + "handler_name" varchar(64) NOT NULL COMMENT '处理器的名字', + "handler_param" varchar(255) DEFAULT NULL COMMENT '处理器的参数', + "cron_expression" varchar(32) NOT NULL COMMENT 'CRON 表达式', + "retry_count" int(11) NOT NULL DEFAULT '0' COMMENT '重试次数', + "retry_interval" int(11) NOT NULL DEFAULT '0' COMMENT '重试间隔', + "monitor_timeout" int(11) NOT NULL DEFAULT '0' COMMENT '监控超时时间', + "creator" varchar(64) DEFAULT '' COMMENT '创建者', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + "updater" varchar(64) DEFAULT '' COMMENT '更新者', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + "deleted" bit NOT NULL DEFAULT FALSE COMMENT '是否删除', + PRIMARY KEY ("id") +) COMMENT='定时任务表'; + +CREATE TABLE IF NOT EXISTS "infra_job_log" ( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号', + "job_id" bigint(20) NOT NULL COMMENT '任务编号', + "handler_name" varchar(64) NOT NULL COMMENT '处理器的名字', + "handler_param" varchar(255) DEFAULT NULL COMMENT '处理器的参数', + "execute_index" tinyint(4) NOT NULL DEFAULT '1' COMMENT '第几次执行', + "begin_time" datetime NOT NULL COMMENT '开始执行时间', + "end_time" datetime DEFAULT NULL COMMENT '结束执行时间', + "duration" int(11) DEFAULT NULL COMMENT '执行时长', + "status" tinyint(4) NOT NULL COMMENT '任务状态', + "result" varchar(4000) DEFAULT '' COMMENT '结果数据', + "creator" varchar(64) DEFAULT '' COMMENT '创建者', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + "updater" varchar(64) DEFAULT '' COMMENT '更新者', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + "deleted" bit(1) NOT NULL DEFAULT FALSE COMMENT '是否删除', + PRIMARY KEY ("id") +)COMMENT='定时任务日志表'; + +CREATE TABLE IF NOT EXISTS "infra_api_access_log" ( + "id" bigint not null GENERATED BY DEFAULT AS IDENTITY, + "trace_id" varchar(64) not null default '', + "user_id" bigint not null default '0', + "user_type" tinyint not null default '0', + "application_name" varchar(50) not null, + "request_method" varchar(16) not null default '', + "request_url" varchar(255) not null default '', + "request_params" varchar(8000) not null default '', + "response_body" varchar(8000) not null default '', + "user_ip" varchar(50) not null, + "user_agent" varchar(512) not null, + `operate_module` varchar(50) NOT NULL, + `operate_name` varchar(50) NOT NULL, + `operate_type` bigint(4) NOT NULL DEFAULT '0', + "begin_time" timestamp not null, + "end_time" timestamp not null, + "duration" integer not null, + "result_code" integer not null default '0', + "result_msg" varchar(512) default '', + "creator" varchar(64) default '', + "create_time" timestamp not null default current_timestamp, + "updater" varchar(64) default '', + "update_time" timestamp not null default current_timestamp, + "deleted" bit not null default false, + "tenant_id" bigint not null default '0', + primary key ("id") +) COMMENT 'API 访问日志表'; + +CREATE TABLE IF NOT EXISTS "infra_api_error_log" ( + "id" bigint not null GENERATED BY DEFAULT AS IDENTITY, + "trace_id" varchar(64) not null, + "user_id" bigint not null default '0', + "user_type" tinyint not null default '0', + "application_name" varchar(50) not null, + "request_method" varchar(16) not null, + "request_url" varchar(255) not null, + "request_params" varchar(8000) not null, + "user_ip" varchar(50) not null, + "user_agent" varchar(512) not null, + "exception_time" timestamp not null, + "exception_name" varchar(128) not null default '', + "exception_message" clob not null, + "exception_root_cause_message" clob not null, + "exception_stack_trace" clob not null, + "exception_class_name" varchar(512) not null, + "exception_file_name" varchar(512) not null, + "exception_method_name" varchar(512) not null, + "exception_line_number" integer not null, + "process_status" tinyint not null, + "process_time" timestamp default null, + "process_user_id" bigint default '0', + "creator" varchar(64) default '', + "create_time" timestamp not null default current_timestamp, + "updater" varchar(64) default '', + "update_time" timestamp not null default current_timestamp, + "deleted" bit not null default false, + "tenant_id" bigint not null default '0', + primary key ("id") +) COMMENT '系统异常日志'; + +CREATE TABLE IF NOT EXISTS "infra_data_source_config" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(100) NOT NULL, + "url" varchar(1024) NOT NULL, + "username" varchar(255) NOT NULL, + "password" varchar(255) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '数据源配置表'; + +CREATE TABLE IF NOT EXISTS "infra_codegen_table" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "data_source_config_id" bigint not null, + "scene" tinyint not null DEFAULT 1, + "table_name" varchar(200) NOT NULL, + "table_comment" varchar(500) NOT NULL, + "remark" varchar(500) NOT NULL, + "module_name" varchar(30) NOT NULL, + "business_name" varchar(30) NOT NULL, + "class_name" varchar(100) NOT NULL, + "class_comment" varchar(50) NOT NULL, + "author" varchar(50) NOT NULL, + "template_type" tinyint not null DEFAULT 1, + "front_type" tinyint not null, + "parent_menu_id" bigint not null, + "master_table_id" bigint not null, + "sub_join_column_id" bigint not null, + "sub_join_many" bit not null, + "tree_parent_column_id" bigint not null, + "tree_name_column_id" bigint not null, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '代码生成表定义表'; + +CREATE TABLE IF NOT EXISTS "infra_codegen_column" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "table_id" bigint not null, + "column_name" varchar(200) NOT NULL, + "data_type" varchar(100) NOT NULL, + "column_comment" varchar(500) NOT NULL, + "nullable" tinyint not null, + "primary_key" tinyint not null, + "ordinal_position" int not null, + "java_type" varchar(32) NOT NULL, + "java_field" varchar(64) NOT NULL, + "dict_type" varchar(200) NOT NULL, + "example" varchar(64) NOT NULL, + "create_operation" bit not null, + "update_operation" bit not null, + "list_operation" bit not null, + "list_operation_condition" varchar(32) not null, + "list_operation_result" bit not null, + "html_type" varchar(32) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '代码生成表字段定义表'; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/pom.xml new file mode 100644 index 0000000..f4854ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/pom.xml @@ -0,0 +1,31 @@ + + + + yudao + cn.iocoder.boot + ${revision} + + 4.0.0 + + yudao-module-mall + pom + + ${project.artifactId} + + + 商城大模块,由 product 商品、promotion 营销、trade 交易、statistics 统计等组成 + + + yudao-module-promotion-api + yudao-module-promotion-biz + yudao-module-product-api + yudao-module-product-biz + yudao-module-trade-api + yudao-module-trade-biz + yudao-module-statistics-api + yudao-module-statistics-biz + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/pom.xml new file mode 100644 index 0000000..123e7c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + cn.iocoder.boot + yudao-module-mall + ${revision} + + + yudao-module-product-api + jar + + ${project.artifactId} + + product 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApi.java new file mode 100644 index 0000000..38feb96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApi.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.product.api.category; + +import java.util.Collection; + +/** + * 商品分类 API 接口 + * + * @author owen + */ +public interface ProductCategoryApi { + + /** + * 校验商品分类是否有效。如下情况,视为无效: + * 1. 商品分类编号不存在 + * 2. 商品分类被禁用 + * + * @param ids 商品分类编号数组 + */ + void validateCategoryList(Collection ids); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApi.java new file mode 100644 index 0000000..b0ba1f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApi.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.product.api.comment; + +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; + +/** + * 产品评论 API 接口 + * + * @author HUIHUI + */ +public interface ProductCommentApi { + + /** + * 创建评论 + * + * @param createReqDTO 评论参数 + * @return 返回评论创建后的 id + */ + Long createComment(ProductCommentCreateReqDTO createReqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/ProductCommentCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/ProductCommentCreateReqDTO.java new file mode 100644 index 0000000..0afcfe9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/ProductCommentCreateReqDTO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.product.api.comment.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 评论创建请求 DTO + * + * @author HUIHUI + */ +@Data +public class ProductCommentCreateReqDTO { + + /** + * 商品 SKU 编号 + */ + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + /** + * 订单编号 + */ + private Long orderId; + /** + * 交易订单项编号 + */ + private Long orderItemId; + + /** + * 描述星级 1-5 分 + */ + @NotNull(message = "描述星级不能为空") + private Integer descriptionScores; + /** + * 服务星级 1-5 分 + */ + @NotNull(message = "服务星级不能为空") + private Integer benefitScores; + /** + * 评论内容 + */ + @NotNull(message = "评论内容不能为空") + private String content; + /** + * 评论图片地址数组,以逗号分隔最多上传 9 张 + */ + private List picUrls; + + /** + * 是否匿名 + */ + @NotNull(message = "是否匿名不能为空") + private Boolean anonymous; + /** + * 评价人 + */ + @NotNull(message = "评价人不能为空") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java new file mode 100644 index 0000000..b190928 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.product.api; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/dto/ProductPropertyValueDetailRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/dto/ProductPropertyValueDetailRespDTO.java new file mode 100644 index 0000000..2a1ab71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/property/dto/ProductPropertyValueDetailRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.product.api.property.dto; + +import lombok.Data; + +/** + * 商品属性项的明细 Response DTO + * + * @author 芋道源码 + */ +@Data +public class ProductPropertyValueDetailRespDTO { + + /** + * 属性的编号 + */ + private Long propertyId; + + /** + * 属性的名称 + */ + private String propertyName; + + /** + * 属性值的编号 + */ + private Long valueId; + + /** + * 属性值的名称 + */ + private String valueName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java new file mode 100644 index 0000000..3581fdb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.product.api.sku; + +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 商品 SKU API 接口 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +public interface ProductSkuApi { + + /** + * 查询 SKU 信息 + * + * @param id SKU 编号 + * @return SKU 信息 + */ + ProductSkuRespDTO getSku(Long id); + + /** + * 批量查询 SKU 数组 + * + * @param ids SKU 编号列表 + * @return SKU 数组 + */ + List getSkuList(Collection ids); + + /** + * 批量查询 SKU 数组 + * + * @param spuIds SPU 编号列表 + * @return SKU 数组 + */ + List getSkuListBySpuId(Collection spuIds); + + /** + * 更新 SKU 库存(增加 or 减少) + * + * @param updateStockReqDTO 更新请求 + */ + void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java new file mode 100644 index 0000000..338c4dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.product.api.sku.dto; + +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import lombok.Data; + +import java.util.List; + +/** + * 商品 SKU 信息 Response DTO + * + * @author LeeYan9 + * @since 2022-08-26 + */ +@Data +public class ProductSkuRespDTO { + + /** + * 商品 SKU 编号,自增 + */ + private Long id; + /** + * SPU 编号 + */ + private Long spuId; + + /** + * 属性数组 + */ + private List properties; + /** + * 销售价格,单位:分 + */ + private Integer price; + /** + * 市场价,单位:分 + */ + private Integer marketPrice; + /** + * 成本价,单位:分 + */ + private Integer costPrice; + /** + * SKU 的条形码 + */ + private String barCode; + /** + * 图片地址 + */ + private String picUrl; + /** + * 库存 + */ + private Integer stock; + /** + * 商品重量,单位:kg 千克 + */ + private Double weight; + /** + * 商品体积,单位:m^3 平米 + */ + private Double volume; + /** + * 一级分销的佣金,单位:分 + */ + private Integer firstBrokeragePrice; + /** + * 二级分销的佣金,单位:分 + */ + private Integer secondBrokeragePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java new file mode 100644 index 0000000..345c17c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuUpdateStockReqDTO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.product.api.sku.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 商品 SKU 更新库存 Request DTO + * + * @author LeeYan9 + * @since 2022-08-26 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductSkuUpdateStockReqDTO { + + /** + * 商品 SKU + */ + @NotNull(message = "商品 SKU 不能为空") + private List items; + + @Data + public static class Item { + + /** + * 商品 SKU 编号 + */ + @NotNull(message = "商品 SKU 编号不能为空") + private Long id; + + /** + * 库存变化数量 + * + * 正数:增加库存 + * 负数:扣减库存 + */ + @NotNull(message = "库存变化数量不能为空") + private Integer incrCount; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java new file mode 100644 index 0000000..233d129 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.product.api.spu; + +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 商品 SPU API 接口 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +public interface ProductSpuApi { + + /** + * 批量查询 SPU 数组 + * + * @param ids SPU 编号列表 + * @return SPU 数组 + */ + List getSpuList(Collection ids); + + /** + * 批量查询 SPU 数组,并且校验是否 SPU 是否有效。 + * + * 如下情况,视为无效: + * 1. 商品编号不存在 + * 2. 商品被禁用 + * + * @param ids SPU 编号列表 + * @return SPU 数组 + */ + List validateSpuList(Collection ids); + + /** + * 获得 SPU + * + * @return SPU + */ + ProductSpuRespDTO getSpu(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java new file mode 100644 index 0000000..5479b9a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.product.api.spu.dto; + +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import lombok.Data; + +// TODO @LeeYan9: ProductSpuRespDTO +/** + * 商品 SPU 信息 Response DTO + * + * @author LeeYan9 + * @since 2022-08-26 + */ +@Data +public class ProductSpuRespDTO { + + /** + * 商品 SPU 编号,自增 + */ + private Long id; + + // ========== 基本信息 ========= + + /** + * 商品名称 + */ + private String name; + + /** + * 商品分类编号 + */ + private Long categoryId; + /** + * 商品封面图 + */ + private String picUrl; + + /** + * 商品状态 + *

+ * 枚举 {@link ProductSpuStatusEnum} + */ + private Integer status; + + // ========== SKU 相关字段 ========= + + /** + * 规格类型 + * + * false - 单规格 + * true - 多规格 + */ + private Boolean specType; + /** + * 商品价格,单位使用:分 + */ + private Integer price; + /** + * 市场价,单位使用:分 + */ + private Integer marketPrice; + /** + * 成本价,单位使用:分 + */ + private Integer costPrice; + /** + * 库存 + */ + private Integer stock; + + // ========== 物流相关字段 ========= + + /** + * 物流配置模板编号 + * + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 + */ + private Long deliveryTemplateId; + + // ========== 营销相关字段 ========= + + /** + * 赠送积分 + */ + private Integer giveIntegral; + + // ========== 分销相关字段 ========= + + /** + * 分销类型 + * + * false - 默认 + * true - 自行设置 + */ + private Boolean subCommissionType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java new file mode 100644 index 0000000..b96dde1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/DictTypeConstants.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.product.enums; + +/** + * product 字典类型的枚举类 + * + * @author HUIHUI + */ +public interface DictTypeConstants { + + String PRODUCT_SPU_STATUS = "product_spu_status"; // 商品 SPU 状态 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..1d0ea18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.product.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Product 错误码枚举类 + * + * product 系统,使用 1-008-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 商品分类相关 1-008-001-000 ============ + ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_008_001_000, "商品分类不存在"); + ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_008_001_001, "父分类不存在"); + ErrorCode CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_008_001_002, "父分类不能是二级分类"); + ErrorCode CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_008_001_003, "存在子分类,无法删除"); + ErrorCode CATEGORY_DISABLED = new ErrorCode(1_008_001_004, "商品分类({})已禁用,无法使用"); + ErrorCode CATEGORY_HAVE_BIND_SPU = new ErrorCode(1_008_001_005, "类别下存在商品,无法删除"); + + // ========== 商品品牌相关编号 1-008-002-000 ========== + ErrorCode BRAND_NOT_EXISTS = new ErrorCode(1_008_002_000, "品牌不存在"); + ErrorCode BRAND_DISABLED = new ErrorCode(1_008_002_001, "品牌已禁用"); + ErrorCode BRAND_NAME_EXISTS = new ErrorCode(1_008_002_002, "品牌名称已存在"); + + // ========== 商品属性项 1-008-003-000 ========== + ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1_008_003_000, "属性项不存在"); + ErrorCode PROPERTY_EXISTS = new ErrorCode(1_008_003_001, "属性项的名称已存在"); + ErrorCode PROPERTY_DELETE_FAIL_VALUE_EXISTS = new ErrorCode(1_008_003_002, "属性项下存在属性值,无法删除"); + + // ========== 商品属性值 1-008-004-000 ========== + ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1_008_004_000, "属性值不存在"); + ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1_008_004_001, "属性值的名称已存在"); + + // ========== 商品 SPU 1-008-005-000 ========== + ErrorCode SPU_NOT_EXISTS = new ErrorCode(1_008_005_000, "商品 SPU 不存在"); + ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1_008_005_001, "商品分类不正确,原因:必须使用第二级的商品分类及以下"); + ErrorCode SPU_SAVE_FAIL_COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_005_002, "商品 SPU 保存失败,原因:优惠卷不存在"); + ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_003, "商品 SPU【{}】不处于上架状态"); + ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_004, "商品 SPU 不处于回收站状态"); + + // ========== 商品 SKU 1-008-006-000 ========== + ErrorCode SKU_NOT_EXISTS = new ErrorCode(1_008_006_000, "商品 SKU 不存在"); + ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1_008_006_001, "商品 SKU 的属性组合存在重复"); + ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1_008_006_002, "一个 SPU 下的每个 SKU,其属性项必须一致"); + ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1_008_006_003, "一个 SPU 下的每个 SKU,必须不重复"); + ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1_008_006_004, "商品 SKU 库存不足"); + + // ========== 商品 评价 1-008-007-000 ========== + ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1_008_007_000, "商品评价不存在"); + ErrorCode COMMENT_ORDER_EXISTS = new ErrorCode(1_008_007_001, "订单的商品评价已存在"); + + // ========== 商品 收藏 1-008-008-000 ========== + ErrorCode FAVORITE_EXISTS = new ErrorCode(1_008_008_000, "该商品已经被收藏"); + ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1_008_008_001, "商品收藏不存在"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java new file mode 100644 index 0000000..f3570c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ProductConstants.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.product.enums; + +/** + * Product 常量 + * + * @author HUIHUI + */ +public interface ProductConstants { + + /** + * 警戒库存 TODO 警戒库存暂时为 10,后期需要使用常量或者数据库配置替换 + */ + int ALERT_STOCK = 10; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentAuditStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentAuditStatusEnum.java new file mode 100644 index 0000000..276839d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentAuditStatusEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.product.enums.comment; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 商品评论的审批状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum ProductCommentAuditStatusEnum implements IntArrayValuable { + + NONE(1, "待审核"), + APPROVE(2, "审批通过"), + REJECT(2, "审批不通过"),; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentAuditStatusEnum::getStatus).toArray(); + + /** + * 审批状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java new file mode 100644 index 0000000..a114e1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/comment/ProductCommentScoresEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.product.enums.comment; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 商品评论的星级枚举 + * + * @author wangzhs + */ +@Getter +@AllArgsConstructor +public enum ProductCommentScoresEnum implements IntArrayValuable { + + ONE(1, "1星"), + TWO(2, "2星"), + THREE(3, "3星"), + FOUR(4, "4星"), + FIVE(5, "5星"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductCommentScoresEnum::getScores).toArray(); + + /** + * 星级 + */ + private final Integer scores; + + /** + * 星级名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java new file mode 100644 index 0000000..4ba6124 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.product.enums.spu; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 商品 SPU 状态 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum ProductSpuStatusEnum implements IntArrayValuable { + + RECYCLE(-1, "回收站"), + DISABLE(0, "下架"), + ENABLE(1, "上架"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + /** + * 判断是否处于【上架】状态 + * + * @param status 状态 + * @return 是否处于【上架】状态 + */ + public static boolean isEnable(Integer status) { + return ENABLE.getStatus().equals(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/pom.xml new file mode 100644 index 0000000..c8bad46 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/pom.xml @@ -0,0 +1,63 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-product-biz + jar + + ${project.artifactId} + + product 模块,主要实现商品相关功能 + 例如:品牌、商品分类、spu、sku等功能。 + + + + + cn.iocoder.boot + yudao-module-product-api + ${revision} + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApiImpl.java new file mode 100644 index 0000000..18f5c1d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/category/ProductCategoryApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.product.api.category; + +import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * 商品分类 API 接口实现类 + * + * @author owen + */ +@Service +@Validated +public class ProductCategoryApiImpl implements ProductCategoryApi { + + @Resource + private ProductCategoryService productCategoryService; + + @Override + public void validateCategoryList(Collection ids) { + productCategoryService.validateCategoryList(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApiImpl.java new file mode 100644 index 0000000..919c22c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.product.api.comment; + +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 商品评论 API 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class ProductCommentApiImpl implements ProductCommentApi { + + @Resource + private ProductCommentService productCommentService; + + @Override + public Long createComment(ProductCommentCreateReqDTO createReqDTO) { + return productCommentService.createComment(createReqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java new file mode 100644 index 0000000..162453c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.product.api; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java new file mode 100644 index 0000000..ac7ac16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.product.api.sku; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 商品 SKU API 实现类 + * + * @author LeeYan9 + * @since 2022-09-06 + */ +@Service +@Validated +public class ProductSkuApiImpl implements ProductSkuApi { + + @Resource + private ProductSkuService productSkuService; + + @Override + public ProductSkuRespDTO getSku(Long id) { + ProductSkuDO sku = productSkuService.getSku(id); + return BeanUtils.toBean(sku, ProductSkuRespDTO.class); + } + + @Override + public List getSkuList(Collection ids) { + List skus = productSkuService.getSkuList(ids); + return BeanUtils.toBean(skus, ProductSkuRespDTO.class); + } + + @Override + public List getSkuListBySpuId(Collection spuIds) { + List skus = productSkuService.getSkuListBySpuId(spuIds); + return BeanUtils.toBean(skus, ProductSkuRespDTO.class); + } + + @Override + public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) { + productSkuService.updateSkuStock(updateStockReqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java new file mode 100644 index 0000000..bca37b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.product.api.spu; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 商品 SPU API 接口实现类 + * + * @author LeeYan9 + * @since 2022-09-06 + */ +@Service +@Validated +public class ProductSpuApiImpl implements ProductSpuApi { + + @Resource + private ProductSpuService spuService; + + @Override + public List getSpuList(Collection ids) { + List spus = spuService.getSpuList(ids); + return BeanUtils.toBean(spus, ProductSpuRespDTO.class); + } + + @Override + public List validateSpuList(Collection ids) { + List spus = spuService.validateSpuList(ids); + return BeanUtils.toBean(spus, ProductSpuRespDTO.class); + } + + @Override + public ProductSpuRespDTO getSpu(Long id) { + ProductSpuDO spu = spuService.getSpu(id); + return BeanUtils.toBean(spu, ProductSpuRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java new file mode 100644 index 0000000..a7c9541 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/ProductBrandController.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*; +import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import cn.iocoder.yudao.module.product.service.brand.ProductBrandService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品品牌") +@RestController +@RequestMapping("/product/brand") +@Validated +public class ProductBrandController { + + @Resource + private ProductBrandService brandService; + + @PostMapping("/create") + @Operation(summary = "创建品牌") + @PreAuthorize("@ss.hasPermission('product:brand:create')") + public CommonResult createBrand(@Valid @RequestBody ProductBrandCreateReqVO createReqVO) { + return success(brandService.createBrand(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新品牌") + @PreAuthorize("@ss.hasPermission('product:brand:update')") + public CommonResult updateBrand(@Valid @RequestBody ProductBrandUpdateReqVO updateReqVO) { + brandService.updateBrand(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除品牌") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:brand:delete')") + public CommonResult deleteBrand(@RequestParam("id") Long id) { + brandService.deleteBrand(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得品牌") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:brand:query')") + public CommonResult getBrand(@RequestParam("id") Long id) { + ProductBrandDO brand = brandService.getBrand(id); + return success(ProductBrandConvert.INSTANCE.convert(brand)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取品牌精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getSimpleBrandList() { + // 获取品牌列表,只要开启状态的 + List list = brandService.getBrandListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 排序后,返回给前端 + return success(ProductBrandConvert.INSTANCE.convertList1(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得品牌分页") + @PreAuthorize("@ss.hasPermission('product:brand:query')") + public CommonResult> getBrandPage(@Valid ProductBrandPageReqVO pageVO) { + PageResult pageResult = brandService.getBrandPage(pageVO); + return success(ProductBrandConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/list") + @Operation(summary = "获得品牌列表") + @PreAuthorize("@ss.hasPermission('product:brand:query')") + public CommonResult> getBrandList(@Valid ProductBrandListReqVO listVO) { + List list = brandService.getBrandList(listVO); + list.sort(Comparator.comparing(ProductBrandDO::getSort)); + return success(ProductBrandConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandBaseVO.java new file mode 100644 index 0000000..a148d52 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandBaseVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** +* 商品品牌 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class ProductBrandBaseVO { + + @Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + @NotNull(message = "品牌名称不能为空") + private String name; + + @Schema(description = "品牌图片", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "品牌图片不能为空") + private String picUrl; + + @Schema(description = "品牌排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "品牌排序不能为空") + private Integer sort; + + @Schema(description = "品牌描述", example = "描述") + private String description; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandCreateReqVO.java new file mode 100644 index 0000000..dc85a47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品品牌创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductBrandCreateReqVO extends ProductBrandBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandListReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandListReqVO.java new file mode 100644 index 0000000..ed93ff0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandListReqVO.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 商品品牌分页 Request VO") +@Data +public class ProductBrandListReqVO { + + @Schema(description = "品牌名称", example = "苹果") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java new file mode 100644 index 0000000..3a6efc9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品品牌分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductBrandPageReqVO extends PageParam { + + @Schema(description = "品牌名称", example = "苹果") + private String name; + + @Schema(description = "状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java new file mode 100644 index 0000000..486fe76 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 品牌 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductBrandRespVO extends ProductBrandBaseVO { + + @Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandSimpleRespVO.java new file mode 100644 index 0000000..6379a5f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandSimpleRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 品牌精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductBrandSimpleRespVO { + + @Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "苹果") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandUpdateReqVO.java new file mode 100644 index 0000000..a39a683 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/brand/vo/ProductBrandUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.product.controller.admin.brand.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品品牌更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductBrandUpdateReqVO extends ProductBrandBaseVO { + + @Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "品牌编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/ProductCategoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/ProductCategoryController.java new file mode 100644 index 0000000..d2343e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/ProductCategoryController.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.product.controller.admin.category; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryRespVO; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategorySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品分类") +@RestController +@RequestMapping("/product/category") +@Validated +public class ProductCategoryController { + + @Resource + private ProductCategoryService categoryService; + + @PostMapping("/create") + @Operation(summary = "创建商品分类") + @PreAuthorize("@ss.hasPermission('product:category:create')") + public CommonResult createCategory(@Valid @RequestBody ProductCategorySaveReqVO createReqVO) { + return success(categoryService.createCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新商品分类") + @PreAuthorize("@ss.hasPermission('product:category:update')") + public CommonResult updateCategory(@Valid @RequestBody ProductCategorySaveReqVO updateReqVO) { + categoryService.updateCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商品分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('product:category:delete')") + public CommonResult deleteCategory(@RequestParam("id") Long id) { + categoryService.deleteCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得商品分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:category:query')") + public CommonResult getCategory(@RequestParam("id") Long id) { + ProductCategoryDO category = categoryService.getCategory(id); + return success(BeanUtils.toBean(category, ProductCategoryRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得商品分类列表") + @PreAuthorize("@ss.hasPermission('product:category:query')") + public CommonResult> getCategoryList(@Valid ProductCategoryListReqVO listReqVO) { + List list = categoryService.getCategoryList(listReqVO); + list.sort(Comparator.comparing(ProductCategoryDO::getSort)); + return success(BeanUtils.toBean(list, ProductCategoryRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryListReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryListReqVO.java new file mode 100644 index 0000000..9e5364c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryListReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.controller.admin.category.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Collection; + +@Schema(description = "管理后台 - 商品分类列表查询 Request VO") +@Data +public class ProductCategoryListReqVO { + + @Schema(description = "分类名称", example = "办公文具") + private String name; + + @Schema(description = "开启状态", example = "0") + private Integer status; + + @Schema(description = "父分类编号", example = "1") + private Long parentId; + + @Schema(description = "父分类编号数组", example = "1,2,3") + private Collection parentIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java new file mode 100644 index 0000000..c8ef92e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategoryRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.product.controller.admin.category.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 商品分类 Response VO") +@Data +public class ProductCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long id; + + @Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long parentId; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "办公文具") + private String name; + + @Schema(description = "移动端分类图", requiredMode = Schema.RequiredMode.REQUIRED) + private String picUrl; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sort; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "分类描述", example = "描述") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategorySaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategorySaveReqVO.java new file mode 100644 index 0000000..a637fde --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/category/vo/ProductCategorySaveReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.product.controller.admin.category.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品分类新增/更新 Request VO") +@Data +public class ProductCategorySaveReqVO { + + @Schema(description = "分类编号", example = "2") + private Long id; + + @Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "父分类编号不能为空") + private Long parentId; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "办公文具") + @NotBlank(message = "分类名称不能为空") + private String name; + + @Schema(description = "移动端分类图", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "移动端分类图不能为空") + private String picUrl; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sort; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @Schema(description = "分类描述", example = "描述") + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.http new file mode 100644 index 0000000..e69de29 diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java new file mode 100644 index 0000000..ea74713 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.*; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 商品评价") +@RestController +@RequestMapping("/product/comment") +@Validated +public class ProductCommentController { + + @Resource + private ProductCommentService productCommentService; + + @GetMapping("/page") + @Operation(summary = "获得商品评价分页") + @PreAuthorize("@ss.hasPermission('product:comment:query')") + public CommonResult> getCommentPage(@Valid ProductCommentPageReqVO pageVO) { + PageResult pageResult = productCommentService.getCommentPage(pageVO); + return success(BeanUtils.toBean(pageResult, ProductCommentRespVO.class)); + } + + @PutMapping("/update-visible") + @Operation(summary = "显示 / 隐藏评论") + @PreAuthorize("@ss.hasPermission('product:comment:update')") + public CommonResult updateCommentVisible(@Valid @RequestBody ProductCommentUpdateVisibleReqVO updateReqVO) { + productCommentService.updateCommentVisible(updateReqVO); + return success(true); + } + + @PutMapping("/reply") + @Operation(summary = "商家回复") + @PreAuthorize("@ss.hasPermission('product:comment:update')") + public CommonResult commentReply(@Valid @RequestBody ProductCommentReplyReqVO replyVO) { + productCommentService.replyComment(replyVO, getLoginUserId()); + return success(true); + } + + @PostMapping("/create") + @Operation(summary = "添加自评") + @PreAuthorize("@ss.hasPermission('product:comment:update')") + public CommonResult createComment(@Valid @RequestBody ProductCommentCreateReqVO createReqVO) { + productCommentService.createComment(createReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentCreateReqVO.java new file mode 100644 index 0000000..8fd8e64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentCreateReqVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Schema(description = "管理后台 - 商品评价创建 Request VO") +@Data +public class ProductCommentCreateReqVO { + + @Schema(description = "评价人", requiredMode = Schema.RequiredMode.REQUIRED, example = "16868") + private Long userId; + + @Schema(description = "评价订单项", requiredMode = Schema.RequiredMode.REQUIRED, example = "19292") + private Long orderItemId; + + @Schema(description = "评价人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小姑凉") + @NotNull(message = "评价人名称不能为空") + private String userNickname; + + @Schema(description = "评价人头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @NotNull(message = "评价人头像不能为空") + private String userAvatar; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "描述星级不能为空") + private Integer descriptionScores; + + @Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "服务星级分不能为空") + private Integer benefitScores; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "穿起来非常丝滑凉快") + @NotNull(message = "评论内容不能为空") + private String content; + + @Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, + example = "[https://www.iocoder.cn/xx.png]") + @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张") + private List picUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java new file mode 100644 index 0000000..3791f57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品评价分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductCommentPageReqVO extends PageParam { + + @Schema(description = "评价人名称", example = "王二狗") + private String userNickname; + + @Schema(description = "交易订单编号", example = "24428") + private Long orderId; + + @Schema(description = "商品SPU编号", example = "29502") + private Long spuId; + + @Schema(description = "商品SPU名称", example = "感冒药") + private String spuName; + + @Schema(description = "评分星级 1-5 分", example = "5") + @InEnum(ProductCommentScoresEnum.class) + private Integer scores; + + @Schema(description = "商家是否回复", example = "true") + private Boolean replyStatus; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentReplyReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentReplyReqVO.java new file mode 100644 index 0000000..97ad39d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentReplyReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品评价的商家回复 Request VO") +@Data +@ToString(callSuper = true) +public class ProductCommentReplyReqVO { + + @Schema(description = "评价编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721") + @NotNull(message = "评价编号不能为空") + private Long id; + + @Schema(description = "商家回复内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "谢谢亲") + @NotEmpty(message = "商家回复内容不能为空") + private String replyContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java new file mode 100644 index 0000000..605019a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment.vo; + +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 商品评价 Response VO") +@Data +public class ProductCommentRespVO { + + @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24965") + private Long id; + + @Schema(description = "评价人", requiredMode = Schema.RequiredMode.REQUIRED, example = "16868") + private Long userId; + + @Schema(description = "评价人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小姑凉") + private String userNickname; + + @Schema(description = "评价人头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String userAvatar; + @Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean anonymous; + + @Schema(description = "交易订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24428") + private Long orderId; + + @Schema(description = "评价订单项", requiredMode = Schema.RequiredMode.REQUIRED, example = "19292") + private Long orderItemId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long skuId; + + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String spuName; + + @Schema(description = "商品 SKU 图片地址", example = "https://www.iocoder.cn/yudao.jpg") + private String skuPicUrl; + + @Schema(description = "商品 SKU 规格值数组") + private List skuProperties; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED) + private Boolean visible; + + @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer scores; + + @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer descriptionScores; + + @Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer benefitScores; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "穿起来非常丝滑凉快") + private String content; + + @Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]") + private List picUrls; + + @Schema(description = "商家是否回复", requiredMode = Schema.RequiredMode.REQUIRED) + private Boolean replyStatus; + + @Schema(description = "回复管理员编号", example = "9527") + private Long replyUserId; + + @Schema(description = "商家回复内容", example = "感谢好评哦亲(づ ̄3 ̄)づ╭❤~") + private String replyContent; + + @Schema(description = "商家回复时间", example = "2023-08-08 12:20:55") + private LocalDateTime replyTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentUpdateVisibleReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentUpdateVisibleReqVO.java new file mode 100644 index 0000000..c88fbaf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentUpdateVisibleReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.product.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品评价可见修改 Request VO") +@Data +@ToString(callSuper = true) +public class ProductCommentUpdateVisibleReqVO { + + @Schema(description = "评价编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721") + @NotNull(message = "评价编号不能为空") + private Long id; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "是否可见不能为空") + private Boolean visible; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java new file mode 100644 index 0000000..721cf19 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; +import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.favorite.ProductFavoriteService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 商品收藏") +@RestController +@RequestMapping("/product/favorite") +@Validated +public class ProductFavoriteController { + + @Resource + private ProductFavoriteService productFavoriteService; + + @Resource + private ProductSpuService productSpuService; + + @GetMapping("/page") + @Operation(summary = "获得商品收藏分页") + @PreAuthorize("@ss.hasPermission('product:favorite:query')") + public CommonResult> getFavoritePage(@Valid ProductFavoritePageReqVO pageVO) { + PageResult pageResult = productFavoriteService.getFavoritePage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + // 拼接数据 + List spuList = productSpuService.getSpuList(convertSet(pageResult.getList(), ProductFavoriteDO::getSpuId)); + return success(ProductFavoriteConvert.INSTANCE.convertPage(pageResult, spuList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java new file mode 100644 index 0000000..68b0a0a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 商品收藏 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class ProductFavoriteBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5036") + @NotNull(message = "用户编号不能为空") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java new file mode 100644 index 0000000..3d78883 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品收藏分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductFavoritePageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "5036") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java new file mode 100644 index 0000000..3c22226 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品收藏的单个 Response VO") +@Data +@ToString(callSuper = true) +public class ProductFavoriteReqVO extends ProductFavoriteBaseVO { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32734") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java new file mode 100644 index 0000000..3c09aa8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品收藏 Response VO") +@Data +@ToString(callSuper = true) +public class ProductFavoriteRespVO extends ProductSpuRespVO { + + @Schema(description = "userId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + private Long userId; + + @Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java new file mode 100644 index 0000000..e0d47f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.product.controller.admin.history; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品浏览记录") +@RestController +@RequestMapping("/product/browse-history") +@Validated +public class ProductBrowseHistoryController { + + @Resource + private ProductBrowseHistoryService browseHistoryService; + + @GetMapping("/page") + @Operation(summary = "获得商品浏览记录分页") + @PreAuthorize("@ss.hasPermission('product:browse-history:query')") + public CommonResult> getBrowseHistoryPage(@Valid ProductBrowseHistoryPageReqVO pageReqVO) { + PageResult pageResult = browseHistoryService.getBrowseHistoryPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ProductBrowseHistoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryPageReqVO.java new file mode 100644 index 0000000..aa30102 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.product.controller.admin.history.vo; + +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品浏览记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductBrowseHistoryPageReqVO extends SortablePageParam { + + @Schema(description = "用户编号", example = "4314") + private Long userId; + + @Schema(description = "用户是否删除", example = "false") + private Boolean userDeleted; + + @Schema(description = "商品 SPU 编号", example = "42") + private Long spuId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java new file mode 100644 index 0000000..0e2e0cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.product.controller.admin.history.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 商品浏览记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ProductBrowseHistoryRespVO { + + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26055") + @ExcelProperty("记录编号") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4314") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户是否删除", example = "false") + private Boolean userDeleted; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "42") + @ExcelProperty("商品 SPU 编号") + private Long spuId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java new file mode 100644 index 0000000..ee9bf55 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.product.controller.admin.property; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品属性项") +@RestController +@RequestMapping("/product/property") +@Validated +public class ProductPropertyController { + + @Resource + private ProductPropertyService productPropertyService; + + @PostMapping("/create") + @Operation(summary = "创建属性项") + @PreAuthorize("@ss.hasPermission('product:property:create')") + public CommonResult createProperty(@Valid @RequestBody ProductPropertySaveReqVO createReqVO) { + return success(productPropertyService.createProperty(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新属性项") + @PreAuthorize("@ss.hasPermission('product:property:update')") + public CommonResult updateProperty(@Valid @RequestBody ProductPropertySaveReqVO updateReqVO) { + productPropertyService.updateProperty(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除属性项") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('product:property:delete')") + public CommonResult deleteProperty(@RequestParam("id") Long id) { + productPropertyService.deleteProperty(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得属性项") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult getProperty(@RequestParam("id") Long id) { + ProductPropertyDO property = productPropertyService.getProperty(id); + return success(BeanUtils.toBean(property, ProductPropertyRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得属性项分页") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) { + PageResult pageResult = productPropertyService.getPropertyPage(pageVO); + return success(BeanUtils.toBean(pageResult, ProductPropertyRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java new file mode 100644 index 0000000..d372a63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.product.controller.admin.property; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品属性值") +@RestController +@RequestMapping("/product/property/value") +@Validated +public class ProductPropertyValueController { + + @Resource + private ProductPropertyValueService productPropertyValueService; + + @PostMapping("/create") + @Operation(summary = "创建属性值") + @PreAuthorize("@ss.hasPermission('product:property:create')") + public CommonResult createPropertyValue(@Valid @RequestBody ProductPropertyValueSaveReqVO createReqVO) { + return success(productPropertyValueService.createPropertyValue(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新属性值") + @PreAuthorize("@ss.hasPermission('product:property:update')") + public CommonResult updatePropertyValue(@Valid @RequestBody ProductPropertyValueSaveReqVO updateReqVO) { + productPropertyValueService.updatePropertyValue(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除属性值") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:property:delete')") + public CommonResult deletePropertyValue(@RequestParam("id") Long id) { + productPropertyValueService.deletePropertyValue(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得属性值") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult getPropertyValue(@RequestParam("id") Long id) { + ProductPropertyValueDO value = productPropertyValueService.getPropertyValue(id); + return success(BeanUtils.toBean(value, ProductPropertyValueRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得属性值分页") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) { + PageResult pageResult = productPropertyValueService.getPropertyValuePage(pageVO); + return success(BeanUtils.toBean(pageResult, ProductPropertyValueRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java new file mode 100644 index 0000000..97b959d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 属性项 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductPropertyPageReqVO extends PageParam { + + @Schema(description = "名称", example = "颜色") + private String name; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java new file mode 100644 index 0000000..82a3a0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 属性项 Response VO") +@Data +public class ProductPropertyRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色") + private String name; + + @Schema(description = "备注", example = "颜色") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertySaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertySaveReqVO.java new file mode 100644 index 0000000..a96568c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertySaveReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Schema(description = "管理后台 - 属性项新增/更新 Request VO") +@Data +public class ProductPropertySaveReqVO { + + @Schema(description = "主键", example = "1") + private Long id; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色") + @NotBlank(message = "名称不能为空") + private String name; + + @Schema(description = "备注", example = "颜色") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java new file mode 100644 index 0000000..ff0c326 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品属性值分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductPropertyValuePageReqVO extends PageParam { + + @Schema(description = "属性项的编号", example = "1024") + private String propertyId; + + @Schema(description = "名称", example = "红色") + private String name; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java new file mode 100644 index 0000000..d401df1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 商品属性值 Response VO") +@Data +public class ProductPropertyValueRespVO { + + @Schema(description = "主键", example = "1024") + private Long id; + + @Schema(description = "属性项的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "属性项的编号不能为空") + private Long propertyId; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色") + @NotEmpty(message = "名称名字不能为空") + private String name; + + @Schema(description = "备注", example = "颜色") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueSaveReqVO.java new file mode 100644 index 0000000..1a33f71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueSaveReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品属性值新增/更新 Request VO") +@Data +public class ProductPropertyValueSaveReqVO { + + @Schema(description = "主键", example = "1024") + private Long id; + + @Schema(description = "属性项的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "属性项的编号不能为空") + private Long propertyId; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色") + @NotEmpty(message = "名称名字不能为空") + private String name; + + @Schema(description = "备注", example = "颜色") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http new file mode 100644 index 0000000..4ab7b4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http @@ -0,0 +1,4 @@ +### 获得商品 SPU 明细 +GET {{baseUrl}}/product/spu/get-detail?id=4 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java new file mode 100644 index 0000000..0c30897 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; + +@Tag(name = "管理后台 - 商品 SPU") +@RestController +@RequestMapping("/product/spu") +@Validated +public class ProductSpuController { + + @Resource + private ProductSpuService productSpuService; + @Resource + private ProductSkuService productSkuService; + + @PostMapping("/create") + @Operation(summary = "创建商品 SPU") + @PreAuthorize("@ss.hasPermission('product:spu:create')") + public CommonResult createProductSpu(@Valid @RequestBody ProductSpuSaveReqVO createReqVO) { + return success(productSpuService.createSpu(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新商品 SPU") + @PreAuthorize("@ss.hasPermission('product:spu:update')") + public CommonResult updateSpu(@Valid @RequestBody ProductSpuSaveReqVO updateReqVO) { + productSpuService.updateSpu(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新商品 SPU Status") + @PreAuthorize("@ss.hasPermission('product:spu:update')") + public CommonResult updateStatus(@Valid @RequestBody ProductSpuUpdateStatusReqVO updateReqVO) { + productSpuService.updateSpuStatus(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商品 SPU") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:spu:delete')") + public CommonResult deleteSpu(@RequestParam("id") Long id) { + productSpuService.deleteSpu(id); + return success(true); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得商品 SPU 明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult getSpuDetail(@RequestParam("id") Long id) { + // 获得商品 SPU + ProductSpuDO spu = productSpuService.getSpu(id); + if (spu == null) { + return success(null); + } + // 查询商品 SKU + List skus = productSkuService.getSkuListBySpuId(spu.getId()); + return success(ProductSpuConvert.INSTANCE.convert(spu, skus)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获得商品 SPU 精简列表") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult> getSpuSimpleList() { + List list = productSpuService.getSpuListByStatus(ProductSpuStatusEnum.ENABLE.getStatus()); + // 降序排序后,返回给前端 + list.sort(Comparator.comparing(ProductSpuDO::getSort).reversed()); + return success(BeanUtils.toBean(list, ProductSpuSimpleRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得商品 SPU 详情列表") + @Parameter(name = "spuIds", description = "spu 编号列表", required = true, example = "[1,2,3]") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult> getSpuList(@RequestParam("spuIds") Collection spuIds) { + return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespListVO( + productSpuService.getSpuList(spuIds), productSkuService.getSkuListBySpuId(spuIds))); + } + + @GetMapping("/page") + @Operation(summary = "获得商品 SPU 分页") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult> getSpuPage(@Valid ProductSpuPageReqVO pageVO) { + PageResult pageResult = productSpuService.getSpuPage(pageVO); + return success(BeanUtils.toBean(pageResult, ProductSpuRespVO.class)); + } + + @GetMapping("/get-count") + @Operation(summary = "获得商品 SPU 分页 tab count") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult> getSpuCount() { + return success(productSpuService.getTabsCount()); + } + + @GetMapping("/export") + @Operation(summary = "导出商品") + @PreAuthorize("@ss.hasPermission('product:spu:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSpuList(@Validated ProductSpuPageReqVO reqVO, + HttpServletResponse response) throws IOException { + reqVO.setPageSize(PAGE_SIZE_NONE); + List list = productSpuService.getSpuPage(reqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "商品列表.xls", "数据", ProductSpuRespVO.class, + BeanUtils.toBean(list, ProductSpuRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuRespVO.java new file mode 100644 index 0000000..f977d33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 商品 SKU Response VO") +@Data +public class ProductSkuRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "商品 SKU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖") + private String name; + + @Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + private Integer price; + + @Schema(description = "市场价", example = "2999") + private Integer marketPrice; + + @Schema(description = "成本价", example = "19") + private Integer costPrice; + + @Schema(description = "条形码", example = "15156165456") + private String barCode; + + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer stock; + + @Schema(description = "商品重量,单位:kg 千克", example = "1.2") + private Double weight; + + @Schema(description = "商品体积,单位:m^3 平米", example = "2.5") + private Double volume; + + @Schema(description = "一级分销的佣金,单位:分", example = "199") + private Integer firstBrokeragePrice; + + @Schema(description = "二级分销的佣金,单位:分", example = "19") + private Integer secondBrokeragePrice; + + @Schema(description = "属性数组") + private List properties; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuSaveReqVO.java new file mode 100644 index 0000000..6aa703b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSkuSaveReqVO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 商品 SKU 创建/更新 Request VO") +@Data +public class ProductSkuSaveReqVO { + + @Schema(description = "商品 SKU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖") + @NotEmpty(message = "商品 SKU 名字不能为空") + private String name; + + @Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + @NotNull(message = "销售价格,单位:分不能为空") + private Integer price; + + @Schema(description = "市场价", example = "2999") + private Integer marketPrice; + + @Schema(description = "成本价", example = "19") + private Integer costPrice; + + @Schema(description = "条形码", example = "15156165456") + private String barCode; + + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @NotNull(message = "图片地址不能为空") + private String picUrl; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + @NotNull(message = "库存不能为空") + private Integer stock; + + @Schema(description = "商品重量,单位:kg 千克", example = "1.2") + private Double weight; + + @Schema(description = "商品体积,单位:m^3 平米", example = "2.5") + private Double volume; + + @Schema(description = "一级分销的佣金,单位:分", example = "199") + private Integer firstBrokeragePrice; + + @Schema(description = "二级分销的佣金,单位:分", example = "19") + private Integer secondBrokeragePrice; + + @Schema(description = "属性数组") + private List properties; + + @Schema(description = "商品属性") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Property { + + @Schema(description = "属性编号", example = "10") + private Long propertyId; + + @Schema(description = "属性名字", example = "颜色") + private String propertyName; + + @Schema(description = "属性值编号", example = "10") + private Long valueId; + + @Schema(description = "属性值名字", example = "红色") + private String valueName; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java new file mode 100644 index 0000000..81cff42 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品 SPU 分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductSpuPageReqVO extends PageParam { + + /** + * 出售中商品 + */ + public static final Integer FOR_SALE = 0; + + /** + * 仓库中商品 + */ + public static final Integer IN_WAREHOUSE = 1; + + /** + * 已售空商品 + */ + public static final Integer SOLD_OUT = 2; + + /** + * 警戒库存 + */ + public static final Integer ALERT_STOCK = 3; + + /** + * 商品回收站 + */ + public static final Integer RECYCLE_BIN = 4; + + @Schema(description = "商品名称", example = "清凉小短袖") + private String name; + + @Schema(description = "前端请求的tab类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer tabType; + + @Schema(description = "商品分类编号", example = "1") + private Long categoryId; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java new file mode 100644 index 0000000..fbc7552 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; +import cn.iocoder.yudao.module.product.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 商品 SPU Response VO") +@Data +@ExcelIgnoreUnannotated +public class ProductSpuRespVO { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + @ExcelProperty("商品编号") + private Long id; + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖") + @ExcelProperty("商品名称") + private String name; + + @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗") + @ExcelProperty("关键字") + private String keyword; + + @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介") + @ExcelProperty("商品简介") + private String introduction; + + @Schema(description = "商品详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖详情") + @ExcelProperty("商品详情") + private String description; + + @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("商品分类编号") + private Long categoryId; + + @Schema(description = "商品品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("商品品牌编号") + private Long brandId; + + @Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @ExcelProperty("商品封面图") + private String picUrl; + + @Schema(description = "商品轮播图", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]") + private List sliderPicUrls; + + @Schema(description = "排序字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("排序字段") + private Integer sort; + + @Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "商品状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.PRODUCT_SPU_STATUS) + private Integer status; + + @Schema(description = "商品创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-05-24 00:00:00") + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + // ========== SKU 相关字段 ========= + + @Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty("规格类型") + private Boolean specType; + + @Schema(description = "商品价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + @ExcelProperty(value = "商品价格", converter = MoneyConvert.class) + private Integer price; + + @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "199") + @ExcelProperty(value = "市场价", converter = MoneyConvert.class) + private Integer marketPrice; + + @Schema(description = "成本价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "19") + @ExcelProperty(value = "成本价", converter = MoneyConvert.class) + private Integer costPrice; + + @Schema(description = "商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") + @ExcelProperty("库存") + private Integer stock; + + @Schema(description = "SKU 数组") + private List skus; + + // ========== 物流相关字段 ========= + + @Schema(description = "配送方式数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private List deliveryTypes; + + @Schema(description = "物流配置模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + @ExcelProperty("物流配置模板编号") + private Long deliveryTemplateId; + + // ========== 营销相关字段 ========= + + @Schema(description = "赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + @ExcelProperty("赠送积分") + private Integer giveIntegral; + + @Schema(description = "分销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @ExcelProperty("分销类型") + private Boolean subCommissionType; + + // ========== 统计相关字段 ========= + + @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + @ExcelProperty("商品销量") + private Integer salesCount; + + @Schema(description = "虚拟销量", example = "66") + @ExcelProperty("虚拟销量") + private Integer virtualSalesCount; + + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @ExcelProperty("商品点击量") + private Integer browseCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSaveReqVO.java new file mode 100644 index 0000000..3408145 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSaveReqVO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 商品 SPU 新增/更新 Request VO") +@Data +public class ProductSpuSaveReqVO { + + @Schema(description = "商品编号", example = "1") + private Long id; + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖") + @NotEmpty(message = "商品名称不能为空") + private String name; + + @Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑不出汗") + @NotEmpty(message = "商品关键字不能为空") + private String keyword; + + @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介") + @NotEmpty(message = "商品简介不能为空") + private String introduction; + + @Schema(description = "商品详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖详情") + @NotEmpty(message = "商品详情不能为空") + private String description; + + @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品分类不能为空") + private Long categoryId; + + @Schema(description = "商品品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品品牌不能为空") + private Long brandId; + + @Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @NotEmpty(message = "商品封面图不能为空") + private String picUrl; + + @Schema(description = "商品轮播图", requiredMode = Schema.RequiredMode.REQUIRED, + example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]") + private List sliderPicUrls; + + @Schema(description = "排序字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品排序字段不能为空") + private Integer sort; + + // ========== SKU 相关字段 ========= + + @Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "商品规格类型不能为空") + private Boolean specType; + + // ========== 物流相关字段 ========= + + @Schema(description = "配送方式数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "配送方式不能为空") + private List deliveryTypes; + + @Schema(description = "物流配置模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + private Long deliveryTemplateId; + + // ========== 营销相关字段 ========= + + @Schema(description = "赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + @NotNull(message = "商品赠送积分不能为空") + private Integer giveIntegral; + + @Schema(description = "分销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "商品分销类型不能为空") + private Boolean subCommissionType; + + // ========== 统计相关字段 ========= + + @Schema(description = "虚拟销量", example = "66") + private Integer virtualSalesCount; + + @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + private Integer salesCount; + + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + private Integer browseCount; + + // ========== SKU 相关字段 ========= + + @Schema(description = "SKU 数组") + @Valid + private List skus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java new file mode 100644 index 0000000..7d9d0d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品 SPU 精简 Response VO") +@Data +@ToString(callSuper = true) +public class ProductSpuSimpleRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "213") + private Long id; + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖") + private String name; + + @Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") + private Integer price; + + @Schema(description = "商品市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "199") + private Integer marketPrice; + + @Schema(description = "商品成本价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "19") + private Integer costPrice; + + @Schema(description = "商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + private Integer stock; + + // ========== 统计相关字段 ========= + + @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer salesCount; + + @Schema(description = "商品虚拟销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20000") + private Integer virtualSalesCount; + + @Schema(description = "商品浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + private Integer browseCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java new file mode 100644 index 0000000..e36e684 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO") +@Data +public class ProductSpuUpdateStatusReqVO{ + + @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品编号不能为空") + private Long id; + + @Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品状态不能为空") + @InEnum(ProductSpuStatusEnum.class) + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java new file mode 100644 index 0000000..eb651e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.product.controller.app.category; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.app.category.vo.AppCategoryRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 商品分类") +@RestController +@RequestMapping("/product/category") +@Validated +public class AppCategoryController { + + @Resource + private ProductCategoryService categoryService; + + @GetMapping("/list") + @Operation(summary = "获得商品分类列表") + public CommonResult> getProductCategoryList() { + List list = categoryService.getEnableCategoryList(); + list.sort(Comparator.comparing(ProductCategoryDO::getSort)); + return success(BeanUtils.toBean(list, AppCategoryRespVO.class)); + } + + @GetMapping("/list-by-ids") + @Operation(summary = "获得商品分类列表,指定编号") + @Parameter(name = "ids", description = "商品分类编号数组", required = true) + public CommonResult> getProductCategoryList(@RequestParam("ids") List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + List list = categoryService.getEnableCategoryList(ids); + list.sort(Comparator.comparing(ProductCategoryDO::getSort)); + return success(BeanUtils.toBean(list, AppCategoryRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/vo/AppCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/vo/AppCategoryRespVO.java new file mode 100644 index 0000000..02e5f17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/vo/AppCategoryRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.product.controller.app.category.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@Schema(description = "用户 APP - 商品分类 Response VO") +public class AppCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long id; + + @Schema(description = "父分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "父分类编号不能为空") + private Long parentId; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "办公文具") + @NotBlank(message = "分类名称不能为空") + private String name; + + @Schema(description = "分类图片", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "分类图片不能为空") + private String picUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.http new file mode 100644 index 0000000..e69de29 diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java new file mode 100644 index 0000000..e6e332a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.product.controller.app.comment; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 商品评价") +@RestController +@RequestMapping("/product/comment") +@Validated +public class AppProductCommentController { + + @Resource + private ProductCommentService productCommentService; + + @GetMapping("/page") + @Operation(summary = "获得商品评价分页") + public CommonResult> getCommentPage(@Valid AppCommentPageReqVO pageVO) { + // 查询评论分页 + PageResult pageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + pageResult.getList().forEach(item -> { + if (Boolean.TRUE.equals(item.getAnonymous())) { + item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS); + } + }); + return success(BeanUtils.toBean(pageResult, AppProductCommentRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java new file mode 100644 index 0000000..8a3cf5e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.product.controller.app.comment.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 商品评价分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppCommentPageReqVO extends PageParam { + + /** + * 好评 + */ + public static final Integer GOOD_COMMENT = 1; + /** + * 中评 + */ + public static final Integer MEDIOCRE_COMMENT = 2; + /** + * 差评 + */ + public static final Integer NEGATIVE_COMMENT = 3; + + @Schema(description = "商品 SPU 编号", example = "29502") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "app 评论页 tab 类型 (0 全部、1 好评、2 中评、3 差评)", example = "0") + @NotNull(message = "商品 SPU 编号不能为空") + private Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java new file mode 100644 index 0000000..5a77d87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.product.controller.app.comment.vo; + +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 商品评价详情 Response VO") +@Data +@ToString(callSuper = true) +public class AppProductCommentRespVO { + + @Schema(description = "评价人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721") + private Long userId; + + @Schema(description = "评价人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String userNickname; + + @Schema(description = "评价人头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String userAvatar; + + @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24965") + private Long id; + + @Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean anonymous; + + @Schema(description = "交易订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24428") + private Long orderId; + + @Schema(description = "交易订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8233") + private Long orderItemId; + + @Schema(description = "商家是否回复", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean replyStatus; + + @Schema(description = "回复管理员编号", example = "22212") + private Long replyUserId; + + @Schema(description = "商家回复内容", example = "亲,你的好评就是我的动力(*^▽^*)") + private String replyContent; + + @Schema(description = "商家回复时间") + private LocalDateTime replyTime; + + @Schema(description = "追加评价内容", example = "穿了很久都很丝滑诶") + private String additionalContent; + + @Schema(description = "追评评价图片地址数组,以逗号分隔最多上传 9 张", example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]") + private List additionalPicUrls; + + @Schema(description = "追加评价时间") + private LocalDateTime additionalTime; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "91192") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑小短袖") + @NotNull(message = "商品 SPU 名称不能为空") + private String spuName; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "81192") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "商品 SKU 属性", requiredMode = Schema.RequiredMode.REQUIRED) + private List skuProperties; + + @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "评分星级 1-5 分不能为空") + private Integer scores; + + @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "描述星级 1-5 分不能为空") + private Integer descriptionScores; + + @Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "服务星级 1-5 分不能为空") + private Integer benefitScores; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "哇,真的很丝滑凉快诶,好评") + @NotNull(message = "评论内容不能为空") + private String content; + + @Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, + example = "[https://www.iocoder.cn/xx.png]") + @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张") + private List picUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/AppFavoriteController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/AppFavoriteController.java new file mode 100644 index 0000000..f6087a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/AppFavoriteController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.product.controller.app.favorite; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteBatchReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO; +import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.favorite.ProductFavoriteService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 商品收藏") +@RestController +@RequestMapping("/product/favorite") +public class AppFavoriteController { + + @Resource + private ProductFavoriteService productFavoriteService; + @Resource + private ProductSpuService productSpuService; + + @PostMapping(value = "/create") + @Operation(summary = "添加商品收藏") + @PreAuthenticated + public CommonResult createFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) { + return success(productFavoriteService.createFavorite(getLoginUserId(), reqVO.getSpuId())); + } + + @DeleteMapping(value = "/delete") + @Operation(summary = "取消单个商品收藏") + @PreAuthenticated + public CommonResult deleteFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) { + productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId()); + return success(Boolean.TRUE); + } + + @GetMapping(value = "/page") + @Operation(summary = "获得商品收藏分页") + @PreAuthenticated + public CommonResult> getFavoritePage(AppFavoritePageReqVO reqVO) { + PageResult favoritePage = productFavoriteService.getFavoritePage(getLoginUserId(), reqVO); + if (CollUtil.isEmpty(favoritePage.getList())) { + return success(PageResult.empty()); + } + + // 得到商品 spu 信息 + List favorites = favoritePage.getList(); + List spuIds = convertList(favorites, ProductFavoriteDO::getSpuId); + List spus = productSpuService.getSpuList(spuIds); + + // 转换 VO 结果 + PageResult pageResult = new PageResult<>(favoritePage.getTotal()); + pageResult.setList(ProductFavoriteConvert.INSTANCE.convertList(favorites, spus)); + return success(pageResult); + } + + @GetMapping(value = "/exits") + @Operation(summary = "检查是否收藏过商品") + @PreAuthenticated + public CommonResult isFavoriteExists(AppFavoriteReqVO reqVO) { + ProductFavoriteDO favorite = productFavoriteService.getFavorite(getLoginUserId(), reqVO.getSpuId()); + return success(favorite != null); + } + + @GetMapping(value = "/get-count") + @Operation(summary = "获得商品收藏数量") + @PreAuthenticated + public CommonResult getFavoriteCount() { + return success(productFavoriteService.getFavoriteCount(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteBatchReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteBatchReqVO.java new file mode 100644 index 0000000..fbb1afb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteBatchReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.product.controller.app.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "用户 APP - 商品收藏的批量 Request VO") // 用于收藏、取消收藏、获取收藏 +@Data +public class AppFavoriteBatchReqVO { + + @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502") + @NotEmpty(message = "商品 SPU 编号数组不能为空") + private List spuIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoritePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoritePageReqVO.java new file mode 100644 index 0000000..2aacc3e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoritePageReqVO.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.product.controller.app.favorite.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 商品收藏分页查询 Request VO") +@Data +public class AppFavoritePageReqVO extends PageParam { +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteReqVO.java new file mode 100644 index 0000000..4f95a6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.product.controller.app.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "用户 APP - 商品收藏的单个 Request VO") // 用于收藏、取消收藏、获取收藏 +@Data +public class AppFavoriteReqVO { + + @Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteRespVO.java new file mode 100644 index 0000000..db2ea90 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.product.controller.app.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "用户 App - 商品收藏 Response VO") +@Data +public class AppFavoriteRespVO { + + @Schema(description = "编号", requiredMode = REQUIRED, example = "1") + private Long id; + + @Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502") + private Long spuId; + + // ========== 商品相关字段 ========== + + @Schema(description = "商品 SPU 名称", example = "赵六") + private String spuName; + + @Schema(description = "商品封面图", example = "https://domain/pic.png") + private String picUrl; + + @Schema(description = "商品单价", example = "100") + private Integer price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/AppProductBrowseHistoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/AppProductBrowseHistoryController.java new file mode 100644 index 0000000..b275151 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/AppProductBrowseHistoryController.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.product.controller.app.history; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryDeleteReqVO; +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.history.vo.AppProductBrowseHistoryRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 商品浏览记录") +@RestController +@RequestMapping("/product/browse-history") +public class AppProductBrowseHistoryController { + + @Resource + private ProductBrowseHistoryService productBrowseHistoryService; + @Resource + private ProductSpuService productSpuService; + + @DeleteMapping(value = "/delete") + @Operation(summary = "删除商品浏览记录") + @PreAuthenticated + public CommonResult deleteBrowseHistory(@RequestBody @Valid AppProductBrowseHistoryDeleteReqVO reqVO) { + productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), reqVO.getSpuIds()); + return success(Boolean.TRUE); + } + + @DeleteMapping(value = "/clean") + @Operation(summary = "清空商品浏览记录") + @PreAuthenticated + public CommonResult deleteBrowseHistory() { + productBrowseHistoryService.hideUserBrowseHistory(getLoginUserId(), null); + return success(Boolean.TRUE); + } + + @GetMapping(value = "/page") + @Operation(summary = "获得商品浏览记录分页") + @PreAuthenticated + public CommonResult> getBrowseHistoryPage(AppProductBrowseHistoryPageReqVO reqVO) { + ProductBrowseHistoryPageReqVO pageReqVO = BeanUtils.toBean(reqVO, ProductBrowseHistoryPageReqVO.class) + .setUserId(getLoginUserId()) + .setUserDeleted(false); // 排除用户已删除的(隐藏的) + PageResult pageResult = productBrowseHistoryService.getBrowseHistoryPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 得到商品 spu 信息 + Set spuIds = convertSet(pageResult.getList(), ProductBrowseHistoryDO::getSpuId); + Map spuMap = convertMap(productSpuService.getSpuList(spuIds), ProductSpuDO::getId); + return success(BeanUtils.toBean(pageResult, AppProductBrowseHistoryRespVO.class, + vo -> Optional.ofNullable(spuMap.get(vo.getSpuId())) + .ifPresent(spu -> vo.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setPrice(spu.getPrice())))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryDeleteReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryDeleteReqVO.java new file mode 100644 index 0000000..13eb7dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryDeleteReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.product.controller.app.history.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "用户 APP - 删除商品浏览记录的 Request VO") +@Data +public class AppProductBrowseHistoryDeleteReqVO { + + @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502") + @NotEmpty(message = "商品 SPU 编号数组不能为空") + private List spuIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryPageReqVO.java new file mode 100644 index 0000000..f959fd0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.controller.app.history.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "用户 APP - 商品浏览记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppProductBrowseHistoryPageReqVO extends PageParam { + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryRespVO.java new file mode 100644 index 0000000..05b528c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/history/vo/AppProductBrowseHistoryRespVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.product.controller.app.history.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "用户 App - 商品浏览记录 Response VO") +@Data +public class AppProductBrowseHistoryRespVO { + + @Schema(description = "编号", requiredMode = REQUIRED, example = "1") + private Long id; + + @Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502") + private Long spuId; + + // ========== 商品相关字段 ========== + + @Schema(description = "商品 SPU 名称", example = "赵六") + private String spuName; + + @Schema(description = "商品封面图", example = "https://domain/pic.png") + private String picUrl; + + @Schema(description = "商品单价", example = "100") + private Integer price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java new file mode 100644 index 0000000..379e851 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无时间作用,避免 package 缩进 + */ +package cn.iocoder.yudao.module.product.controller.app.property; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java new file mode 100644 index 0000000..6538bea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/property/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无时间作用,避免 package 缩进 + */ +package cn.iocoder.yudao.module.product.controller.app.property.vo.property; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java new file mode 100644 index 0000000..5cac091 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/property/vo/value/AppProductPropertyValueDetailRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.product.controller.app.property.vo.value; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 商品属性值的明细 Response VO") +@Data +public class AppProductPropertyValueDetailRespVO { + + @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long propertyId; + + @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色") + private String propertyName; + + @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long valueId; + + @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色") + private String valueName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http new file mode 100644 index 0000000..c391b58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http @@ -0,0 +1,18 @@ +### 获得订单交易的分页(默认) +GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得订单交易的分页(价格) +GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=price&sortAsc=true +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得订单交易的分页(销售) +GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=salesCount&sortAsc=true +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得商品 SPU 明细 +GET {{appApi}}/product/spu/get-detail?id=102 +tenant-id: {{appTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java new file mode 100644 index 0000000..f64e6f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -0,0 +1,152 @@ +package cn.iocoder.yudao.module.product.controller.app.spu; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; + +@Tag(name = "用户 APP - 商品 SPU") +@RestController +@RequestMapping("/product/spu") +@Validated +public class AppProductSpuController { + + @Resource + private ProductSpuService productSpuService; + @Resource + private ProductSkuService productSkuService; + @Resource + private ProductBrowseHistoryService productBrowseHistoryService; + + @Resource + private MemberLevelApi memberLevelApi; + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/list-by-ids") + @Operation(summary = "获得商品 SPU 列表") + @Parameter(name = "ids", description = "编号列表", required = true) + public CommonResult> getSpuList(@RequestParam("ids") Set ids) { + List list = productSpuService.getSpuList(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + // 拼接返回 + list.forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); + List voList = BeanUtils.toBean(list, AppProductSpuRespVO.class); + // 处理 vip 价格 + MemberLevelRespDTO memberLevel = getMemberLevel(); + voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); + return success(voList); + } + + @GetMapping("/page") + @Operation(summary = "获得商品 SPU 分页") + public CommonResult> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { + PageResult pageResult = productSpuService.getSpuPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); + PageResult voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class); + // 处理 vip 价格 + MemberLevelRespDTO memberLevel = getMemberLevel(); + voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); + return success(voPageResult); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得商品 SPU 明细") + @Parameter(name = "id", description = "编号", required = true) + public CommonResult getSpuDetail(@RequestParam("id") Long id) { + // 获得商品 SPU + ProductSpuDO spu = productSpuService.getSpu(id); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { + throw exception(SPU_NOT_ENABLE, spu.getName()); + } + // 获得商品 SKU + List skus = productSkuService.getSkuListBySpuId(spu.getId()); + + // 增加浏览量 + productSpuService.updateBrowseCount(id, 1); + // 保存浏览记录 + productBrowseHistoryService.createBrowseHistory(getLoginUserId(), id); + + // 拼接返回 + spu.setBrowseCount(spu.getBrowseCount() + spu.getVirtualSalesCount()); + AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class) + .setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class)); + // 处理 vip 价格 + MemberLevelRespDTO memberLevel = getMemberLevel(); + spuVO.setVipPrice(calculateVipPrice(spuVO.getPrice(), memberLevel)); + return success(spuVO); + } + + private MemberLevelRespDTO getMemberLevel() { + Long userId = getLoginUserId(); + if (userId == null) { + return null; + } + MemberUserRespDTO user = memberUserApi.getUser(userId); + if (user.getLevelId() == null || user.getLevelId() <= 0) { + return null; + } + return memberLevelApi.getMemberLevel(user.getLevelId()); + } + + /** + * 计算会员 VIP 优惠价格 + * + * @param price 原价 + * @param memberLevel 会员等级 + * @return 优惠价格 + */ + public Integer calculateVipPrice(Integer price, MemberLevelRespDTO memberLevel) { + if (memberLevel == null || memberLevel.getDiscountPercent() == null) { + return 0; + } + Integer newPrice = price * memberLevel.getDiscountPercent() / 100; + return price - newPrice; + } + + // TODO 芋艿:商品的浏览记录; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java new file mode 100644 index 0000000..f1ee49b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.product.controller.app.spu.vo; + +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 商品 SPU 明细 Response VO") +@Data +public class AppProductSpuDetailRespVO { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + // ========== 基本信息 ========= + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个快乐简介") + private String introduction; + + @Schema(description = "商品详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是商品描述") + private String description; + + @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long categoryId; + + @Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED) + private String picUrl; + + @Schema(description = "商品轮播图", requiredMode = Schema.RequiredMode.REQUIRED) + private List sliderPicUrls; + + // ========== 营销相关字段 ========= + + // ========== SKU 相关字段 ========= + + @Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean specType; + + @Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer price; + + @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer marketPrice; + + @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格 + private Integer vipPrice; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Integer stock; + + /** + * SKU 数组 + */ + private List skus; + + // ========== 统计相关字段 ========= + + @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer salesCount; + + @Schema(description = "用户 App - 商品 SPU 明细的 SKU 信息") + @Data + public static class Sku { + + @Schema(description = "商品 SKU 编号", example = "1") + private Long id; + + /** + * 商品属性数组 + */ + private List properties; + + @Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer price; + + @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer marketPrice; + + @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格 + private Integer vipPrice; + + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer stock; + + @Schema(description = "商品重量", example = "1") // 单位:kg 千克 + private Double weight; + + @Schema(description = "商品体积", example = "1024") // 单位:m^3 平米 + private Double volume; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java new file mode 100644 index 0000000..1584dc6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.product.controller.app.spu.vo; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.AssertTrue; +import java.util.List; + +@Schema(description = "用户 App - 商品 SPU 分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppProductSpuPageReqVO extends PageParam { + + public static final String SORT_FIELD_PRICE = "price"; + public static final String SORT_FIELD_SALES_COUNT = "salesCount"; + public static final String SORT_FIELD_CREATE_TIME = "createTime"; + + @Schema(description = "商品 SPU 编号数组", example = "1,3,5") + private List ids; + + @Schema(description = "分类编号", example = "1") + private Long categoryId; + + @Schema(description = "分类编号数组", example = "1,2,3") + private List categoryIds; + + @Schema(description = "关键字", example = "好看") + private String keyword; + + @Schema(description = "排序字段", example = "price") // 参见 AppProductSpuPageReqVO.SORT_FIELD_XXX 常量 + private String sortField; + + @Schema(description = "排序方式", example = "true") + private Boolean sortAsc; + + @AssertTrue(message = "排序字段不合法") + @JsonIgnore + public boolean isSortFieldValid() { + if (StrUtil.isEmpty(sortField)) { + return true; + } + return StrUtil.equalsAny(sortField, SORT_FIELD_PRICE, SORT_FIELD_SALES_COUNT); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java new file mode 100644 index 0000000..df61090 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.product.controller.app.spu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 商品 SPU Response VO") +@Data +public class AppProductSpuRespVO { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介") + private String introduction; + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long categoryId; + + @Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED) + private String picUrl; + + @Schema(description = "商品轮播图", requiredMode = Schema.RequiredMode.REQUIRED) + private List sliderPicUrls; + + // ========== SKU 相关字段 ========= + + @Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean specType; + + @Schema(description = "商品价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer price; + + @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer marketPrice; + + @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格 + private Integer vipPrice; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Integer stock; + + // ========== 营销相关字段 ========= + + // ========== 统计相关字段 ========= + + @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer salesCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/ProductBrandConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/ProductBrandConvert.java new file mode 100644 index 0000000..e6c72fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/brand/ProductBrandConvert.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.product.convert.brand; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandRespVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandSimpleRespVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandUpdateReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 品牌 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface ProductBrandConvert { + + ProductBrandConvert INSTANCE = Mappers.getMapper(ProductBrandConvert.class); + + ProductBrandDO convert(ProductBrandCreateReqVO bean); + + ProductBrandDO convert(ProductBrandUpdateReqVO bean); + + ProductBrandRespVO convert(ProductBrandDO bean); + + List convertList1(List list); + + List convertList(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java new file mode 100644 index 0000000..7a3a3c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.product.convert.comment; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 商品评价 Convert + * + * @author wangzhs + */ +@Mapper +public interface ProductCommentConvert { + + ProductCommentConvert INSTANCE = Mappers.getMapper(ProductCommentConvert.class); + + default ProductCommentDO convert(ProductCommentCreateReqDTO createReqDTO, + ProductSpuDO spu, ProductSkuDO sku, MemberUserRespDTO user) { + ProductCommentDO comment = BeanUtils.toBean(createReqDTO, ProductCommentDO.class) + .setScores(convertScores(createReqDTO.getDescriptionScores(), createReqDTO.getBenefitScores())); + if (user != null) { + comment.setUserId(user.getId()).setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()); + } + if (spu != null) { + comment.setSpuId(spu.getId()).setSpuName(spu.getName()); + } + if (sku != null) { + comment.setSkuPicUrl(sku.getPicUrl()).setSkuProperties(sku.getProperties()); + } + return comment; + } + + default ProductCommentDO convert(ProductCommentCreateReqVO createReq, ProductSpuDO spu, ProductSkuDO sku) { + ProductCommentDO comment = BeanUtils.toBean(createReq, ProductCommentDO.class) + .setVisible(true).setUserId(0L).setAnonymous(false) + .setScores(convertScores(createReq.getDescriptionScores(), createReq.getBenefitScores())); + if (spu != null) { + comment.setSpuId(spu.getId()).setSpuName(spu.getName()); + } + if (sku != null) { + comment.setSkuPicUrl(sku.getPicUrl()).setSkuProperties(sku.getProperties()); + } + return comment; + } + + default Integer convertScores(Integer descriptionScores, Integer benefitScores) { + // 计算评价最终综合评分 最终星数 = (商品评星 + 服务评星) / 2 + BigDecimal sumScore = new BigDecimal(descriptionScores + benefitScores); + BigDecimal divide = sumScore.divide(BigDecimal.valueOf(2L), 0, RoundingMode.DOWN); + return divide.intValue(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java new file mode 100644 index 0000000..7b419b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.product.convert.favorite; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +@Mapper +public interface ProductFavoriteConvert { + + ProductFavoriteConvert INSTANCE = Mappers.getMapper(ProductFavoriteConvert.class); + + ProductFavoriteDO convert(Long userId, Long spuId); + + @Mapping(target = "id", source = "favorite.id") + @Mapping(target = "spuName", source = "spu.name") + AppFavoriteRespVO convert(ProductSpuDO spu, ProductFavoriteDO favorite); + + default List convertList(List favorites, List spus) { + List resultList = new ArrayList<>(favorites.size()); + Map spuMap = convertMap(spus, ProductSpuDO::getId); + for (ProductFavoriteDO favorite : favorites) { + ProductSpuDO spuDO = spuMap.get(favorite.getSpuId()); + resultList.add(convert(spuDO, favorite)); + } + return resultList; + } + + default PageResult convertPage(PageResult pageResult, List spuList) { + Map spuMap = convertMap(spuList, ProductSpuDO::getId); + List voList = CollectionUtils.convertList(pageResult.getList(), favorite -> { + ProductSpuDO spu = spuMap.get(favorite.getSpuId()); + return convert02(spu, favorite); + }); + return new PageResult<>(voList, pageResult.getTotal()); + } + @Mapping(target = "id", source = "favorite.id") + @Mapping(target = "userId", source = "favorite.userId") + @Mapping(target = "spuId", source = "favorite.spuId") + @Mapping(target = "createTime", source = "favorite.createTime") + ProductFavoriteRespVO convert02(ProductSpuDO spu, ProductFavoriteDO favorite); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java new file mode 100644 index 0000000..492f483 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.product.convert.sku; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 商品 SKU Convert + * + * @author 芋道源码 + */ +@Mapper +public interface ProductSkuConvert { + + ProductSkuConvert INSTANCE = Mappers.getMapper(ProductSkuConvert.class); + + /** + * 获得 SPU 的库存变化 Map + * + * @param items SKU 库存变化 + * @param skus SKU 列表 + * @return SPU 的库存变化 Map + */ + default Map convertSpuStockMap(List items, + List skus) { + Map skuIdAndSpuIdMap = convertMap(skus, ProductSkuDO::getId, ProductSkuDO::getSpuId); // SKU 与 SKU 编号的 Map 关系 + Map spuIdAndStockMap = new HashMap<>(); // SPU 的库存变化 Map 关系 + items.forEach(item -> { + Long spuId = skuIdAndSpuIdMap.get(item.getId()); + if (spuId == null) { + return; + } + Integer stock = spuIdAndStockMap.getOrDefault(spuId, 0) + item.getIncrCount(); + spuIdAndStockMap.put(spuId, stock); + }); + return spuIdAndStockMap; + } + + default String buildPropertyKey(ProductSkuDO bean) { + if (CollUtil.isEmpty(bean.getProperties())) { + return StrUtil.EMPTY; + } + List properties = new ArrayList<>(bean.getProperties()); + properties.sort(Comparator.comparing(ProductSkuDO.Property::getValueId)); + return properties.stream().map(m -> String.valueOf(m.getValueId())).collect(Collectors.joining()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java new file mode 100644 index 0000000..3644342 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.product.convert.spu; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuRespVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; + +/** + * 商品 SPU Convert + * + * @author 芋道源码 + */ +@Mapper +public interface ProductSpuConvert { + + ProductSpuConvert INSTANCE = Mappers.getMapper(ProductSpuConvert.class); + + ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean); + + default ProductSpuRespVO convert(ProductSpuDO spu, List skus) { + ProductSpuRespVO spuVO = BeanUtils.toBean(spu, ProductSpuRespVO.class); + spuVO.setSkus(BeanUtils.toBean(skus, ProductSkuRespVO.class)); + return spuVO; + } + + default List convertForSpuDetailRespListVO(List spus, List skus) { + Map> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId); + return CollectionUtils.convertList(spus, spu -> convert(spu, skuMultiMap.get(spu.getId()))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java new file mode 100644 index 0000000..9775f36 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.brand; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商品品牌 DO + * + * @author 芋道源码 + */ +@TableName("product_brand") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductBrandDO extends BaseDO { + + /** + * 品牌编号 + */ + @TableId + private Long id; + /** + * 品牌名称 + */ + private String name; + /** + * 品牌图片 + */ + private String picUrl; + /** + * 品牌排序 + */ + private Integer sort; + /** + * 品牌描述 + */ + private String description; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + // TODO 芋艿:firstLetter 首字母 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java new file mode 100644 index 0000000..78e35d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商品分类 DO + * + * @author 芋道源码 + */ +@TableName("product_category") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductCategoryDO extends BaseDO { + + /** + * 父分类编号 - 根分类 + */ + public static final Long PARENT_ID_NULL = 0L; + /** + * 限定分类层级 + */ + public static final int CATEGORY_LEVEL = 2; + + /** + * 分类编号 + */ + @TableId + private Long id; + /** + * 父分类编号 + */ + private Long parentId; + /** + * 分类名称 + */ + private String name; + /** + * 移动端分类图 + * + * 建议 180*180 分辨率 + */ + private String picUrl; + /** + * 分类排序 + */ + private Integer sort; + /** + * 开启状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java new file mode 100644 index 0000000..40b04ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.comment; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 商品评论 DO + * + * @author 芋道源码 + */ +@TableName(value = "product_comment", autoResultMap = true) +@KeySequence("product_comment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductCommentDO extends BaseDO { + + /** + * 默认匿名昵称 + */ + public static final String NICKNAME_ANONYMOUS = "匿名用户"; + + /** + * 评论编号,主键自增 + */ + @TableId + private Long id; + + /** + * 评价人的用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 评价人名称 + */ + private String userNickname; + /** + * 评价人头像 + */ + private String userAvatar; + /** + * 是否匿名 + */ + private Boolean anonymous; + + /** + * 交易订单编号 + * + * 关联 TradeOrderDO 的 id 编号 + */ + private Long orderId; + /** + * 交易订单项编号 + * + * 关联 TradeOrderItemDO 的 id 编号 + */ + private Long orderItemId; + + /** + * 商品 SPU 编号 + * + * 关联 {@link ProductSpuDO#getId()} + */ + private Long spuId; + /** + * 商品 SPU 名称 + * + * 关联 {@link ProductSpuDO#getName()} + */ + private String spuName; + /** + * 商品 SKU 编号 + * + * 关联 {@link ProductSkuDO#getId()} + */ + private Long skuId; + /** + * 商品 SKU 图片地址 + * + * 关联 {@link ProductSkuDO#getPicUrl()} + */ + private String skuPicUrl; + /** + * 属性数组,JSON 格式 + * + * 关联 {@link ProductSkuDO#getProperties()} + */ + @TableField(typeHandler = ProductSkuDO.PropertyTypeHandler.class) + private List skuProperties; + + /** + * 是否可见 + * + * true:显示 + * false:隐藏 + */ + private Boolean visible; + /** + * 评分星级 + * + * 1-5 分 + */ + private Integer scores; + /** + * 描述星级 + * + * 1-5 星 + */ + private Integer descriptionScores; + /** + * 服务星级 + * + * 1-5 星 + */ + private Integer benefitScores; + /** + * 评论内容 + */ + private String content; + /** + * 评论图片地址数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List picUrls; + + /** + * 商家是否回复 + */ + private Boolean replyStatus; + /** + * 回复管理员编号 + * 关联 AdminUserDO 的 id 编号 + */ + private Long replyUserId; + /** + * 商家回复内容 + */ + private String replyContent; + /** + * 商家回复时间 + */ + private LocalDateTime replyTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDO.java new file mode 100644 index 0000000..6e00eaa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.favorite; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商品收藏 DO + * + * @author 芋道源码 + */ +@TableName("product_favorite") +@KeySequence("product_favorite_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductFavoriteDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 商品 SPU 编号 + * + * 关联 {@link ProductSpuDO#getId()} + */ + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/history/ProductBrowseHistoryDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/history/ProductBrowseHistoryDO.java new file mode 100644 index 0000000..472574b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/history/ProductBrowseHistoryDO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.history; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商品浏览记录 DO + * + * @author owen + */ +@TableName("product_browse_history") +@KeySequence("product_browse_history_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductBrowseHistoryDO extends BaseDO { + + /** + * 记录编号 + */ + @TableId + private Long id; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户是否删除 + */ + private Boolean userDeleted; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java new file mode 100644 index 0000000..8cc646b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.property; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商品属性项 DO + * + * @author 芋道源码 + */ +@TableName("product_property") +@KeySequence("product_property_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductPropertyDO extends BaseDO { + + /** + * SPU 单规格时,默认属性 id + */ + public static final Long ID_DEFAULT = 0L; + /** + * SPU 单规格时,默认属性名字 + */ + public static final String NAME_DEFAULT = "默认"; + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 名称 + */ + private String name; + /** + * 状态 + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java new file mode 100644 index 0000000..cefa2d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.property; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + + +/** + * 商品属性值 DO + * + * @author 芋道源码 + */ +@TableName("product_property_value") +@KeySequence("product_property_value_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductPropertyValueDO extends BaseDO { + + /** + * SPU 单规格时,默认属性值 id + */ + public static final Long ID_DEFAULT = 0L; + /** + * SPU 单规格时,默认属性值名字 + */ + public static final String NAME_DEFAULT = "默认"; + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 属性项的编号 + * + * 关联 {@link ProductPropertyDO#getId()} + */ + private Long propertyId; + /** + * 名称 + */ + private String name; + /** + * 备注 + * + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java new file mode 100644 index 0000000..dacb02e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.sku; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 商品 SKU DO + * + * @author 芋道源码 + */ +@TableName(value = "product_sku", autoResultMap = true) +@KeySequence("product_sku_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductSkuDO extends BaseDO { + + /** + * 商品 SKU 编号,自增 + */ + @TableId + private Long id; + /** + * SPU 编号 + * + * 关联 {@link ProductSpuDO#getId()} + */ + private Long spuId; + /** + * 属性数组,JSON 格式 + */ + @TableField(typeHandler = PropertyTypeHandler.class) + private List properties; + /** + * 商品价格,单位:分 + */ + private Integer price; + /** + * 市场价,单位:分 + */ + private Integer marketPrice; + /** + * 成本价,单位:分 + */ + private Integer costPrice; + /** + * 商品条码 + */ + private String barCode; + /** + * 图片地址 + */ + private String picUrl; + /** + * 库存 + */ + private Integer stock; + /** + * 商品重量,单位:kg 千克 + */ + private Double weight; + /** + * 商品体积,单位:m^3 平米 + */ + private Double volume; + + /** + * 一级分销的佣金,单位:分 + */ + private Integer firstBrokeragePrice; + /** + * 二级分销的佣金,单位:分 + */ + private Integer secondBrokeragePrice; + + // ========== 营销相关字段 ========= + + // ========== 统计相关字段 ========= + /** + * 商品销量 + */ + private Integer salesCount; + + /** + * 商品属性 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Property { + + /** + * 属性编号 + * 关联 {@link ProductPropertyDO#getId()} + */ + private Long propertyId; + /** + * 属性名字 + * 冗余 {@link ProductPropertyDO#getName()} + * + * 注意:每次属性名字发生变化时,需要更新该冗余 + */ + private String propertyName; + + /** + * 属性值编号 + * 关联 {@link ProductPropertyValueDO#getId()} + */ + private Long valueId; + /** + * 属性值名字 + * 冗余 {@link ProductPropertyValueDO#getName()} + * + * 注意:每次属性值名字发生变化时,需要更新该冗余 + */ + private String valueName; + + } + + // TODO @芋艿:可以找一些新的思路 + public static class PropertyTypeHandler extends AbstractJsonTypeHandler { + + @Override + protected Object parse(String json) { + return JsonUtils.parseArray(json, Property.class); + } + + @Override + protected String toJson(Object obj) { + return JsonUtils.toJsonString(obj); + } + + } + + // TODO 芋艿:integral from y + // TODO 芋艿:pinkPrice from y + // TODO 芋艿:seckillPrice from y + // TODO 芋艿:pinkStock from y + // TODO 芋艿:seckillStock from y + +} + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java new file mode 100644 index 0000000..d2b5195 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.spu; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 商品 SPU DO + * + * @author 芋道源码 + */ +@TableName(value = "product_spu", autoResultMap = true) +@KeySequence("product_spu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductSpuDO extends BaseDO { + + /** + * 商品 SPU 编号,自增 + */ + @TableId + private Long id; + + // ========== 基本信息 ========= + + /** + * 商品名称 + */ + private String name; + /** + * 关键字 + */ + private String keyword; + /** + * 商品简介 + */ + private String introduction; + /** + * 商品详情 + */ + private String description; + + /** + * 商品分类编号 + * + * 关联 {@link ProductCategoryDO#getId()} + */ + private Long categoryId; + /** + * 商品品牌编号 + * + * 关联 {@link ProductBrandDO#getId()} + */ + private Long brandId; + /** + * 商品封面图 + */ + private String picUrl; + /** + * 商品轮播图 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List sliderPicUrls; + + /** + * 排序字段 + */ + private Integer sort; + /** + * 商品状态 + * + * 枚举 {@link ProductSpuStatusEnum} + */ + private Integer status; + + // ========== SKU 相关字段 ========= + + /** + * 规格类型 + * + * false - 单规格 + * true - 多规格 + */ + private Boolean specType; + /** + * 商品价格,单位使用:分 + * + * 基于其对应的 {@link ProductSkuDO#getPrice()} sku单价最低的商品的 + */ + private Integer price; + /** + * 市场价,单位使用:分 + * + * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} sku单价最低的商品的 + */ + private Integer marketPrice; + /** + * 成本价,单位使用:分 + * + * 基于其对应的 {@link ProductSkuDO#getCostPrice()} sku单价最低的商品的 + */ + private Integer costPrice; + /** + * 库存 + * + * 基于其对应的 {@link ProductSkuDO#getStock()} 求和 + */ + private Integer stock; + + // ========== 物流相关字段 ========= + + /** + * 配送方式数组 + * + * 对应 DeliveryTypeEnum 枚举 + */ + @TableField(typeHandler = IntegerListTypeHandler.class) + private List deliveryTypes; + /** + * 物流配置模板编号 + * + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 + */ + private Long deliveryTemplateId; + + // ========== 营销相关字段 ========= + + /** + * 赠送积分 + */ + private Integer giveIntegral; + + // TODO @puhui999:字段估计要改成 brokerageType + /** + * 分销类型 + * + * false - 默认 + * true - 自行设置 + */ + private Boolean subCommissionType; + + // ========== 统计相关字段 ========= + + /** + * 商品销量 + */ + private Integer salesCount; + /** + * 虚拟销量 + */ + private Integer virtualSalesCount; + /** + * 浏览量 + */ + private Integer browseCount; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java new file mode 100644 index 0000000..b2c4bd5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/brand/ProductBrandMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.product.dal.mysql.brand; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface ProductBrandMapper extends BaseMapperX { + + default PageResult selectPage(ProductBrandPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ProductBrandDO::getName, reqVO.getName()) + .eqIfPresent(ProductBrandDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(ProductBrandDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ProductBrandDO::getId)); + } + + + default List selectList(ProductBrandListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(ProductBrandDO::getName, reqVO.getName())); + } + + default ProductBrandDO selectByName(String name) { + return selectOne(ProductBrandDO::getName, name); + } + + default List selectListByStatus(Integer status) { + return selectList(ProductBrandDO::getStatus, status); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/category/ProductCategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/category/ProductCategoryMapper.java new file mode 100644 index 0000000..4c212de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/category/ProductCategoryMapper.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.product.dal.mysql.category; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 商品分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ProductCategoryMapper extends BaseMapperX { + + default List selectList(ProductCategoryListReqVO listReqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(ProductCategoryDO::getName, listReqVO.getName()) + .eqIfPresent(ProductCategoryDO::getParentId, listReqVO.getParentId()) + .inIfPresent(ProductCategoryDO::getId, listReqVO.getParentIds()) + .eqIfPresent(ProductCategoryDO::getStatus, listReqVO.getStatus()) + .orderByDesc(ProductCategoryDO::getId)); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(ProductCategoryDO::getParentId, parentId); + } + + default List selectListByStatus(Integer status) { + return selectList(ProductCategoryDO::getStatus, status); + } + + default List selectListByIdAndStatus(Collection ids, Integer status) { + return selectList(new LambdaQueryWrapperX() + .in(ProductCategoryDO::getId, ids) + .eq(ProductCategoryDO::getStatus, status)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java new file mode 100644 index 0000000..47421d3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.product.dal.mysql.comment; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ProductCommentMapper extends BaseMapperX { + + default PageResult selectPage(ProductCommentPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ProductCommentDO::getUserNickname, reqVO.getUserNickname()) + .eqIfPresent(ProductCommentDO::getOrderId, reqVO.getOrderId()) + .eqIfPresent(ProductCommentDO::getSpuId, reqVO.getSpuId()) + .eqIfPresent(ProductCommentDO::getScores, reqVO.getScores()) + .eqIfPresent(ProductCommentDO::getReplyStatus, reqVO.getReplyStatus()) + .betweenIfPresent(ProductCommentDO::getCreateTime, reqVO.getCreateTime()) + .likeIfPresent(ProductCommentDO::getSpuName, reqVO.getSpuName()) + .orderByDesc(ProductCommentDO::getId)); + } + + static void appendTabQuery(LambdaQueryWrapperX queryWrapper, Integer type) { + // 构建好评查询语句:好评计算 总评 >= 4 + if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) { + queryWrapper.ge(ProductCommentDO::getScores, 4); + } + // 构建中评查询语句:中评计算 总评 >= 3 且 总评 < 4 + if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) { + queryWrapper.ge(ProductCommentDO::getScores, 3); + queryWrapper.lt(ProductCommentDO::getScores, 4); + } + // 构建差评查询语句:差评计算 总评 < 3 + if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) { + queryWrapper.lt(ProductCommentDO::getScores, 3); + } + } + + default PageResult selectPage(AppCommentPageReqVO reqVO, Boolean visible) { + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + .eqIfPresent(ProductCommentDO::getSpuId, reqVO.getSpuId()) + .eqIfPresent(ProductCommentDO::getVisible, visible); + // 构建评价查询语句 + appendTabQuery(queryWrapper, reqVO.getType()); + // 按评价时间排序最新的显示在前面 + queryWrapper.orderByDesc(ProductCommentDO::getCreateTime); + return selectPage(reqVO, queryWrapper); + } + + default ProductCommentDO selectByUserIdAndOrderItemId(Long userId, Long orderItemId) { + return selectOne(new LambdaQueryWrapperX() + .eq(ProductCommentDO::getUserId, userId) + .eq(ProductCommentDO::getOrderItemId, orderItemId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java new file mode 100644 index 0000000..a681d42 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.product.dal.mysql.favorite; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ProductFavoriteMapper extends BaseMapperX { + + default ProductFavoriteDO selectByUserIdAndSpuId(Long userId, Long spuId) { + return selectOne(ProductFavoriteDO::getUserId, userId, + ProductFavoriteDO::getSpuId, spuId); + } + + default PageResult selectPageByUserAndType(Long userId, AppFavoritePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapper() + .eq(ProductFavoriteDO::getUserId, userId) + .orderByDesc(ProductFavoriteDO::getId)); + } + + default PageResult selectPageByUserId(ProductFavoritePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProductFavoriteDO::getUserId, reqVO.getUserId()) + .orderByDesc(ProductFavoriteDO::getId)); + } + + default Long selectCountByUserId(Long userId) { + return selectCount(ProductFavoriteDO::getUserId, userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/history/ProductBrowseHistoryMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/history/ProductBrowseHistoryMapper.java new file mode 100644 index 0000000..124357c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/history/ProductBrowseHistoryMapper.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.product.dal.mysql.history; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; + +/** + * 商品浏览记录 Mapper + * + * @author owen + */ +@Mapper +public interface ProductBrowseHistoryMapper extends BaseMapperX { + + default ProductBrowseHistoryDO selectByUserIdAndSpuId(Long userId, Long spuId) { + return selectOne(new LambdaQueryWrapperX() + .eq(ProductBrowseHistoryDO::getUserId, userId) + .eq(ProductBrowseHistoryDO::getSpuId, spuId)); + } + + default PageResult selectPage(ProductBrowseHistoryPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProductBrowseHistoryDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ProductBrowseHistoryDO::getUserDeleted, reqVO.getUserDeleted()) + .eqIfPresent(ProductBrowseHistoryDO::getSpuId, reqVO.getSpuId()) + .betweenIfPresent(ProductBrowseHistoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ProductBrowseHistoryDO::getId)); + } + + default void updateUserDeletedByUserId(Long userId, Collection spuIds, Boolean userDeleted) { + update(new LambdaUpdateWrapper() + .eq(ProductBrowseHistoryDO::getUserId, userId) + .in(CollUtil.isNotEmpty(spuIds), ProductBrowseHistoryDO::getSpuId, spuIds) + .set(ProductBrowseHistoryDO::getUserDeleted, userDeleted)); + } + + default Page selectPageByUserIdOrderByCreateTimeAsc(Long userId, Integer pageNo, Integer pageSize) { + Page page = Page.of(pageNo, pageSize); + return selectPage(page, new LambdaQueryWrapperX() + .eqIfPresent(ProductBrowseHistoryDO::getUserId, userId) + .orderByAsc(ProductBrowseHistoryDO::getCreateTime)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java new file mode 100644 index 0000000..8a55eaf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.dal.mysql.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ProductPropertyMapper extends BaseMapperX { + + default PageResult selectPage(ProductPropertyPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ProductPropertyDO::getName, reqVO.getName()) + .betweenIfPresent(ProductPropertyDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ProductPropertyDO::getId)); + } + + default ProductPropertyDO selectByName(String name) { + return selectOne(ProductPropertyDO::getName, name); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java new file mode 100644 index 0000000..402df51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.product.dal.mysql.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface ProductPropertyValueMapper extends BaseMapperX { + + default List selectListByPropertyId(Collection propertyIds) { + return selectList(new LambdaQueryWrapperX() + .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); + } + + default ProductPropertyValueDO selectByName(Long propertyId, String name) { + return selectOne(new LambdaQueryWrapperX() + .eq(ProductPropertyValueDO::getPropertyId, propertyId) + .eq(ProductPropertyValueDO::getName, name)); + } + + default void deleteByPropertyId(Long propertyId) { + delete(new LambdaQueryWrapperX() + .eq(ProductPropertyValueDO::getPropertyId, propertyId)); + } + + default PageResult selectPage(ProductPropertyValuePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId()) + .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName()) + .orderByDesc(ProductPropertyValueDO::getId)); + } + + default Integer selectCountByPropertyId(Long propertyId) { + return selectCount(ProductPropertyValueDO::getPropertyId, propertyId).intValue(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java new file mode 100644 index 0000000..82bfc87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.product.dal.mysql.sku; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface ProductSkuMapper extends BaseMapperX { + + default List selectListBySpuId(Long spuId) { + return selectList(ProductSkuDO::getSpuId, spuId); + } + + default List selectListBySpuId(Collection spuIds) { + return selectList(ProductSkuDO::getSpuId, spuIds); + } + + default void deleteBySpuId(Long spuId) { + delete(new LambdaQueryWrapperX().eq(ProductSkuDO::getSpuId, spuId)); + } + + /** + * 更新 SKU 库存(增加) + * + * @param id 编号 + * @param incrCount 增加库存(正数) + */ + default void updateStockIncr(Long id, Integer incrCount) { + Assert.isTrue(incrCount > 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" stock = stock + " + incrCount) + .eq(ProductSkuDO::getId, id); + update(null, lambdaUpdateWrapper); + } + + /** + * 更新 SKU 库存(减少) + * + * @param id 编号 + * @param incrCount 减少库存(负数) + * @return 更新条数 + */ + default int updateStockDecr(Long id, Integer incrCount) { + Assert.isTrue(incrCount < 0); + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + .setSql(" stock = stock + " + incrCount) // 负数,所以使用 + 号 + .eq(ProductSkuDO::getId, id) + .ge(ProductSkuDO::getStock, -incrCount); // cas 逻辑 + return update(null, updateWrapper); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java new file mode 100644 index 0000000..cf8ae64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.product.dal.mysql.spu; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.enums.ProductConstants; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Objects; +import java.util.Set; + +@Mapper +public interface ProductSpuMapper extends BaseMapperX { + + /** + * 获取商品 SPU 分页列表数据 + * + * @param reqVO 分页请求参数 + * @return 商品 SPU 分页列表数据 + */ + default PageResult selectPage(ProductSpuPageReqVO reqVO) { + Integer tabType = reqVO.getTabType(); + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + .likeIfPresent(ProductSpuDO::getName, reqVO.getName()) + .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId()) + .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ProductSpuDO::getSort) + .orderByDesc(ProductSpuDO::getId); + appendTabQuery(tabType, queryWrapper); + return selectPage(reqVO, queryWrapper); + } + + /** + * 查询触发警戒库存的 SPU 数量 + * + * @return 触发警戒库存的 SPU 数量 + */ + default Long selectCount() { + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX<>(); + // 库存小于等于警戒库存 + queryWrapper.le(ProductSpuDO::getStock, ProductConstants.ALERT_STOCK) + // 如果库存触发警戒库存且状态为回收站的话则不计入触发警戒库存的个数 + .notIn(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()); + return selectCount(queryWrapper); + } + + /** + * 获得商品 SPU 分页,提供给用户 App 使用 + */ + default PageResult selectPage(AppProductSpuPageReqVO pageReqVO, Set categoryIds) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + // 关键字匹配,目前只匹配商品名 + .likeIfPresent(ProductSpuDO::getName, pageReqVO.getKeyword()) + // 分类 + .inIfPresent(ProductSpuDO::getCategoryId, categoryIds); + // 上架状态 且有库存 + query.eq(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()); + + // 排序逻辑 + if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { + query.last(String.format(" ORDER BY (sales_count + virtual_sales_count) %s, sort DESC, id DESC", + pageReqVO.getSortAsc() ? "ASC" : "DESC")); + } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) { + query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getPrice) + .orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); + } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_CREATE_TIME)) { + query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getCreateTime) + .orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); + } else { + query.orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); + } + return selectPage(pageReqVO, query); + } + + /** + * 更新商品 SPU 库存 + * + * @param id 商品 SPU 编号 + * @param incrCount 增加的库存数量 + */ + default void updateStock(Long id, Integer incrCount) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + // 负数,所以使用 + 号 + .setSql(" stock = stock +" + incrCount) + .eq(ProductSpuDO::getId, id); + update(null, updateWrapper); + } + + /** + * 添加后台 Tab 选项的查询条件 + * + * @param tabType 标签类型 + * @param query 查询条件 + */ + static void appendTabQuery(Integer tabType, LambdaQueryWrapperX query) { + // 出售中商品 + if (ObjectUtil.equals(ProductSpuPageReqVO.FOR_SALE, tabType)) { + query.eqIfPresent(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()); + } + // 仓储中商品 + if (ObjectUtil.equals(ProductSpuPageReqVO.IN_WAREHOUSE, tabType)) { + query.eqIfPresent(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus()); + } + // 已售空商品 + if (ObjectUtil.equals(ProductSpuPageReqVO.SOLD_OUT, tabType)) { + query.eqIfPresent(ProductSpuDO::getStock, 0); + } + // 警戒库存 + if (ObjectUtil.equals(ProductSpuPageReqVO.ALERT_STOCK, tabType)) { + query.le(ProductSpuDO::getStock, ProductConstants.ALERT_STOCK) + // 如果库存触发警戒库存且状态为回收站的话则不在警戒库存列表展示 + .notIn(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()); + } + // 回收站 + if (ObjectUtil.equals(ProductSpuPageReqVO.RECYCLE_BIN, tabType)) { + query.eqIfPresent(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()); + } + } + + /** + * 更新商品 SPU 浏览量 + * + * @param id 商品 SPU 编号 + * @param incrCount 增加的数量 + */ + default void updateBrowseCount(Long id, int incrCount) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() + .setSql(" browse_count = browse_count +" + incrCount) + .eq(ProductSpuDO::getId, id); + update(null, updateWrapper); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/package-info.java new file mode 100644 index 0000000..d2e1c93 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 product 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.product.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/config/ProductWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/config/ProductWebConfiguration.java new file mode 100644 index 0000000..9d1bf7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/config/ProductWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * product 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class ProductWebConfiguration { + + /** + * product 模块的 API 分组 + */ + @Bean + public GroupedOpenApi productGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("product"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/package-info.java new file mode 100644 index 0000000..f4adb2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * product 模块的 web 配置 + */ +package cn.iocoder.yudao.module.product.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/package-info.java new file mode 100644 index 0000000..e329429 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/package-info.java @@ -0,0 +1,8 @@ +/** + * product 模块,主要实现交易相关功能 + * 例如:订单、退款、购物车等功能。 + * + * 1. Controller URL:以 /product/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 product_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.product; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandService.java new file mode 100644 index 0000000..aa401ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandService.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.product.service.brand; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.*; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 商品品牌 Service 接口 + * + * @author 芋道源码 + */ +public interface ProductBrandService { + + /** + * 创建品牌 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBrand(@Valid ProductBrandCreateReqVO createReqVO); + + /** + * 更新品牌 + * + * @param updateReqVO 更新信息 + */ + void updateBrand(@Valid ProductBrandUpdateReqVO updateReqVO); + + /** + * 删除品牌 + * + * @param id 编号 + */ + void deleteBrand(Long id); + + /** + * 获得品牌 + * + * @param id 编号 + * @return 品牌 + */ + ProductBrandDO getBrand(Long id); + + /** + * 获得品牌列表 + * + * @param ids 编号 + * @return 品牌列表 + */ + List getBrandList(Collection ids); + + /** + * 获得品牌列表 + * + * @param listReqVO 请求参数 + * @return 品牌列表 + */ + List getBrandList(ProductBrandListReqVO listReqVO); + + /** + * 验证选择的商品分类是否合法 + * + * @param id 分类编号 + */ + void validateProductBrand(Long id); + + /** + * 获得品牌分页 + * + * @param pageReqVO 分页查询 + * @return 品牌分页 + */ + PageResult getBrandPage(ProductBrandPageReqVO pageReqVO); + + /** + * 获取指定状态的品牌列表 + * + * @param status 状态 + * @return 返回品牌列表 + */ + List getBrandListByStatus(Integer status); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImpl.java new file mode 100644 index 0000000..b97123f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImpl.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.product.service.brand; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandUpdateReqVO; +import cn.iocoder.yudao.module.product.convert.brand.ProductBrandConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import cn.iocoder.yudao.module.product.dal.mysql.brand.ProductBrandMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 品牌 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductBrandServiceImpl implements ProductBrandService { + + @Resource + private ProductBrandMapper brandMapper; + + @Override + public Long createBrand(ProductBrandCreateReqVO createReqVO) { + // 校验 + validateBrandNameUnique(null, createReqVO.getName()); + + // 插入 + ProductBrandDO brand = ProductBrandConvert.INSTANCE.convert(createReqVO); + brandMapper.insert(brand); + // 返回 + return brand.getId(); + } + + @Override + public void updateBrand(ProductBrandUpdateReqVO updateReqVO) { + // 校验存在 + validateBrandExists(updateReqVO.getId()); + validateBrandNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 更新 + ProductBrandDO updateObj = ProductBrandConvert.INSTANCE.convert(updateReqVO); + brandMapper.updateById(updateObj); + } + + @Override + public void deleteBrand(Long id) { + // 校验存在 + validateBrandExists(id); + // 删除 + brandMapper.deleteById(id); + } + + private void validateBrandExists(Long id) { + if (brandMapper.selectById(id) == null) { + throw exception(BRAND_NOT_EXISTS); + } + } + + @VisibleForTesting + public void validateBrandNameUnique(Long id, String name) { + ProductBrandDO brand = brandMapper.selectByName(name); + if (brand == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(BRAND_NAME_EXISTS); + } + if (!brand.getId().equals(id)) { + throw exception(BRAND_NAME_EXISTS); + } + } + + @Override + public ProductBrandDO getBrand(Long id) { + return brandMapper.selectById(id); + } + + @Override + public List getBrandList(Collection ids) { + return brandMapper.selectBatchIds(ids); + } + + @Override + public List getBrandList(ProductBrandListReqVO listReqVO) { + return brandMapper.selectList(listReqVO); + } + + @Override + public void validateProductBrand(Long id) { + ProductBrandDO brand = brandMapper.selectById(id); + if (brand == null) { + throw exception(BRAND_NOT_EXISTS); + } + if (brand.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(BRAND_DISABLED); + } + } + + @Override + public PageResult getBrandPage(ProductBrandPageReqVO pageReqVO) { + return brandMapper.selectPage(pageReqVO); + } + + @Override + public List getBrandListByStatus(Integer status) { + return brandMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryService.java new file mode 100644 index 0000000..52959a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryService.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.product.service.category; + +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategorySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 商品分类 Service 接口 + * + * @author 芋道源码 + */ +public interface ProductCategoryService { + + /** + * 创建商品分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCategory(@Valid ProductCategorySaveReqVO createReqVO); + + /** + * 更新商品分类 + * + * @param updateReqVO 更新信息 + */ + void updateCategory(@Valid ProductCategorySaveReqVO updateReqVO); + + /** + * 删除商品分类 + * + * @param id 编号 + */ + void deleteCategory(Long id); + + /** + * 获得商品分类 + * + * @param id 编号 + * @return 商品分类 + */ + ProductCategoryDO getCategory(Long id); + + /** + * 校验商品分类 + * + * @param id 分类编号 + */ + void validateCategory(Long id); + + /** + * 获得商品分类的层级 + * + * @param id 编号 + * @return 商品分类的层级 + */ + Integer getCategoryLevel(Long id); + + /** + * 获得商品分类列表 + * + * @param listReqVO 查询条件 + * @return 商品分类列表 + */ + List getCategoryList(ProductCategoryListReqVO listReqVO); + + /** + * 获得开启状态的商品分类列表 + * + * @return 商品分类列表 + */ + List getEnableCategoryList(); + + /** + * 获得开启状态的商品分类列表,指定编号 + * + * @param ids 商品分类编号数组 + * @return 商品分类列表 + */ + List getEnableCategoryList(List ids); + + /** + * 校验商品分类是否有效。如下情况,视为无效: + * 1. 商品分类编号不存在 + * 2. 商品分类被禁用 + * + * @param ids 商品分类编号数组 + */ + void validateCategoryList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java new file mode 100644 index 0000000..1dbf62f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.module.product.service.category; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategorySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.dal.mysql.category.ProductCategoryMapper; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.PARENT_ID_NULL; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 商品分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductCategoryServiceImpl implements ProductCategoryService { + + @Resource + private ProductCategoryMapper productCategoryMapper; + @Resource + @Lazy // 循环依赖,避免报错 + private ProductSpuService productSpuService; + + @Override + public Long createCategory(ProductCategorySaveReqVO createReqVO) { + // 校验父分类存在 + validateParentProductCategory(createReqVO.getParentId()); + + // 插入 + ProductCategoryDO category = BeanUtils.toBean(createReqVO, ProductCategoryDO.class); + productCategoryMapper.insert(category); + // 返回 + return category.getId(); + } + + @Override + public void updateCategory(ProductCategorySaveReqVO updateReqVO) { + // 校验分类是否存在 + validateProductCategoryExists(updateReqVO.getId()); + // 校验父分类存在 + validateParentProductCategory(updateReqVO.getParentId()); + + // 更新 + ProductCategoryDO updateObj = BeanUtils.toBean(updateReqVO, ProductCategoryDO.class); + productCategoryMapper.updateById(updateObj); + } + + @Override + public void deleteCategory(Long id) { + // 校验分类是否存在 + validateProductCategoryExists(id); + // 校验是否还有子分类 + if (productCategoryMapper.selectCountByParentId(id) > 0) { + throw exception(CATEGORY_EXISTS_CHILDREN); + } + // 校验分类是否绑定了 SPU + Long spuCount = productSpuService.getSpuCountByCategoryId(id); + if (spuCount > 0) { + throw exception(CATEGORY_HAVE_BIND_SPU); + } + // 删除 + productCategoryMapper.deleteById(id); + } + + private void validateParentProductCategory(Long id) { + // 如果是根分类,无需验证 + if (Objects.equals(id, PARENT_ID_NULL)) { + return; + } + // 父分类不存在 + ProductCategoryDO category = productCategoryMapper.selectById(id); + if (category == null) { + throw exception(CATEGORY_PARENT_NOT_EXISTS); + } + // 父分类不能是二级分类 + if (!Objects.equals(category.getParentId(), PARENT_ID_NULL)) { + throw exception(CATEGORY_PARENT_NOT_FIRST_LEVEL); + } + } + + private void validateProductCategoryExists(Long id) { + ProductCategoryDO category = productCategoryMapper.selectById(id); + if (category == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + } + + @Override + public void validateCategoryList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得商品分类信息 + List list = productCategoryMapper.selectBatchIds(ids); + Map categoryMap = CollectionUtils.convertMap(list, ProductCategoryDO::getId); + // 校验 + ids.forEach(id -> { + ProductCategoryDO category = categoryMap.get(id); + if (category == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(category.getStatus())) { + throw exception(CATEGORY_DISABLED, category.getName()); + } + }); + } + + @Override + public ProductCategoryDO getCategory(Long id) { + return productCategoryMapper.selectById(id); + } + + @Override + public void validateCategory(Long id) { + ProductCategoryDO category = productCategoryMapper.selectById(id); + if (category == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + if (Objects.equals(category.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + throw exception(CATEGORY_DISABLED, category.getName()); + } + } + + @Override + public Integer getCategoryLevel(Long id) { + if (Objects.equals(id, PARENT_ID_NULL)) { + return 0; + } + int level = 1; + // for 的原因,是因为避免脏数据,导致可能的死循环。一般不会超过 100 层哈 + for (int i = 0; i < Byte.MAX_VALUE; i++) { + // 如果没有父节点,break 结束 + ProductCategoryDO category = productCategoryMapper.selectById(id); + if (category == null + || Objects.equals(category.getParentId(), PARENT_ID_NULL)) { + break; + } + // 继续递归父节点 + level++; + id = category.getParentId(); + } + return level; + } + + @Override + public List getCategoryList(ProductCategoryListReqVO listReqVO) { + return productCategoryMapper.selectList(listReqVO); + } + + @Override + public List getEnableCategoryList() { + return productCategoryMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + } + + @Override + public List getEnableCategoryList(List ids) { + return productCategoryMapper.selectListByIdAndStatus(ids, CommonStatusEnum.ENABLE.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java new file mode 100644 index 0000000..b54e219 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.product.service.comment; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 商品评论 Service 接口 + * + * @author wangzhs + */ +@Service +@Validated +public interface ProductCommentService { + + /** + * 创建商品评论 + * 后台管理员创建评论使用 + * + * @param createReqVO 商品评价创建 Request VO 对象 + */ + void createComment(ProductCommentCreateReqVO createReqVO); + + /** + * 创建评论 + * 创建商品评论 APP 端创建商品评论使用 + * + * @param createReqDTO 创建请求 dto + * @return 返回评论 id + */ + Long createComment(ProductCommentCreateReqDTO createReqDTO); + + /** + * 修改评论是否可见 + * + * @param updateReqVO 修改评论可见 + */ + void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO); + + /** + * 商家回复 + * + * @param replyVO 商家回复 + * @param userId 管理后台商家登陆人 ID + */ + void replyComment(ProductCommentReplyReqVO replyVO, Long userId); + + /** + * 【管理员】获得商品评价分页 + * + * @param pageReqVO 分页查询 + * @return 商品评价分页 + */ + PageResult getCommentPage(ProductCommentPageReqVO pageReqVO); + + /** + * 【会员】获得商品评价分页 + * + * @param pageVO 分页查询 + * @param visible 是否可见 + * @return 商品评价分页 + */ + PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java new file mode 100644 index 0000000..3f65b91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.product.service.comment; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 商品评论 Service 实现类 + * + * @author wangzhs + */ +@Service +@Validated +public class ProductCommentServiceImpl implements ProductCommentService { + + @Resource + private ProductCommentMapper productCommentMapper; + + @Resource + private ProductSpuService productSpuService; + + @Resource + @Lazy + private ProductSkuService productSkuService; + + @Resource + private MemberUserApi memberUserApi; + + @Override + public void createComment(ProductCommentCreateReqVO createReqVO) { + // 校验 SKU + ProductSkuDO sku = validateSku(createReqVO.getSkuId()); + // 校验 SPU + ProductSpuDO spu = validateSpu(sku.getSpuId()); + + // 创建评论 + ProductCommentDO comment = ProductCommentConvert.INSTANCE.convert(createReqVO, spu, sku); + productCommentMapper.insert(comment); + } + + @Override + public Long createComment(ProductCommentCreateReqDTO createReqDTO) { + // 校验 SKU + ProductSkuDO sku = validateSku(createReqDTO.getSkuId()); + // 校验 SPU + ProductSpuDO spu = validateSpu(sku.getSpuId()); + // 校验评论 + validateCommentExists(createReqDTO.getUserId(), createReqDTO.getOrderId()); + // 获取用户详细信息 + MemberUserRespDTO user = memberUserApi.getUser(createReqDTO.getUserId()); + + // 创建评论 + ProductCommentDO comment = ProductCommentConvert.INSTANCE.convert(createReqDTO, spu, sku, user); + productCommentMapper.insert(comment); + return comment.getId(); + } + + /** + * 判断当前订单的当前商品用户是否评价过 + * + * @param userId 用户编号 + * @param orderItemId 订单项编号 + */ + private void validateCommentExists(Long userId, Long orderItemId) { + ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemId(userId, orderItemId); + if (exist != null) { + throw exception(COMMENT_ORDER_EXISTS); + } + } + + private ProductSkuDO validateSku(Long skuId) { + ProductSkuDO sku = productSkuService.getSku(skuId); + if (sku == null) { + throw exception(SKU_NOT_EXISTS); + } + return sku; + } + + private ProductSpuDO validateSpu(Long spuId) { + ProductSpuDO spu = productSpuService.getSpu(spuId); + if (null == spu) { + throw exception(SPU_NOT_EXISTS); + } + return spu; + } + + @Override + public void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO) { + // 校验评论是否存在 + validateCommentExists(updateReqVO.getId()); + + // 更新可见状态 + productCommentMapper.updateById(new ProductCommentDO().setId(updateReqVO.getId()) + .setVisible(updateReqVO.getVisible())); + } + + @Override + public void replyComment(ProductCommentReplyReqVO replyVO, Long userId) { + // 校验评论是否存在 + validateCommentExists(replyVO.getId()); + // 回复评论 + productCommentMapper.updateById(new ProductCommentDO().setId(replyVO.getId()) + .setReplyTime(LocalDateTime.now()).setReplyUserId(userId) + .setReplyStatus(Boolean.TRUE).setReplyContent(replyVO.getReplyContent())); + } + + private ProductCommentDO validateCommentExists(Long id) { + ProductCommentDO productComment = productCommentMapper.selectById(id); + if (productComment == null) { + throw exception(COMMENT_NOT_EXISTS); + } + return productComment; + } + + @Override + public PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) { + return productCommentMapper.selectPage(pageVO, visible); + } + + @Override + public PageResult getCommentPage(ProductCommentPageReqVO pageReqVO) { + return productCommentMapper.selectPage(pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java new file mode 100644 index 0000000..3dd3bd5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.product.service.favorite; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; + +import javax.validation.Valid; + +/** + * 商品收藏 Service 接口 + * + * @author jason + */ +public interface ProductFavoriteService { + + /** + * 创建商品收藏 + * + * @param userId 用户编号 + * @param spuId SPU 编号 + */ + Long createFavorite(Long userId, Long spuId); + + /** + * 取消商品收藏 + * + * @param userId 用户编号 + * @param spuId SPU 编号 + */ + void deleteFavorite(Long userId, Long spuId); + + /** + * 分页查询用户收藏列表 + * + * @param userId 用户编号 + * @param reqVO 请求 vo + */ + PageResult getFavoritePage(Long userId, @Valid AppFavoritePageReqVO reqVO); + + /** + * 分页查询用户收藏列表 + * + * @param reqVO 请求 vo + */ + PageResult getFavoritePage(@Valid ProductFavoritePageReqVO reqVO); + + /** + * 获取收藏过商品 + * + * @param userId 用户编号 + * @param spuId SPU 编号 + */ + ProductFavoriteDO getFavorite(Long userId, Long spuId); + + /** + * 获取用户收藏数量 + * + * @param userId 用户编号 + * @return 数量 + */ + Long getFavoriteCount(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java new file mode 100644 index 0000000..927d030 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.product.service.favorite; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; +import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.mysql.favorite.ProductFavoriteMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.FAVORITE_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.FAVORITE_NOT_EXISTS; + +/** + * 商品收藏 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class ProductFavoriteServiceImpl implements ProductFavoriteService { + + @Resource + private ProductFavoriteMapper productFavoriteMapper; + + @Override + public Long createFavorite(Long userId, Long spuId) { + ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); + if (favorite != null) { + throw exception(FAVORITE_EXISTS); + } + + ProductFavoriteDO entity = ProductFavoriteConvert.INSTANCE.convert(userId, spuId); + productFavoriteMapper.insert(entity); + return entity.getId(); + } + + @Override + public void deleteFavorite(Long userId, Long spuId) { + ProductFavoriteDO favorite = productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); + if (favorite == null) { + throw exception(FAVORITE_NOT_EXISTS); + } + + productFavoriteMapper.deleteById(favorite.getId()); + } + + @Override + public PageResult getFavoritePage(Long userId, @Valid AppFavoritePageReqVO reqVO) { + return productFavoriteMapper.selectPageByUserAndType(userId, reqVO); + } + + @Override + public PageResult getFavoritePage(@Valid ProductFavoritePageReqVO reqVO) { + return productFavoriteMapper.selectPageByUserId(reqVO); + } + + @Override + public ProductFavoriteDO getFavorite(Long userId, Long spuId) { + return productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); + } + + @Override + public Long getFavoriteCount(Long userId) { + return productFavoriteMapper.selectCountByUserId(userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryService.java new file mode 100644 index 0000000..10f3a71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryService.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.product.service.history; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import org.springframework.scheduling.annotation.Async; + +import java.util.Collection; + +/** + * 商品浏览记录 Service 接口 + * + * @author owen + */ +public interface ProductBrowseHistoryService { + + /** + * 创建商品浏览记录 + * + * @param userId 用户编号 + * @param spuId SPU 编号 + */ + @Async + void createBrowseHistory(Long userId, Long spuId); + + /** + * 隐藏用户商品浏览记录 + * + * @param userId 用户编号 + * @param spuId SPU 编号 + */ + void hideUserBrowseHistory(Long userId, Collection spuId); + + /** + * 获得商品浏览记录分页 + * + * @param pageReqVO 分页查询 + * @return 商品浏览记录分页 + */ + PageResult getBrowseHistoryPage(ProductBrowseHistoryPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryServiceImpl.java new file mode 100644 index 0000000..8645be7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/history/ProductBrowseHistoryServiceImpl.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.product.service.history; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import cn.iocoder.yudao.module.product.dal.mysql.history.ProductBrowseHistoryMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * 商品浏览记录 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class ProductBrowseHistoryServiceImpl implements ProductBrowseHistoryService { + + private static final int USER_STORE_MAXIMUM = 100; + + @Resource + private ProductBrowseHistoryMapper browseHistoryMapper; + + @Override + public void createBrowseHistory(Long userId, Long spuId) { + // 用户未登录时不记录 + if (userId == null) { + return; + } + + // 情况一:同一个商品,只保留最新的一条记录 + ProductBrowseHistoryDO history = browseHistoryMapper.selectByUserIdAndSpuId(userId, spuId); + if (history != null) { + browseHistoryMapper.deleteById(history); + } else { + // 情况二:限制每个用户的浏览记录的条数(只查一条最早地记录、记录总数) + // TODO @疯狂:这里最好先查询一次数量。如果发现超过了,再删除;主要考虑,可能有部分不超过,提前就多了一次 sql 查询了 + Page pageResult = browseHistoryMapper.selectPageByUserIdOrderByCreateTimeAsc(userId, 1, 1); + if (pageResult.getTotal() >= USER_STORE_MAXIMUM) { + browseHistoryMapper.deleteById(CollUtil.getFirst(pageResult.getRecords())); + } + } + + // 插入 + ProductBrowseHistoryDO browseHistory = new ProductBrowseHistoryDO() + .setUserId(userId) + .setSpuId(spuId); + browseHistoryMapper.insert(browseHistory); + } + + @Override + public void hideUserBrowseHistory(Long userId, Collection spuIds) { + browseHistoryMapper.updateUserDeletedByUserId(userId, spuIds, true); + } + + @Override + public PageResult getBrowseHistoryPage(ProductBrowseHistoryPageReqVO pageReqVO) { + return browseHistoryMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java new file mode 100644 index 0000000..278be0f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 商品属性项 Service 接口 + * + * @author 芋道源码 + */ +public interface ProductPropertyService { + + /** + * 创建属性项 + * 注意,如果已经存在该属性项,直接返回它的编号即可 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProperty(@Valid ProductPropertySaveReqVO createReqVO); + + /** + * 更新属性项 + * + * @param updateReqVO 更新信息 + */ + void updateProperty(@Valid ProductPropertySaveReqVO updateReqVO); + + /** + * 删除属性项 + * + * @param id 编号 + */ + void deleteProperty(Long id); + + /** + * 获取属性名称分页 + * + * @param pageReqVO 分页条件 + * @return 属性项分页 + */ + PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO); + + /** + * 获得指定编号的属性项 + * + * @param id 编号 + * @return 属性项 + */ + ProductPropertyDO getProperty(Long id); + + /** + * 根据属性项的编号的集合,获得对应的属性项数组 + * + * @param ids 属性项的编号的集合 + * @return 属性项数组 + */ + List getPropertyList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java new file mode 100644 index 0000000..8843640 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyMapper; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 商品属性项 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductPropertyServiceImpl implements ProductPropertyService { + + @Resource + private ProductPropertyMapper productPropertyMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖问题 + private ProductPropertyValueService productPropertyValueService; + + @Resource + private ProductSkuService productSkuService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createProperty(ProductPropertySaveReqVO createReqVO) { + // 如果已经添加过该属性项,直接返回 + ProductPropertyDO dbProperty = productPropertyMapper.selectByName(createReqVO.getName()); + if (dbProperty != null) { + return dbProperty.getId(); + } + + // 插入 + ProductPropertyDO property = BeanUtils.toBean(createReqVO, ProductPropertyDO.class); + productPropertyMapper.insert(property); + // 返回 + return property.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateProperty(ProductPropertySaveReqVO updateReqVO) { + validatePropertyExists(updateReqVO.getId()); + // 校验名字重复 + ProductPropertyDO property = productPropertyMapper.selectByName(updateReqVO.getName()); + if (property != null && + ObjUtil.notEqual(property.getId(), updateReqVO.getId())) { + throw exception(PROPERTY_EXISTS); + } + + // 更新 + ProductPropertyDO updateObj = BeanUtils.toBean(updateReqVO, ProductPropertyDO.class); + productPropertyMapper.updateById(updateObj); + // 更新 sku 相关属性 + productSkuService.updateSkuProperty(updateObj.getId(), updateObj.getName()); + } + + @Override + public void deleteProperty(Long id) { + // 校验存在 + validatePropertyExists(id); + // 校验其下是否有规格值 + if (productPropertyValueService.getPropertyValueCountByPropertyId(id) > 0) { + throw exception(PROPERTY_DELETE_FAIL_VALUE_EXISTS); + } + + // 删除 + productPropertyMapper.deleteById(id); + // 同步删除属性值 + productPropertyValueService.deletePropertyValueByPropertyId(id); + } + + private void validatePropertyExists(Long id) { + if (productPropertyMapper.selectById(id) == null) { + throw exception(PROPERTY_NOT_EXISTS); + } + } + + @Override + public PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO) { + return productPropertyMapper.selectPage(pageReqVO); + } + + @Override + public ProductPropertyDO getProperty(Long id) { + return productPropertyMapper.selectById(id); + } + + @Override + public List getPropertyList(Collection ids) { + return productPropertyMapper.selectBatchIds(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java new file mode 100644 index 0000000..aaa7ff1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; + +import java.util.Collection; +import java.util.List; + +/** + * 商品属性值 Service 接口 + * + * @author LuoWenFeng + */ +public interface ProductPropertyValueService { + + /** + * 创建属性值 + * 注意,如果已经存在该属性值,直接返回它的编号即可 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPropertyValue(ProductPropertyValueSaveReqVO createReqVO); + + /** + * 更新属性值 + * + * @param updateReqVO 更新信息 + */ + void updatePropertyValue(ProductPropertyValueSaveReqVO updateReqVO); + + /** + * 删除属性值 + * + * @param id 编号 + */ + void deletePropertyValue(Long id); + + /** + * 获得属性值 + * + * @param id 编号 + * @return 属性值 + */ + ProductPropertyValueDO getPropertyValue(Long id); + + /** + * 根据属性项编号数组,获得属性值列表 + * + * @param propertyIds 属性项目编号数组 + * @return 属性值列表 + */ + List getPropertyValueListByPropertyId(Collection propertyIds); + + /** + * 根据属性项编号,活的属性值数量 + * + * @param propertyId 属性项编号数 + * @return 属性值数量 + */ + Integer getPropertyValueCountByPropertyId(Long propertyId); + + /** + * 获取属性值的分页 + * + * @param pageReqVO 查询条件 + * @return 属性值的分页 + */ + PageResult getPropertyValuePage(ProductPropertyValuePageReqVO pageReqVO); + + /** + * 删除指定属性项编号下的属性值们 + * + * @param propertyId 属性项的编号 + */ + void deletePropertyValueByPropertyId(Long propertyId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java new file mode 100644 index 0000000..6ef0011 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS; + +/** + * 商品属性值 Service 实现类 + * + * @author LuoWenFeng + */ +@Service +@Validated +public class ProductPropertyValueServiceImpl implements ProductPropertyValueService { + + @Resource + private ProductPropertyValueMapper productPropertyValueMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private ProductSkuService productSkuService; + + @Override + public Long createPropertyValue(ProductPropertyValueSaveReqVO createReqVO) { + // 如果已经添加过该属性值,直接返回 + ProductPropertyValueDO dbValue = productPropertyValueMapper.selectByName( + createReqVO.getPropertyId(), createReqVO.getName()); + if (dbValue != null) { + return dbValue.getId(); + } + + // 新增 + ProductPropertyValueDO value = BeanUtils.toBean(createReqVO, ProductPropertyValueDO.class); + productPropertyValueMapper.insert(value); + return value.getId(); + } + + @Override + public void updatePropertyValue(ProductPropertyValueSaveReqVO updateReqVO) { + validatePropertyValueExists(updateReqVO.getId()); + // 校验名字唯一 + ProductPropertyValueDO value = productPropertyValueMapper.selectByName + (updateReqVO.getPropertyId(), updateReqVO.getName()); + if (value != null && !value.getId().equals(updateReqVO.getId())) { + throw exception(PROPERTY_VALUE_EXISTS); + } + + // 更新 + ProductPropertyValueDO updateObj = BeanUtils.toBean(updateReqVO, ProductPropertyValueDO.class); + productPropertyValueMapper.updateById(updateObj); + // 更新 sku 相关属性 + productSkuService.updateSkuPropertyValue(updateObj.getId(), updateObj.getName()); + } + + @Override + public void deletePropertyValue(Long id) { + validatePropertyValueExists(id); + productPropertyValueMapper.deleteById(id); + } + + private void validatePropertyValueExists(Long id) { + if (productPropertyValueMapper.selectById(id) == null) { + throw exception(PROPERTY_VALUE_NOT_EXISTS); + } + } + + @Override + public ProductPropertyValueDO getPropertyValue(Long id) { + return productPropertyValueMapper.selectById(id); + } + + @Override + public List getPropertyValueListByPropertyId(Collection propertyIds) { + return productPropertyValueMapper.selectListByPropertyId(propertyIds); + } + + @Override + public Integer getPropertyValueCountByPropertyId(Long propertyId) { + return productPropertyValueMapper.selectCountByPropertyId(propertyId); + } + + @Override + public PageResult getPropertyValuePage(ProductPropertyValuePageReqVO pageReqVO) { + return productPropertyValueMapper.selectPage(pageReqVO); + } + + @Override + public void deletePropertyValueByPropertyId(Long propertyId) { + productPropertyValueMapper.deleteByPropertyId(propertyId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java new file mode 100644 index 0000000..a6d3f02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.product.service.sku; + +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; + +import java.util.Collection; +import java.util.List; + +/** + * 商品 SKU Service 接口 + * + * @author 芋道源码 + */ +public interface ProductSkuService { + + /** + * 删除商品 SKU + * + * @param id 编号 + */ + void deleteSku(Long id); + + /** + * 获得商品 SKU 信息 + * + * @param id 编号 + * @return 商品 SKU 信息 + */ + ProductSkuDO getSku(Long id); + + /** + * 获得商品 SKU 列表 + * + * @param ids 编号 + * @return 商品sku列表 + */ + List getSkuList(Collection ids); + + /** + * 对 sku 的组合的属性等进行合法性校验 + * + * @param list sku组合的集合 + */ + void validateSkuList(List list, Boolean specType); + + /** + * 批量创建 SKU + * + * @param spuId 商品 SPU 编号 + * @param list SKU 对象集合 + */ + void createSkuList(Long spuId, List list); + + /** + * 根据 SPU 编号,批量更新它的 SKU 信息 + * + * @param spuId SPU 编码 + * @param skus SKU 的集合 + */ + void updateSkuList(Long spuId, List skus); + + /** + * 更新 SKU 库存(增量) + *

+ * 如果更新的库存不足,会抛出异常 + * + * @param updateStockReqDTO 更行请求 + */ + void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO); + + /** + * 获得商品 SKU 集合 + * + * @param spuId spu 编号 + * @return 商品sku 集合 + */ + List getSkuListBySpuId(Long spuId); + + /** + * 获得 spu 对应的 SKU 集合 + * + * @param spuIds spu 编码集合 + * @return 商品 sku 集合 + */ + List getSkuListBySpuId(Collection spuIds); + + /** + * 通过 spuId 删除 sku 信息 + * + * @param spuId spu 编码 + */ + void deleteSkuBySpuId(Long spuId); + + /** + * 更新 sku 属性 + * + * @param propertyId 属性 id + * @param propertyName 属性名 + * @return int 影响的行数 + */ + int updateSkuProperty(Long propertyId, String propertyName); + + /** + * 更新 sku 属性值 + * + * @param propertyValueId 属性值 id + * @param propertyValueName 属性值名字 + * @return int 影响的行数 + */ + int updateSkuPropertyValue(Long propertyValueId, String propertyValueName); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java new file mode 100644 index 0000000..4d07f7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -0,0 +1,270 @@ +package cn.iocoder.yudao.module.product.service.sku; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 商品 SKU Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductSkuServiceImpl implements ProductSkuService { + + @Resource + private ProductSkuMapper productSkuMapper; + + @Resource + @Lazy // 循环依赖,避免报错 + private ProductSpuService productSpuService; + @Resource + @Lazy // 循环依赖,避免报错 + private ProductPropertyService productPropertyService; + @Resource + private ProductPropertyValueService productPropertyValueService; + + @Override + public void deleteSku(Long id) { + // 校验存在 + validateSkuExists(id); + // 删除 + productSkuMapper.deleteById(id); + } + + private void validateSkuExists(Long id) { + if (productSkuMapper.selectById(id) == null) { + throw exception(SKU_NOT_EXISTS); + } + } + + @Override + public ProductSkuDO getSku(Long id) { + return productSkuMapper.selectById(id); + } + + @Override + public List getSkuList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return productSkuMapper.selectBatchIds(ids); + } + + @Override + public void validateSkuList(List skus, Boolean specType) { + // 0、校验skus是否为空 + if (CollUtil.isEmpty(skus)) { + throw exception(SKU_NOT_EXISTS); + } + // 单规格,赋予单规格默认属性 + if (ObjectUtil.equal(specType, false)) { + ProductSkuSaveReqVO skuVO = skus.get(0); + List properties = new ArrayList<>(); + ProductSkuSaveReqVO.Property property = new ProductSkuSaveReqVO.Property() + .setPropertyId(ProductPropertyDO.ID_DEFAULT).setPropertyName(ProductPropertyDO.NAME_DEFAULT) + .setValueId(ProductPropertyValueDO.ID_DEFAULT).setValueName(ProductPropertyValueDO.NAME_DEFAULT); + properties.add(property); + skuVO.setProperties(properties); + return; // 单规格不需要后续的校验 + } + + // 1、校验属性项存在 + Set propertyIds = skus.stream().filter(p -> p.getProperties() != null) + // 遍历多个 Property 属性 + .flatMap(p -> p.getProperties().stream()) + // 将每个 Property 转换成对应的 propertyId,最后形成集合 + .map(ProductSkuSaveReqVO.Property::getPropertyId) + .collect(Collectors.toSet()); + List propertyList = productPropertyService.getPropertyList(propertyIds); + if (propertyList.size() != propertyIds.size()) { + throw exception(PROPERTY_NOT_EXISTS); + } + + // 2. 校验,一个 SKU 下,没有重复的属性。校验方式是,遍历每个 SKU ,看看是否有重复的属性 propertyId + Map propertyValueMap = convertMap(productPropertyValueService.getPropertyValueListByPropertyId(propertyIds), ProductPropertyValueDO::getId); + skus.forEach(sku -> { + Set skuPropertyIds = convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId()); + if (skuPropertyIds.size() != sku.getProperties().size()) { + throw exception(SKU_PROPERTIES_DUPLICATED); + } + }); + + // 3. 再校验,每个 Sku 的属性值的数量,是一致的。 + int attrValueIdsSize = skus.get(0).getProperties().size(); + for (int i = 1; i < skus.size(); i++) { + if (attrValueIdsSize != skus.get(i).getProperties().size()) { + throw exception(SPU_ATTR_NUMBERS_MUST_BE_EQUALS); + } + } + + // 4. 最后校验,每个 Sku 之间不是重复的 + // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的. + Set> skuAttrValues = new HashSet<>(); + for (ProductSkuSaveReqVO sku : skus) { + // 添加失败,说明重复 + if (!skuAttrValues.add(convertSet(sku.getProperties(), ProductSkuSaveReqVO.Property::getValueId))) { + throw exception(SPU_SKU_NOT_DUPLICATE); + } + } + } + + @Override + public void createSkuList(Long spuId, List skuCreateReqList) { + List skus = BeanUtils.toBean(skuCreateReqList, ProductSkuDO.class, sku -> sku.setSpuId(spuId)); + productSkuMapper.insertBatch(skus); + } + + @Override + public List getSkuListBySpuId(Long spuId) { + return productSkuMapper.selectListBySpuId(spuId); + } + + @Override + public List getSkuListBySpuId(Collection spuIds) { + if (CollUtil.isEmpty(spuIds)) { + return Collections.emptyList(); + } + return productSkuMapper.selectListBySpuId(spuIds); + } + + @Override + public void deleteSkuBySpuId(Long spuId) { + productSkuMapper.deleteBySpuId(spuId); + } + + @Override + public int updateSkuProperty(Long propertyId, String propertyName) { + // 获取所有的 sku + List skuDOList = productSkuMapper.selectList(); + // 处理后需要更新的 sku + List updateSkus = new ArrayList<>(); + if (CollUtil.isEmpty(skuDOList)) { + return 0; + } + skuDOList.stream().filter(sku -> sku.getProperties() != null) + .forEach(sku -> sku.getProperties().forEach(property -> { + if (property.getPropertyId().equals(propertyId)) { + property.setPropertyName(propertyName); + updateSkus.add(sku); + } + })); + if (CollUtil.isEmpty(updateSkus)) { + return 0; + } + + productSkuMapper.updateBatch(updateSkus); + return updateSkus.size(); + } + + @Override + public int updateSkuPropertyValue(Long propertyValueId, String propertyValueName) { + // 获取所有的 sku + List skuDOList = productSkuMapper.selectList(); + // 处理后需要更新的 sku + List updateSkus = new ArrayList<>(); + if (CollUtil.isEmpty(skuDOList)) { + return 0; + } + skuDOList.stream() + .filter(sku -> sku.getProperties() != null) + .forEach(sku -> sku.getProperties().forEach(property -> { + if (property.getValueId().equals(propertyValueId)) { + property.setValueName(propertyValueName); + updateSkus.add(sku); + } + })); + if (CollUtil.isEmpty(updateSkus)) { + return 0; + } + + productSkuMapper.updateBatch(updateSkus); + return updateSkus.size(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSkuList(Long spuId, List skus) { + // 构建属性与 SKU 的映射关系; + Map existsSkuMap = convertMap(productSkuMapper.selectListBySpuId(spuId), + ProductSkuConvert.INSTANCE::buildPropertyKey, ProductSkuDO::getId); + + // 拆分三个集合,新插入的、需要更新的、需要删除的 + List insertSkus = new ArrayList<>(); + List updateSkus = new ArrayList<>(); + List allUpdateSkus = BeanUtils.toBean(skus, ProductSkuDO.class, sku -> sku.setSpuId(spuId)); + allUpdateSkus.forEach(sku -> { + String propertiesKey = ProductSkuConvert.INSTANCE.buildPropertyKey(sku); + // 1、找得到的,进行更新 + Long existsSkuId = existsSkuMap.remove(propertiesKey); + if (existsSkuId != null) { + sku.setId(existsSkuId); + updateSkus.add(sku); + return; + } + // 2、找不到,进行插入 + sku.setSpuId(spuId); + insertSkus.add(sku); + }); + + // 执行最终的批量操作 + if (CollUtil.isNotEmpty(insertSkus)) { + productSkuMapper.insertBatch(insertSkus); + } + if (CollUtil.isNotEmpty(updateSkus)) { + updateSkus.forEach(sku -> productSkuMapper.updateById(sku)); + } + if (CollUtil.isNotEmpty(existsSkuMap)) { + productSkuMapper.deleteBatchIds(existsSkuMap.values()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) { + // 更新 SKU 库存 + updateStockReqDTO.getItems().forEach(item -> { + if (item.getIncrCount() > 0) { + productSkuMapper.updateStockIncr(item.getId(), item.getIncrCount()); + } else if (item.getIncrCount() < 0) { + int updateStockIncr = productSkuMapper.updateStockDecr(item.getId(), item.getIncrCount()); + if (updateStockIncr == 0) { + throw exception(SKU_STOCK_NOT_ENOUGH); + } + } + }); + + // 更新 SPU 库存 + List skus = productSkuMapper.selectBatchIds( + convertSet(updateStockReqDTO.getItems(), ProductSkuUpdateStockReqDTO.Item::getId)); + Map spuStockIncrCounts = ProductSkuConvert.INSTANCE.convertSpuStockMap( + updateStockReqDTO.getItems(), skus); + productSpuService.updateSpuStock(spuStockIncrCounts); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java new file mode 100644 index 0000000..63b5dd6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.product.service.spu; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import org.springframework.scheduling.annotation.Async; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 商品 SPU Service 接口 + * + * @author 芋道源码 + */ +public interface ProductSpuService { + + /** + * 创建商品 SPU + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSpu(@Valid ProductSpuSaveReqVO createReqVO); + + /** + * 更新商品 SPU + * + * @param updateReqVO 更新信息 + */ + void updateSpu(@Valid ProductSpuSaveReqVO updateReqVO); + + /** + * 删除商品 SPU + * + * @param id 编号 + */ + void deleteSpu(Long id); + + /** + * 获得商品 SPU + * + * @param id 编号 + * @return 商品 SPU + */ + ProductSpuDO getSpu(Long id); + + /** + * 获得商品 SPU 列表 + * + * @param ids 编号数组 + * @return 商品 SPU 列表 + */ + List getSpuList(Collection ids); + + /** + * 获得指定状态的商品 SPU 列表 + * + * @param status 状态 + * @return 商品 SPU 列表 + */ + List getSpuListByStatus(Integer status); + + /** + * 获得商品 SPU 分页,提供给挂你兰后台使用 + * + * @param pageReqVO 分页查询 + * @return 商品spu分页 + */ + PageResult getSpuPage(ProductSpuPageReqVO pageReqVO); + + /** + * 获得商品 SPU 分页,提供给用户 App 使用 + * + * @param pageReqVO 分页查询 + * @return 商品 SPU 分页 + */ + PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO); + + /** + * 更新商品 SPU 库存(增量) + * + * @param stockIncrCounts SPU 编号与库存变化(增量)的映射 + */ + void updateSpuStock(Map stockIncrCounts); + + /** + * 更新 SPU 状态 + * + * @param updateReqVO 更新请求 + */ + void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO); + + /** + * 获取 SPU 列表标签对应的 Count 数量 + * + * @return Count 数量 + */ + Map getTabsCount(); + + /** + * 通过分类 categoryId 查询 SPU 个数 + * + * @param categoryId 分类 categoryId + * @return SPU 数量 + */ + Long getSpuCountByCategoryId(Long categoryId); + + + /** + * 校验商品是否有效。如下情况,视为无效: + * 1. 商品编号不存在 + * 2. 商品被禁用 + * + * @param ids 商品编号数组 + * @return 商品 SPU 列表 + */ + List validateSpuList(Collection ids); + + /** + * 更新商品 SPU 浏览量 + * + * @param id 商品 SPU 编号 + * @param incrCount 增加的数量 + */ + @Async + void updateBrowseCount(Long id, int incrCount); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java new file mode 100644 index 0000000..3a6cb2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -0,0 +1,274 @@ +package cn.iocoder.yudao.module.product.service.spu; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.brand.ProductBrandService; +import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import com.google.common.collect.Maps; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; + +/** + * 商品 SPU Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductSpuServiceImpl implements ProductSpuService { + + @Resource + private ProductSpuMapper productSpuMapper; + + @Resource + @Lazy // 循环依赖,避免报错 + private ProductSkuService productSkuService; + @Resource + private ProductBrandService brandService; + @Resource + private ProductCategoryService categoryService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createSpu(ProductSpuSaveReqVO createReqVO) { + // 校验分类、品牌 + validateCategory(createReqVO.getCategoryId()); + brandService.validateProductBrand(createReqVO.getBrandId()); + // 校验 SKU + List skuSaveReqList = createReqVO.getSkus(); + productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType()); + + ProductSpuDO spu = BeanUtils.toBean(createReqVO, ProductSpuDO.class); + // 初始化 SPU 中 SKU 相关属性 + initSpuFromSkus(spu, skuSaveReqList); + // 插入 SPU + productSpuMapper.insert(spu); + // 插入 SKU + productSkuService.createSkuList(spu.getId(), skuSaveReqList); + // 返回 + return spu.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSpu(ProductSpuSaveReqVO updateReqVO) { + // 校验 SPU 是否存在 + validateSpuExists(updateReqVO.getId()); + // 校验分类、品牌 + validateCategory(updateReqVO.getCategoryId()); + brandService.validateProductBrand(updateReqVO.getBrandId()); + // 校验SKU + List skuSaveReqList = updateReqVO.getSkus(); + productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType()); + + // 更新 SPU + ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class); + initSpuFromSkus(updateObj, skuSaveReqList); + productSpuMapper.updateById(updateObj); + // 批量更新 SKU + productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus()); + } + + /** + * 基于 SKU 的信息,初始化 SPU 的信息 + * 主要是计数相关的字段,例如说市场价、最大最小价、库存等等 + * + * @param spu 商品 SPU + * @param skus 商品 SKU 数组 + */ + private void initSpuFromSkus(ProductSpuDO spu, List skus) { + // sku 单价最低的商品的价格 + spu.setPrice(getMinValue(skus, ProductSkuSaveReqVO::getPrice)); + // sku 单价最低的商品的市场价格 + spu.setMarketPrice(getMinValue(skus, ProductSkuSaveReqVO::getMarketPrice)); + // sku 单价最低的商品的成本价格 + spu.setCostPrice(getMinValue(skus, ProductSkuSaveReqVO::getCostPrice)); + // skus 库存总数 + spu.setStock(getSumValue(skus, ProductSkuSaveReqVO::getStock, Integer::sum)); + // 若是 spu 已有状态则不处理 + if (spu.getStatus() == null) { + spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); // 默认状态为上架 + spu.setSalesCount(0); // 默认商品销量 + spu.setBrowseCount(0); // 默认商品浏览量 + } + } + + /** + * 校验商品分类是否合法 + * + * @param id 商品分类编号 + */ + private void validateCategory(Long id) { + categoryService.validateCategory(id); + // 校验层级 + if (categoryService.getCategoryLevel(id) < CATEGORY_LEVEL) { + throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR); + } + } + + @Override + public List validateSpuList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + // 获得商品信息 + List list = productSpuMapper.selectBatchIds(ids); + Map spuMap = CollectionUtils.convertMap(list, ProductSpuDO::getId); + // 校验 + ids.forEach(id -> { + ProductSpuDO spu = spuMap.get(id); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { + throw exception(SPU_NOT_ENABLE, spu.getName()); + } + }); + return list; + } + + @Override + public void updateBrowseCount(Long id, int incrCount) { + productSpuMapper.updateBrowseCount(id , incrCount); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSpu(Long id) { + // 校验存在 + validateSpuExists(id); + // 校验商品状态不是回收站不能删除 + ProductSpuDO spuDO = productSpuMapper.selectById(id); + // 判断 SPU 状态是否为回收站 + if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) { + throw exception(SPU_NOT_RECYCLE); + } + // TODO 芋艿:【可选】参与活动中的商品,不允许删除??? + + // 删除 SPU + productSpuMapper.deleteById(id); + // 删除关联的 SKU + productSkuService.deleteSkuBySpuId(id); + } + + private void validateSpuExists(Long id) { + if (productSpuMapper.selectById(id) == null) { + throw exception(SPU_NOT_EXISTS); + } + } + + @Override + public ProductSpuDO getSpu(Long id) { + return productSpuMapper.selectById(id); + } + + @Override + public List getSpuList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + Map spuMap = convertMap(productSpuMapper.selectBatchIds(ids), ProductSpuDO::getId); + // 需要按照 ids 顺序返回。例如说:店铺装修选择了 [3, 1, 2] 三个商品,返回结果还是 [3, 1, 2] 这样的顺序 + return convertList(ids, spuMap::get); + } + + @Override + public List getSpuListByStatus(Integer status) { + return productSpuMapper.selectList(ProductSpuDO::getStatus, status); + } + + @Override + public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) { + return productSpuMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO) { + // 查找时,如果查找某个分类编号,则包含它的子分类。因为顶级分类不包含商品 + Set categoryIds = new HashSet<>(); + if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) { + categoryIds.add(pageReqVO.getCategoryId()); + List categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO() + .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentId(pageReqVO.getCategoryId())); + categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId)); + } + if (CollUtil.isNotEmpty(pageReqVO.getCategoryIds())) { + categoryIds.addAll(pageReqVO.getCategoryIds()); + List categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO() + .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentIds(pageReqVO.getCategoryIds())); + categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId)); + } + // 分页查询 + return productSpuMapper.selectPage(pageReqVO, categoryIds); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSpuStock(Map stockIncrCounts) { + stockIncrCounts.forEach((id, incCount) -> productSpuMapper.updateStock(id, incCount)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO) { + // 校验存在 + validateSpuExists(updateReqVO.getId()); + // TODO 芋艿:【可选】参与活动中的商品,不允许下架??? + + // 更新状态 + ProductSpuDO productSpuDO = productSpuMapper.selectById(updateReqVO.getId()).setStatus(updateReqVO.getStatus()); + productSpuMapper.updateById(productSpuDO); + } + + @Override + public Map getTabsCount() { + Map counts = Maps.newLinkedHashMapWithExpectedSize(5); + // 查询销售中的商品数量 + counts.put(ProductSpuPageReqVO.FOR_SALE, + productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus())); + // 查询仓库中的商品数量 + counts.put(ProductSpuPageReqVO.IN_WAREHOUSE, + productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus())); + // 查询售空的商品数量 + counts.put(ProductSpuPageReqVO.SOLD_OUT, + productSpuMapper.selectCount(ProductSpuDO::getStock, 0)); + // 查询触发警戒库存的商品数量 + counts.put(ProductSpuPageReqVO.ALERT_STOCK, + productSpuMapper.selectCount()); + // 查询回收站中的商品数量 + counts.put(ProductSpuPageReqVO.RECYCLE_BIN, + productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus())); + return counts; + } + + @Override + public Long getSpuCountByCategoryId(Long categoryId) { + return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, categoryId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java new file mode 100644 index 0000000..8304ddc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/brand/ProductBrandServiceImplTest.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.product.service.brand; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.brand.vo.ProductBrandUpdateReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO; +import cn.iocoder.yudao.module.product.dal.mysql.brand.ProductBrandMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.BRAND_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link ProductBrandServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ProductBrandServiceImpl.class) +public class ProductBrandServiceImplTest extends BaseDbUnitTest { + + @Resource + private ProductBrandServiceImpl brandService; + + @Resource + private ProductBrandMapper brandMapper; + + @Test + public void testCreateBrand_success() { + // 准备参数 + ProductBrandCreateReqVO reqVO = randomPojo(ProductBrandCreateReqVO.class); + + // 调用 + Long brandId = brandService.createBrand(reqVO); + // 断言 + assertNotNull(brandId); + // 校验记录的属性是否正确 + ProductBrandDO brand = brandMapper.selectById(brandId); + assertPojoEquals(reqVO, brand); + } + + @Test + public void testUpdateBrand_success() { + // mock 数据 + ProductBrandDO dbBrand = randomPojo(ProductBrandDO.class); + brandMapper.insert(dbBrand);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ProductBrandUpdateReqVO reqVO = randomPojo(ProductBrandUpdateReqVO.class, o -> { + o.setId(dbBrand.getId()); // 设置更新的 ID + }); + + // 调用 + brandService.updateBrand(reqVO); + // 校验是否更新正确 + ProductBrandDO brand = brandMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, brand); + } + + @Test + public void testUpdateBrand_notExists() { + // 准备参数 + ProductBrandUpdateReqVO reqVO = randomPojo(ProductBrandUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> brandService.updateBrand(reqVO), BRAND_NOT_EXISTS); + } + + @Test + public void testDeleteBrand_success() { + // mock 数据 + ProductBrandDO dbBrand = randomPojo(ProductBrandDO.class); + brandMapper.insert(dbBrand);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbBrand.getId(); + + // 调用 + brandService.deleteBrand(id); + // 校验数据不存在了 + assertNull(brandMapper.selectById(id)); + } + + @Test + public void testDeleteBrand_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> brandService.deleteBrand(id), BRAND_NOT_EXISTS); + } + + @Test + public void testGetBrandPage() { + // mock 数据 + ProductBrandDO dbBrand = randomPojo(ProductBrandDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2022, 2, 1)); + }); + brandMapper.insert(dbBrand); + // 测试 name 不匹配 + brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setName("源码"))); + // 测试 status 不匹配 + brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + brandMapper.insert(cloneIgnoreId(dbBrand, o -> o.setCreateTime(buildTime(2022, 3, 1)))); + // 准备参数 + ProductBrandPageReqVO reqVO = new ProductBrandPageReqVO(); + reqVO.setName("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 2, 25)})); + + // 调用 + PageResult pageResult = brandService.getBrandPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBrand, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java new file mode 100644 index 0000000..af09cf3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImplTest.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.product.service.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategorySaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.dal.mysql.category.ProductCategoryMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.PARENT_ID_NULL; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * {@link ProductCategoryServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ProductCategoryServiceImpl.class) +public class ProductCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private ProductCategoryServiceImpl productCategoryService; + + @Resource + private ProductCategoryMapper productCategoryMapper; + + @Test + public void testCreateCategory_success() { + // 准备参数 + //ProductCategoryCreateReqVO reqVO = randomPojo(ProductCategoryCreateReqVO.class); + + // mock 父类 + //ProductCategoryDO parentProductCategory = randomPojo(ProductCategoryDO.class, o -> { + // reqVO.setParentId(o.getId()); + // o.setParentId(PARENT_ID_NULL); + //}); + //productCategoryMapper.insert(parentProductCategory); + // + //// 调用 + //Long categoryId = productCategoryService.createCategory(reqVO); + //// 断言 + //assertNotNull(categoryId); + //// 校验记录的属性是否正确 + //ProductCategoryDO category = productCategoryMapper.selectById(categoryId); + //assertPojoEquals(reqVO, category); + } + + @Test + public void testUpdateCategory_success() { + // mock 数据 + ProductCategoryDO dbCategory = randomPojo(ProductCategoryDO.class); + productCategoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ProductCategorySaveReqVO reqVO = randomPojo(ProductCategorySaveReqVO.class, o -> { + o.setId(dbCategory.getId()); // 设置更新的 ID + }); + // mock 父类 + ProductCategoryDO parentProductCategory = randomPojo(ProductCategoryDO.class, o -> o.setId(reqVO.getParentId())); + productCategoryMapper.insert(parentProductCategory); + + // 调用 + productCategoryService.updateCategory(reqVO); + // 校验是否更新正确 + ProductCategoryDO category = productCategoryMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, category); + } + + @Test + public void testUpdateCategory_notExists() { + // 准备参数 + ProductCategorySaveReqVO reqVO = randomPojo(ProductCategorySaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> productCategoryService.updateCategory(reqVO), CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteCategory_success() { + // mock 数据 + ProductCategoryDO dbCategory = randomPojo(ProductCategoryDO.class); + productCategoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCategory.getId(); + + // 调用 + productCategoryService.deleteCategory(id); + // 校验数据不存在了 + assertNull(productCategoryMapper.selectById(id)); + } + + @Test + public void testDeleteCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> productCategoryService.deleteCategory(id), CATEGORY_NOT_EXISTS); + } + + @Test + public void testGetCategoryLevel() { + // mock 数据 + ProductCategoryDO category1 = randomPojo(ProductCategoryDO.class, + o -> o.setParentId(PARENT_ID_NULL)); + productCategoryMapper.insert(category1); + ProductCategoryDO category2 = randomPojo(ProductCategoryDO.class, + o -> o.setParentId(category1.getId())); + productCategoryMapper.insert(category2); + ProductCategoryDO category3 = randomPojo(ProductCategoryDO.class, + o -> o.setParentId(category2.getId())); + productCategoryMapper.insert(category3); + + // 调用,并断言 + assertEquals(productCategoryService.getCategoryLevel(category1.getId()), 1); + assertEquals(productCategoryService.getCategoryLevel(category2.getId()), 2); + assertEquals(productCategoryService.getCategoryLevel(category3.getId()), 3); + } + + @Test + public void testGetCategoryList() { + // mock 数据 + ProductCategoryDO dbCategory = randomPojo(ProductCategoryDO.class, o -> { // 等会查询到 + o.setName("奥特曼"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setParentId(PARENT_ID_NULL); + }); + productCategoryMapper.insert(dbCategory); + // 测试 name 不匹配 + productCategoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName("奥特块"))); + // 测试 status 不匹配 + productCategoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 parentId 不匹配 + productCategoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setParentId(3333L))); + // 准备参数 + ProductCategoryListReqVO reqVO = new ProductCategoryListReqVO(); + reqVO.setName("特曼"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setParentId(PARENT_ID_NULL); + + // 调用 + List list = productCategoryService.getCategoryList(reqVO); + List all = productCategoryService.getCategoryList(new ProductCategoryListReqVO()); + // 断言 + assertEquals(1, list.size()); + assertEquals(4, all.size()); + assertPojoEquals(dbCategory, list.get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java new file mode 100644 index 0000000..eefe1a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java @@ -0,0 +1,195 @@ +package cn.iocoder.yudao.module.product.service.comment; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentRespVO; +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; +import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Lazy; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +// TODO 芋艿:单测详细 review 下 +/** + * {@link ProductCommentServiceImpl} 的单元测试类 + * + * @author wangzhs + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ProductCommentServiceImpl.class) +public class ProductCommentServiceImplTest extends BaseDbUnitTest { + + @Resource + private ProductCommentMapper productCommentMapper; + + @Resource + @Lazy + private ProductCommentServiceImpl productCommentService; + + @MockBean + private ProductSpuService productSpuService; + @MockBean + private ProductSkuService productSkuService; + + public String generateNo() { + return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); + } + + public Long generateId() { + return RandomUtil.randomLong(100000, 999999); + } + + @Test + public void testCreateCommentAndGet_success() { + // mock 测试 + ProductCommentDO productComment = randomPojo(ProductCommentDO.class); + productCommentMapper.insert(productComment); + + // 断言 + // 校验记录的属性是否正确 + ProductCommentDO comment = productCommentMapper.selectById(productComment.getId()); + assertPojoEquals(productComment, comment); + } + + @Test + public void testGetCommentPage_success() { + // 准备参数 + ProductCommentDO productComment = randomPojo(ProductCommentDO.class, o -> { + o.setUserNickname("王二狗"); + o.setSpuName("感冒药"); + o.setScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setReplyStatus(Boolean.TRUE); + o.setVisible(Boolean.TRUE); + o.setId(generateId()); + o.setUserId(generateId()); + o.setAnonymous(Boolean.TRUE); + o.setOrderId(generateId()); + o.setOrderItemId(generateId()); + o.setSpuId(generateId()); + o.setSkuId(generateId()); + o.setDescriptionScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setBenefitScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setContent("真好吃"); + o.setReplyUserId(generateId()); + o.setReplyContent("确实"); + o.setReplyTime(LocalDateTime.now()); + o.setCreateTime(LocalDateTime.now()); + o.setUpdateTime(LocalDateTime.now()); + }); + productCommentMapper.insert(productComment); + + Long orderId = productComment.getOrderId(); + Long spuId = productComment.getSpuId(); + + // 测试 userNickname 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setUserNickname("王三").setScores(ProductCommentScoresEnum.ONE.getScores()))); + // 测试 orderId 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setOrderId(generateId()))); + // 测试 spuId 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setSpuId(generateId()))); + // 测试 spuName 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setSpuName("感康"))); + // 测试 scores 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setScores(ProductCommentScoresEnum.ONE.getScores()))); + // 测试 replied 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setReplyStatus(Boolean.FALSE))); + // 测试 visible 不匹配 + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setVisible(Boolean.FALSE))); + + // 调用 + ProductCommentPageReqVO productCommentPageReqVO = new ProductCommentPageReqVO(); + productCommentPageReqVO.setUserNickname("王二"); + productCommentPageReqVO.setOrderId(orderId); + productCommentPageReqVO.setSpuId(spuId); + productCommentPageReqVO.setSpuName("感冒药"); + productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores()); + productCommentPageReqVO.setReplyStatus(Boolean.TRUE); + + PageResult commentPage = productCommentService.getCommentPage(productCommentPageReqVO); + PageResult result = BeanUtils.toBean(productCommentMapper.selectPage(productCommentPageReqVO), + ProductCommentRespVO.class); + assertEquals(result.getTotal(), commentPage.getTotal()); + + PageResult all = productCommentService.getCommentPage(new ProductCommentPageReqVO()); + assertEquals(8, all.getTotal()); + + // 测试获取所有商品分页评论数据 + PageResult result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE); + assertEquals(7, result1.getTotal()); + + // 测试获取所有商品分页中评数据 + PageResult result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); + assertEquals(2, result2.getTotal()); + + // 测试获取指定 spuId 商品分页中评数据 + PageResult result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); + assertEquals(2, result3.getTotal()); + + // 测试分页 tab count + //AppCommentStatisticsRespVO tabsCount = productCommentService.getCommentStatistics(spuId, Boolean.TRUE); + //assertEquals(4, tabsCount.getGoodCount()); + //assertEquals(2, tabsCount.getMediocreCount()); + //assertEquals(0, tabsCount.getNegativeCount()); + + } + + @Test + public void testUpdateCommentVisible_success() { + // mock 测试 + ProductCommentDO productComment = randomPojo(ProductCommentDO.class, o -> { + o.setVisible(Boolean.TRUE); + }); + productCommentMapper.insert(productComment); + + Long productCommentId = productComment.getId(); + + ProductCommentUpdateVisibleReqVO updateReqVO = new ProductCommentUpdateVisibleReqVO(); + updateReqVO.setId(productCommentId); + updateReqVO.setVisible(Boolean.FALSE); + productCommentService.updateCommentVisible(updateReqVO); + + ProductCommentDO productCommentDO = productCommentMapper.selectById(productCommentId); + assertFalse(productCommentDO.getVisible()); + } + + + @Test + public void testCommentReply_success() { + // mock 测试 + ProductCommentDO productComment = randomPojo(ProductCommentDO.class); + productCommentMapper.insert(productComment); + + Long productCommentId = productComment.getId(); + + ProductCommentReplyReqVO replyVO = new ProductCommentReplyReqVO(); + replyVO.setId(productCommentId); + replyVO.setReplyContent("测试"); + productCommentService.replyComment(replyVO, 1L); + + ProductCommentDO productCommentDO = productCommentMapper.selectById(productCommentId); + assertEquals("测试", productCommentDO.getReplyContent()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java new file mode 100644 index 0000000..0fb2868 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java @@ -0,0 +1,207 @@ +package cn.iocoder.yudao.module.product.service.sku; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; + +/** + * {@link ProductSkuServiceImpl} 的单元测试 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ProductSkuServiceImpl.class) +public class ProductSkuServiceTest extends BaseDbUnitTest { + + @Resource + private ProductSkuService productSkuService; + + @Resource + private ProductSkuMapper productSkuMapper; + + @MockBean + private ProductSpuService productSpuService; + @MockBean + private ProductPropertyService productPropertyService; + @MockBean + private ProductPropertyValueService productPropertyValueService; + + public Long generateId() { + return RandomUtil.randomLong(100000, 999999); + } + + @Test + public void testUpdateSkuList() { + // mock 数据 + ProductSkuDO sku01 = randomPojo(ProductSkuDO.class, o -> { // 测试更新 + o.setSpuId(1L); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 20L, "红色"))); + }); + productSkuMapper.insert(sku01); + ProductSkuDO sku02 = randomPojo(ProductSkuDO.class, o -> { // 测试删除 + o.setSpuId(1L); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 30L, "蓝色"))); + + }); + productSkuMapper.insert(sku02); + // 准备参数 + Long spuId = 1L; + String spuName = "测试商品"; + List skus = Arrays.asList( + randomPojo(ProductSkuSaveReqVO.class, o -> { // 测试更新 + o.setProperties(singletonList(new ProductSkuSaveReqVO.Property( + 10L, "颜色", 20L, "红色"))); + }), + randomPojo(ProductSkuSaveReqVO.class, o -> { // 测试新增 + o.setProperties(singletonList(new ProductSkuSaveReqVO.Property( + 10L, "颜色", 20L, "红色"))); + }) + ); + + // 调用 + productSkuService.updateSkuList(spuId, skus); + // 断言 + List dbSkus = productSkuMapper.selectListBySpuId(spuId); + assertEquals(dbSkus.size(), 2); + // 断言更新的 + assertEquals(dbSkus.get(0).getId(), sku01.getId()); + assertPojoEquals(dbSkus.get(0), skus.get(0), "properties"); + assertEquals(skus.get(0).getProperties().size(), 1); + assertPojoEquals(dbSkus.get(0).getProperties().get(0), skus.get(0).getProperties().get(0)); + // 断言新增的 + assertNotEquals(dbSkus.get(1).getId(), sku02.getId()); + assertPojoEquals(dbSkus.get(1), skus.get(1), "properties"); + assertEquals(skus.get(1).getProperties().size(), 1); + assertPojoEquals(dbSkus.get(1).getProperties().get(0), skus.get(1).getProperties().get(0)); + } + + @Test + public void testUpdateSkuStock_incrSuccess() { + // 准备参数 + ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO() + .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(10))); + // mock 数据 + productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> { + o.setId(1L).setSpuId(10L).setStock(20); + o.getProperties().forEach(p -> { + // 指定 id 范围 解决 Value too long + p.setPropertyId(generateId()); + p.setValueId(generateId()); + }); + })); + + // 调用 + productSkuService.updateSkuStock(updateStockReqDTO); + // 断言 + ProductSkuDO sku = productSkuMapper.selectById(1L); + assertEquals(sku.getStock(), 30); + verify(productSpuService).updateSpuStock(argThat(spuStockIncrCounts -> { + assertEquals(spuStockIncrCounts.size(), 1); + assertEquals(spuStockIncrCounts.get(10L), 10); + return true; + })); + } + + @Test + public void testUpdateSkuStock_decrSuccess() { + // 准备参数 + ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO() + .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-10))); + // mock 数据 + productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> { + o.setId(1L).setSpuId(10L).setStock(20); + o.getProperties().forEach(p -> { + // 指定 id 范围 解决 Value too long + p.setPropertyId(generateId()); + p.setValueId(generateId()); + }); + })); + + // 调用 + productSkuService.updateSkuStock(updateStockReqDTO); + // 断言 + ProductSkuDO sku = productSkuMapper.selectById(1L); + assertEquals(sku.getStock(), 10); + verify(productSpuService).updateSpuStock(argThat(spuStockIncrCounts -> { + assertEquals(spuStockIncrCounts.size(), 1); + assertEquals(spuStockIncrCounts.get(10L), -10); + return true; + })); + } + + @Test + public void testUpdateSkuStock_decrFail() { + // 准备参数 + ProductSkuUpdateStockReqDTO updateStockReqDTO = new ProductSkuUpdateStockReqDTO() + .setItems(singletonList(new ProductSkuUpdateStockReqDTO.Item().setId(1L).setIncrCount(-30))); + // mock 数据 + productSkuMapper.insert(randomPojo(ProductSkuDO.class, o -> { + o.setId(1L).setSpuId(10L).setStock(20); + o.getProperties().forEach(p -> { + // 指定 id 范围 解决 Value too long + p.setPropertyId(generateId()); + p.setValueId(generateId()); + }); + })); + // 调用并断言 + AssertUtils.assertServiceException(() -> productSkuService.updateSkuStock(updateStockReqDTO), + SKU_STOCK_NOT_ENOUGH); + } + + @Test + public void testDeleteSku_success() { + ProductSkuDO dbSku = randomPojo(ProductSkuDO.class, o -> { + o.setId(generateId()).setSpuId(generateId()); + o.getProperties().forEach(p -> { + // 指定 id 范围 解决 Value too long + p.setPropertyId(generateId()); + p.setValueId(generateId()); + }); + }); + // mock 数据 + productSkuMapper.insert(dbSku); + // 准备参数 + Long id = dbSku.getId(); + + // 调用 + productSkuService.deleteSku(id); + // 校验数据不存在了 + assertNull(productSkuMapper.selectById(id)); + } + + @Test + public void testDeleteSku_notExists() { + // 准备参数 + Long id = 1L; + + // 调用, 并断言异常 + assertServiceException(() -> productSkuService.deleteSku(id), SKU_NOT_EXISTS); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java new file mode 100644 index 0000000..50cb7ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java @@ -0,0 +1,470 @@ +package cn.iocoder.yudao.module.product.service.spu; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.product.service.brand.ProductBrandServiceImpl; +import cn.iocoder.yudao.module.product.service.category.ProductCategoryServiceImpl; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.assertj.core.util.Lists.newArrayList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +// TODO @芋艿:review 下单元测试 + +/** + * {@link ProductSpuServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ProductSpuServiceImpl.class) +public class ProductSpuServiceImplTest extends BaseDbUnitTest { + + @Resource + private ProductSpuServiceImpl productSpuService; + + @Resource + private ProductSpuMapper productSpuMapper; + + @MockBean + private ProductSkuServiceImpl productSkuService; + @MockBean + private ProductCategoryServiceImpl categoryService; + @MockBean + private ProductBrandServiceImpl brandService; + @MockBean + private ProductPropertyService productPropertyService; + @MockBean + private ProductPropertyValueService productPropertyValueService; + + public String generateNo() { + return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); + } + + public Long generateId() { + return RandomUtil.randomLong(100000, 999999); + } + + public int generaInt(){return RandomUtil.randomInt(1,9999999);} + + // TODO @芋艿:单测后续 review 哈 + + @Test + public void testCreateSpu_success() { + // 准备参数 + ProductSkuSaveReqVO skuCreateOrUpdateReqVO = randomPojo(ProductSkuSaveReqVO.class, o->{ + // 限制范围为正整数 + o.setCostPrice(generaInt()); + o.setPrice(generaInt()); + o.setMarketPrice(generaInt()); + o.setStock(generaInt()); + o.setFirstBrokeragePrice(generaInt()); + o.setSecondBrokeragePrice(generaInt()); + // 限制分数为两位数 + o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); + o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); + }); + ProductSpuSaveReqVO createReqVO = randomPojo(ProductSpuSaveReqVO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setSkus(newArrayList(skuCreateOrUpdateReqVO,skuCreateOrUpdateReqVO,skuCreateOrUpdateReqVO)); + }); + when(categoryService.getCategoryLevel(eq(createReqVO.getCategoryId()))).thenReturn(2); + Long spu = productSpuService.createSpu(createReqVO); + ProductSpuDO productSpuDO = productSpuMapper.selectById(spu); + assertPojoEquals(createReqVO, productSpuDO); + } + + @Test + public void testUpdateSpu_success() { + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }); + productSpuMapper.insert(createReqVO); + // 准备参数 + ProductSkuSaveReqVO skuCreateOrUpdateReqVO = randomPojo(ProductSkuSaveReqVO.class, o->{ + // 限制范围为正整数 + o.setCostPrice(generaInt()); + o.setPrice(generaInt()); + o.setMarketPrice(generaInt()); + o.setStock(generaInt()); + o.setFirstBrokeragePrice(generaInt()); + o.setSecondBrokeragePrice(generaInt()); + // 限制分数为两位数 + o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); + o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); + }); + // 准备参数 + ProductSpuSaveReqVO reqVO = randomPojo(ProductSpuSaveReqVO.class, o -> { + o.setId(createReqVO.getId()); // 设置更新的 ID + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + o.setSkus(newArrayList(skuCreateOrUpdateReqVO,skuCreateOrUpdateReqVO,skuCreateOrUpdateReqVO)); + }); + when(categoryService.getCategoryLevel(eq(reqVO.getCategoryId()))).thenReturn(2); + // 调用 + productSpuService.updateSpu(reqVO); + // 校验是否更新正确 + ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, spu); + } + + @Test + public void testValidateSpuExists_exception() { + ProductSpuSaveReqVO reqVO = randomPojo(ProductSpuSaveReqVO.class); + // 调用 + Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO)); + } + + @Test + void deleteSpu() { + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + o.setStatus(-1); // 加入回收站才可删除 + }); + productSpuMapper.insert(createReqVO); + + // 调用 + productSpuService.deleteSpu(createReqVO.getId()); + + Assertions.assertNull(productSpuMapper.selectById(createReqVO.getId())); + } + + @Test + void getSpu() { + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }); + productSpuMapper.insert(createReqVO); + + ProductSpuDO spu = productSpuService.getSpu(createReqVO.getId()); + assertPojoEquals(createReqVO, spu); + } + + @Test + void getSpuList() { + // 准备参数 + ArrayList createReqVOs = Lists.newArrayList(randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }), randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + })); + productSpuMapper.insertBatch(createReqVOs); + + // 调用 + List spuList = productSpuService.getSpuList(createReqVOs.stream().map(ProductSpuDO::getId).collect(Collectors.toList())); + Assertions.assertIterableEquals(createReqVOs, spuList); + } + + @Test + void getSpuPage_alarmStock_empty() { + // 准备参数 + ArrayList createReqVOs = Lists.newArrayList(randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(11); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }), randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(11); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + })); + productSpuMapper.insertBatch(createReqVOs); + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + productSpuPageReqVO.setTabType(ProductSpuPageReqVO.ALERT_STOCK); + + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + + PageResult result = PageResult.empty(); + Assertions.assertIterableEquals(result.getList(), spuPage.getList()); + assertEquals(spuPage.getTotal(), result.getTotal()); + } + + @Test + void getSpuPage_alarmStock() { + // 准备参数 + ArrayList createReqVOs = Lists.newArrayList(randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(5); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }), randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(9); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + })); + productSpuMapper.insertBatch(createReqVOs); + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + productSpuPageReqVO.setTabType(ProductSpuPageReqVO.ALERT_STOCK); + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + assertEquals(createReqVOs.size(), spuPage.getTotal()); + } + + @Test + void testGetSpuPage() { + // 准备参数 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class,o->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + }); + + // 准备参数 + productSpuMapper.insert(createReqVO); + // 测试 status 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()))); + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setStatus(ProductSpuStatusEnum.RECYCLE.getStatus()))); + // 测试 SpecType 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setSpecType(true))); + // 测试 BrandId 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setBrandId(generateId()))); + // 测试 CategoryId 不匹配 + productSpuMapper.insert(cloneIgnoreId(createReqVO, o -> o.setCategoryId(generateId()))); + + // 调用 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); + // 查询条件 按需打开 + //productSpuPageReqVO.setTabType(ProductSpuPageReqVO.ALERT_STOCK); + //productSpuPageReqVO.setTabType(ProductSpuPageReqVO.RECYCLE_BIN); + //productSpuPageReqVO.setTabType(ProductSpuPageReqVO.FOR_SALE); + //productSpuPageReqVO.setTabType(ProductSpuPageReqVO.IN_WAREHOUSE); + //productSpuPageReqVO.setTabType(ProductSpuPageReqVO.SOLD_OUT); + //productSpuPageReqVO.setName(createReqVO.getName()); + //productSpuPageReqVO.setCategoryId(createReqVO.getCategoryId()); + + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + + assertEquals(1, spuPage.getTotal()); + } + + /** + * 生成笛卡尔积 + * + * @param data 数据 + * @return 笛卡尔积 + */ + public static List> cartesianProduct(List> data) { + List> res = null; // 结果集(当前为第N个List,则该处存放的就为前N-1个List的笛卡尔积集合) + for (List list : data) { // 遍历数据 + List> temp = new ArrayList<>(); // 临时结果集,存放本次循环后生成的笛卡尔积集合 + if (res == null) { // 结果集为null表示第一次循环既list为第一个List + for (T t : list) { // 便利第一个List + // 利用stream生成List,第一个List的笛卡尔积集合约等于自己本身(需要创建一个List并把对象添加到当中),存放到临时结果集 + temp.add(Stream.of(t).collect(Collectors.toList())); + } + res = temp; // 将临时结果集赋值给结果集 + continue; // 跳过本次循环 + } + // 不为第一个List,计算前面的集合(笛卡尔积)和当前List的笛卡尔积集合 + for (T t : list) { // 便利 + for (List rl : res) { // 便利前面的笛卡尔积集合 + // 利用stream生成List + temp.add(Stream.concat(rl.stream(), Stream.of(t)).collect(Collectors.toList())); + } + } + res = temp; // 将临时结果集赋值给结果集 + } + // 返回结果 + return res; + } + + @Test + public void testUpdateSpuStock() { + // 准备参数 + Map stockIncrCounts = MapUtil.builder(1L, 10).put(2L, -20).build(); + // mock 方法(数据) + productSpuMapper.insert(randomPojo(ProductSpuDO.class, o ->{ + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + o.setId(1L).setStock(20); + })); + productSpuMapper.insert(randomPojo(ProductSpuDO.class, o -> { + o.setCategoryId(generateId()); + o.setBrandId(generateId()); + o.setDeliveryTemplateId(generateId()); + o.setSort(RandomUtil.randomInt(1,100)); // 限制排序范围 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setVirtualSalesCount(generaInt()); // 限制范围为正整数 + o.setPrice(generaInt()); // 限制范围为正整数 + o.setMarketPrice(generaInt()); // 限制范围为正整数 + o.setCostPrice(generaInt()); // 限制范围为正整数 + o.setStock(generaInt()); // 限制范围为正整数 + o.setGiveIntegral(generaInt()); // 限制范围为正整数 + o.setSalesCount(generaInt()); // 限制范围为正整数 + o.setBrowseCount(generaInt()); // 限制范围为正整数 + o.setId(2L).setStock(30); + })); + + // 调用 + productSpuService.updateSpuStock(stockIncrCounts); + // 断言 + assertEquals(productSpuService.getSpu(1L).getStock(), 30); + assertEquals(productSpuService.getSpu(2L).getStock(), 10); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..3dfadda --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,48 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis-plus: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..e9616cd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,7 @@ +DELETE FROM "product_sku"; +DELETE FROM "product_spu"; +DELETE FROM "product_category"; +DELETE FROM "product_brand"; +DELETE FROM "product_property"; +DELETE FROM "product_property_value"; +DELETE FROM "product_comment"; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..f0f0c70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,157 @@ +CREATE TABLE IF NOT EXISTS `product_sku` ( + `id` bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `spu_id` bigint NOT NULL COMMENT 'spu编号', + `properties` varchar(512) DEFAULT NULL COMMENT '属性数组,JSON 格式', + `price` int NOT NULL DEFAULT '-1' COMMENT '商品价格,单位:分', + `market_price` int DEFAULT NULL COMMENT '市场价,单位:分', + `cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分', + `bar_code` varchar(64) DEFAULT NULL COMMENT 'SKU 的条形码', + `pic_url` varchar(256) NOT NULL COMMENT '图片地址', + `stock` int DEFAULT NULL COMMENT '库存', + `weight` double DEFAULT NULL COMMENT '商品重量,单位:kg 千克', + `volume` double DEFAULT NULL COMMENT '商品体积,单位:m^3 平米', + `sub_commission_first_price` int DEFAULT NULL COMMENT '一级分销的佣金,单位:分', + `sub_commission_second_price` int DEFAULT NULL COMMENT '二级分销的佣金,单位:分', + `sales_count` int DEFAULT NULL COMMENT '商品销量', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY("id") +) COMMENT '商品sku'; + +CREATE TABLE IF NOT EXISTS `product_spu` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '商品 SPU 编号,自增', + `name` varchar(128) NOT NULL COMMENT '商品名称', + `keyword` varchar(256) NOT NULL COMMENT '关键字', + `introduction` varchar(256) NOT NULL COMMENT '商品简介', + `description` text NOT NULL COMMENT '商品详情', + `bar_code` varchar(64) NOT NULL COMMENT '条形码', + `category_id` bigint NOT NULL COMMENT '商品分类编号', + `brand_id` int DEFAULT NULL COMMENT '商品品牌编号', + `pic_url` varchar(256) NOT NULL COMMENT '商品封面图', + `slider_pic_urls` varchar(2000) DEFAULT '' COMMENT '商品轮播图地址\n 数组,以逗号分隔\n 最多上传15张', + `video_url` varchar(256) DEFAULT NULL COMMENT '商品视频', + `unit` tinyint NOT NULL COMMENT '单位', + `sort` int NOT NULL DEFAULT '0' COMMENT '排序字段', + `status` tinyint NOT NULL COMMENT '商品状态: 0 上架(开启) 1 下架(禁用)-1 回收', + `spec_type` bit(1) NOT NULL COMMENT '规格类型:0 单规格 1 多规格', + `price` int NOT NULL DEFAULT '-1' COMMENT '商品价格,单位使用:分', + `market_price` int NOT NULL COMMENT '市场价,单位使用:分', + `cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分', + `stock` int NOT NULL DEFAULT '0' COMMENT '库存', + `delivery_template_id` bigint NOT NULL COMMENT '物流配置模板编号', + `recommend_hot` bit(1) NOT NULL COMMENT '是否热卖推荐: 0 默认 1 热卖', + `recommend_benefit` bit(1) NOT NULL COMMENT '是否优惠推荐: 0 默认 1 优选', + `recommend_best` bit(1) NOT NULL COMMENT '是否精品推荐: 0 默认 1 精品', + `recommend_new` bit(1) NOT NULL COMMENT '是否新品推荐: 0 默认 1 新品', + `recommend_good` bit(1) NOT NULL COMMENT '是否优品推荐', + `give_integral` int NOT NULL COMMENT '赠送积分', + `give_coupon_template_ids` varchar(512) DEFAULT '' COMMENT '赠送的优惠劵编号的数组', + `sub_commission_type` bit(1) NOT NULL COMMENT '分销类型', + `activity_orders` varchar(16) NOT NULL DEFAULT '' COMMENT '活动显示排序0=默认, 1=秒杀,2=砍价,3=拼团', + `sales_count` int DEFAULT '0' COMMENT '商品销量', + `virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量', + `browse_count` int DEFAULT '0' COMMENT '商品点击量', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY("id") +) COMMENT '商品spu'; + +CREATE TABLE IF NOT EXISTS `product_category` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号', + `parent_id` bigint NOT NULL COMMENT '父分类编号', + `name` varchar(255) NOT NULL COMMENT '分类名称', + `pic_url` varchar(255) NOT NULL COMMENT '移动端分类图', + `big_pic_url` varchar(255) DEFAULT NULL COMMENT 'PC 端分类图', + `sort` int DEFAULT '0' COMMENT '分类排序', + `status` tinyint NOT NULL COMMENT '开启状态', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY("id") +) COMMENT '商品分类'; + +CREATE TABLE IF NOT EXISTS `product_brand` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '品牌编号', + `name` varchar(255) NOT NULL COMMENT '品牌名称', + `pic_url` varchar(255) NOT NULL COMMENT '品牌图片', + `sort` int DEFAULT '0' COMMENT '品牌排序', + `description` varchar(1024) DEFAULT NULL COMMENT '品牌描述', + `status` tinyint NOT NULL COMMENT '状态', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY("id") +) COMMENT '商品品牌'; + +CREATE TABLE IF NOT EXISTS `product_property` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) DEFAULT NULL COMMENT '规格名称', + `status` tinyint DEFAULT NULL COMMENT '状态: 0 开启 ,1 禁用', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + PRIMARY KEY("id") +) COMMENT '规格名称'; + +CREATE TABLE IF NOT EXISTS `product_property_value` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `property_id` bigint DEFAULT NULL COMMENT '规格键id', + `name` varchar(128) DEFAULT NULL COMMENT '规格值名字', + `status` tinyint DEFAULT NULL COMMENT '状态: 1 开启 ,2 禁用', + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + PRIMARY KEY("id") +) COMMENT '规格值'; + +DROP TABLE IF EXISTS `product_comment` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '评论编号,主键自增', + `user_id` bigint DEFAULT NULL COMMENT '评价人的用户编号关联 MemberUserDO 的 id 编号', + `user_nickname` varchar(255) DEFAULT NULL COMMENT '评价人名称', + `user_avatar` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '评价人头像', + `anonymous` bit(1) DEFAULT NULL COMMENT '是否匿名', + `order_id` bigint DEFAULT NULL COMMENT '交易订单编号关联 TradeOrderDO 的 id 编号', + `order_item_id` bigint DEFAULT NULL COMMENT '交易订单项编号关联 TradeOrderItemDO 的 id 编号', + `spu_id` bigint DEFAULT NULL COMMENT '商品 SPU 编号关联 ProductSpuDO 的 id', + `spu_name` varchar(255) DEFAULT NULL COMMENT '商品 SPU 名称', + `sku_id` bigint DEFAULT NULL COMMENT '商品 SKU 编号关联 ProductSkuDO 的 id 编号', + `visible` bit(1) DEFAULT NULL COMMENT '是否可见true:显示false:隐藏', + `scores` tinyint DEFAULT NULL COMMENT '评分星级1-5分', + `description_scores` tinyint DEFAULT NULL COMMENT '描述星级1-5 星', + `benefit_scores` tinyint DEFAULT NULL COMMENT '服务星级1-5 星', + `content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '评论内容', + `pic_urls` varchar(4096) DEFAULT NULL COMMENT '评论图片地址数组', + `reply_status` bit(1) DEFAULT NULL COMMENT '商家是否回复', + `reply_user_id` bigint DEFAULT NULL COMMENT '回复管理员编号关联 AdminUserDO 的 id 编号', + `reply_content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商家回复内容', + `reply_time` datetime DEFAULT NULL COMMENT '商家回复时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '商品评论'; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/pom.xml new file mode 100644 index 0000000..1c21560 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/pom.xml @@ -0,0 +1,40 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-promotion-api + jar + + ${project.artifactId} + + promotion 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + + com.fasterxml.jackson.core + jackson-databind + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java new file mode 100644 index 0000000..0f98126 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.promotion.api.bargain; + +/** + * 砍价活动 Api 接口 + * + * @author HUIHUI + */ +public interface BargainActivityApi { + + /** + * 更新砍价活动库存 + * + * @param id 砍价活动编号 + * @param count 购买数量 + */ + void updateBargainActivityStock(Long id, Integer count); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java new file mode 100644 index 0000000..fb0e3f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApi.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.api.bargain; + +import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; + +/** + * 砍价记录 API 接口 + * + * @author HUIHUI + */ +public interface BargainRecordApi { + + /** + * 【下单前】校验是否参与砍价活动 + *

+ * 如果校验失败,则抛出业务异常 + * + * @param userId 用户编号 + * @param bargainRecordId 砍价活动编号 + * @param skuId SKU 编号 + * @return 砍价信息 + */ + BargainValidateJoinRespDTO validateJoinBargain(Long userId, Long bargainRecordId, Long skuId); + + /** + * 更新砍价记录的订单编号 + * + * 在砍价成功后,用户发起订单后,会记录该订单编号 + * + * @param id 砍价记录编号 + * @param orderId 订单编号 + */ + void updateBargainRecordOrderId(Long id, Long orderId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainValidateJoinRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainValidateJoinRespDTO.java new file mode 100644 index 0000000..a64e923 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainValidateJoinRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.api.bargain.dto; + +import lombok.Data; + +/** + * 校验参与砍价 Response DTO + */ +@Data +public class BargainValidateJoinRespDTO { + + /** + * 砍价活动编号 + */ + private Long activityId; + /** + * 砍价活动名称 + */ + private String name; + + /** + * 砍价金额 + */ + private Integer bargainPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java new file mode 100644 index 0000000..bdc902c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.promotion.api.combination; + +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO; + +import javax.validation.Valid; + +/** + * 拼团记录 API 接口 + * + * @author HUIHUI + */ +public interface CombinationRecordApi { + + /** + * 校验是否满足拼团条件 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @param headId 团长编号 + * @param skuId sku 编号 + * @param count 数量 + */ + void validateCombinationRecord(Long userId, Long activityId, Long headId, Long skuId, Integer count); + + /** + * 创建开团记录 + * + * @param reqDTO 请求 DTO + * @return 拼团信息 + */ + CombinationRecordCreateRespDTO createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO); + + /** + * 查询拼团记录是否成功 + * + * @param userId 用户编号 + * @param orderId 订单编号 + * @return 拼团是否成功 + */ + boolean isCombinationRecordSuccess(Long userId, Long orderId); + + /** + * 【下单前】校验是否满足拼团活动条件 + * + * 如果校验失败,则抛出业务异常 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @param headId 团长编号 + * @param skuId sku 编号 + * @param count 数量 + * @return 拼团信息 + */ + CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, + Long skuId, Integer count); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java new file mode 100644 index 0000000..ac86c45 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.promotion.api.combination.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 拼团记录的创建 Request DTO + * + * @author HUIHUI + */ +@Data +public class CombinationRecordCreateReqDTO { + + /** + * 拼团活动编号 + */ + @NotNull(message = "拼团活动编号不能为空") + private Long activityId; + /** + * spu 编号 + */ + @NotNull(message = "spu 编号不能为空") + private Long spuId; + /** + * sku 编号 + */ + @NotNull(message = "sku 编号不能为空") + private Long skuId; + /** + * 购买的商品数量 + */ + @NotNull(message = "购买数量不能为空") + private Integer count; + /** + * 订单编号 + */ + @NotNull(message = "订单编号不能为空") + private Long orderId; + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 团长编号 + */ + private Long headId; + /** + * 拼团商品单价 + */ + @NotNull(message = "拼团商品单价不能为空") + private Integer combinationPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateRespDTO.java new file mode 100644 index 0000000..5f4ea2a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateRespDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.promotion.api.combination.dto; + +import lombok.Data; + +/** + * 拼团记录的创建 Response DTO + * + * @author HUIHUI + */ +@Data +public class CombinationRecordCreateRespDTO { + + /** + * 拼团活动编号 + * + * 关联 CombinationActivityDO 的 id 字段 + */ + private Long combinationActivityId; + /** + * 拼团团长编号 + * + * 关联 CombinationRecordDO 的 headId 字段 + */ + private Long combinationHeadId; + /** + * 拼团记录编号 + * + * 关联 CombinationRecordDO 的 id 字段 + */ + private Long combinationRecordId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationValidateJoinRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationValidateJoinRespDTO.java new file mode 100644 index 0000000..86fe00a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationValidateJoinRespDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.api.combination.dto; + +import lombok.Data; + +/** + * 校验参与拼团 Response DTO + * + * @author HUIHUI + */ +@Data +public class CombinationValidateJoinRespDTO { + + /** + * 砍价活动编号 + */ + private Long activityId; + /** + * 砍价活动名称 + */ + private String name; + + /** + * 拼团金额 + */ + private Integer combinationPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java new file mode 100644 index 0000000..ab970c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.api.coupon; + +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; + +import javax.validation.Valid; + +/** + * 优惠劵 API 接口 + * + * @author 芋道源码 + */ +public interface CouponApi { + + /** + * 使用优惠劵 + * + * @param useReqDTO 使用请求 + */ + void useCoupon(@Valid CouponUseReqDTO useReqDTO); + + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); + + /** + * 校验优惠劵 + * + * @param validReqDTO 校验请求 + * @return 优惠劵 + */ + CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java new file mode 100644 index 0000000..a404bf2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.promotion.api.coupon.dto; + +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 优惠劵 Response DTO + * + * @author 芋道源码 + */ +@Data +public class CouponRespDTO { + + // ========== 基本信息 BEGIN ========== + /** + * 优惠劵编号 + */ + private Long id; + /** + * 优惠劵模板编号 + */ + private Integer templateId; + /** + * 优惠劵名 + */ + private String name; + /** + * 优惠码状态 + * + * 枚举 {@link CouponStatusEnum} + */ + private Integer status; + + // ========== 基本信息 END ========== + + // ========== 领取情况 BEGIN ========== + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 字段 + */ + private Long userId; + /** + * 领取类型 + * + * 枚举 {@link CouponTakeTypeEnum} + */ + private Integer takeType; + // ========== 领取情况 END ========== + + // ========== 使用规则 BEGIN ========== + /** + * 是否设置满多少金额可用,单位:分 + */ + private Integer usePrice; + /** + * 生效开始时间 + */ + private LocalDateTime validStartTime; + /** + * 生效结束时间 + */ + private LocalDateTime validEndTime; + /** + * 商品范围 + */ + private Integer productScope; + /** + * 商品范围编号的数组 + */ + private List productScopeValues; + // ========== 使用规则 END ========== + + // ========== 使用效果 BEGIN ========== + /** + * 折扣类型 + */ + private Integer discountType; + /** + * 折扣百分比 + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + */ + private Integer discountPrice; + /** + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 + */ + private Integer discountLimitPrice; + // ========== 使用效果 END ========== + + // ========== 使用情况 BEGIN ========== + /** + * 使用订单号 + */ + private Long useOrderId; + /** + * 使用时间 + */ + private LocalDateTime useTime; + + // ========== 使用情况 END ========== +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponUseReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponUseReqDTO.java new file mode 100644 index 0000000..9323ab5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponUseReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.api.coupon.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 优惠劵使用 Request DTO + * + * @author 芋道源码 + */ +@Data +public class CouponUseReqDTO { + + /** + * 优惠劵编号 + */ + @NotNull(message = "优惠劵编号不能为空") + private Long id; + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + + /** + * 订单编号 + */ + @NotNull(message = "订单编号不能为空") + private Long orderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponValidReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponValidReqDTO.java new file mode 100644 index 0000000..dd25c64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponValidReqDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.api.coupon.dto; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 优惠劵使用 Request DTO + * + * @author 芋道源码 + */ +@Data +public class CouponValidReqDTO { + + /** + * 优惠劵编号 + */ + @NotNull(message = "优惠劵编号不能为空") + private Long id; + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApi.java new file mode 100644 index 0000000..b25f67d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApi.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.api.discount; + +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 限时折扣 API 接口 + * + * @author 芋道源码 + */ +public interface DiscountActivityApi { + + /** + * 获得商品匹配的的限时折扣信息 + * + * @param skuIds 商品 SKU 编号数组 + * @return 限时折扣信息 + */ + List getMatchDiscountProductList(Collection skuIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java new file mode 100644 index 0000000..52dfdbe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.promotion.api.discount.dto; + +import lombok.Data; + +/** + * 限时折扣活动商品 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DiscountProductRespDTO { + + /** + * 编号,主键自增 + */ + private Long id; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 折扣类型 + */ + private Integer discountType; + /** + * 折扣百分比 + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + */ + private Integer discountPrice; + + // ========== 活动字段 ========== + /** + * 限时折扣活动的编号 + */ + private Long activityId; + /** + * 活动标题 + */ + private String activityName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java new file mode 100644 index 0000000..efeddf3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.api.reward; + +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 满减送活动 API 接口 + * + * @author 芋道源码 + */ +public interface RewardActivityApi { + + + /** + * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 + * + * @param spuIds SPU 编号数组 + * @return 满减送活动列表 + */ + List getMatchRewardActivityList(Collection spuIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java new file mode 100644 index 0000000..6ae71a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.promotion.api.reward.dto; + +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import lombok.Data; + +import java.util.List; + +/** + * 满减送活动的匹配 Response DTO + * + * @author 芋道源码 + */ +@Data +public class RewardActivityMatchRespDTO { + + /** + * 活动编号,主键自增 + */ + private Long id; + /** + * 活动标题 + */ + private String name; + /** + * 条件类型 + * + * 枚举 {@link PromotionConditionTypeEnum} + */ + private Integer conditionType; + /** + * 优惠规则的数组 + */ + private List rules; + + /** + * 商品 SPU 编号的数组 + */ + private List spuIds; + + // TODO 芋艿:后面 RewardActivityRespDTO 有了之后,Rule 可以放过去 + /** + * 优惠规则 + */ + @Data + public static class Rule { + + /** + * 优惠门槛 + * + * 1. 满 N 元,单位:分 + * 2. 满 N 件 + */ + private Integer limit; + /** + * 优惠价格,单位:分 + */ + private Integer discountPrice; + /** + * 是否包邮 + */ + private Boolean freeDelivery; + /** + * 赠送的积分 + */ + private Integer point; + /** + * 赠送的优惠劵编号的数组 + */ + private List couponIds; + /** + * 赠送的优惠券数量的数组 + */ + private List couponCounts; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java new file mode 100644 index 0000000..0d65919 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.promotion.api.seckill; + +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; + +/** + * 秒杀活动 API 接口 + * + * @author HUIHUI + */ +public interface SeckillActivityApi { + + /** + * 更新秒杀库存(减少) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updateSeckillStockDecr(Long id, Long skuId, Integer count); + + /** + * 更新秒杀库存(增加) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updateSeckillStockIncr(Long id, Long skuId, Integer count); + + /** + * 【下单前】校验是否参与秒杀活动 + * + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 + * @return 秒杀信息 + */ + SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java new file mode 100644 index 0000000..aae89a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.api.seckill.dto; + +import lombok.Data; + +/** + * 校验参与秒杀 Response DTO + */ +@Data +public class SeckillValidateJoinRespDTO { + + /** + * 秒杀活动名称 + */ + private String name; + /** + * 总限购数量 + * + * 目的:目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 + */ + private Integer totalLimitCount; + + /** + * 秒杀金额 + */ + private Integer seckillPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/DictTypeConstants.java new file mode 100644 index 0000000..f377ca2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/DictTypeConstants.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.promotion.enums; + +/** + * promotion 字典类型的枚举类 + * + * @author HUIHUI + */ +public class DictTypeConstants { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..3b19d61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -0,0 +1,128 @@ +package cn.iocoder.yudao.module.promotion.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Promotion 错误码枚举类 + *

+ * promotion 系统,使用 1-013-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 促销活动相关 1-013-001-000 ============ + ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_001_000, "限时折扣活动不存在"); + ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动"); + ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改"); + ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除"); + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭"); + + // ========== Banner 相关 1-013-002-000 ============ + ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在"); + + // ========== Coupon 相关 1-013-003-000 ============ + ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1_013_003_000, "优惠劵没有可使用的商品!"); + ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1_013_003_001, "所结算的商品中未满足使用的金额"); + + // ========== 优惠劵模板 1-013-004-000 ========== + ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_004_000, "优惠劵模板不存在"); + ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1_013_004_001, "发放数量不能小于已领取数量({})"); + ErrorCode COUPON_TEMPLATE_NOT_ENOUGH = new ErrorCode(1_013_004_002, "当前剩余数量不够领取"); + ErrorCode COUPON_TEMPLATE_USER_ALREADY_TAKE = new ErrorCode(1_013_004_003, "用户已领取过此优惠券"); + ErrorCode COUPON_TEMPLATE_EXPIRED = new ErrorCode(1_013_004_004, "优惠券已过期"); + ErrorCode COUPON_TEMPLATE_CANNOT_TAKE = new ErrorCode(1_013_004_005, "领取方式不正确"); + + // ========== 优惠劵 1-013-005-000 ========== + ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1_013_005_000, "优惠券不存在"); + ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1_013_005_001, "回收优惠劵失败,优惠劵已被使用"); + ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1_013_005_002, "优惠劵不处于待使用状态"); + ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1_013_005_003, "优惠券不在使用时间范围内"); + ErrorCode COUPON_STATUS_NOT_USED = new ErrorCode(1_013_005_004, "优惠劵不是已使用状态"); + + // ========== 满减送活动 1-013-006-000 ========== + ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_006_000, "满减送活动不存在"); + ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_006_001, "存在商品参加了其它满减送活动"); + ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_002, "满减送活动已关闭,不能修改"); + ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除"); + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭"); + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1_013_006_005, "满减送活动已结束,不能关闭"); + + // ========== TODO 空着 1-013-007-000 ============ + + // ========== 秒杀活动 1-013-008-000 ========== + ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在"); + ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_008_002, "存在商品参加了其它秒杀活动,秒杀时段冲突"); + ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_003, "秒杀活动已关闭,不能修改"); + ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除"); + ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭"); + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_008_006, "秒杀失败,原因:秒杀库存不足"); + ErrorCode SECKILL_JOIN_ACTIVITY_TIME_ERROR = new ErrorCode(1_013_008_007, "秒杀失败,原因:不在活动时间范围内"); + ErrorCode SECKILL_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_008_008, "秒杀失败,原因:秒杀活动已关闭"); + ErrorCode SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_008_009, "秒杀失败,原因:单次限购超出"); + ErrorCode SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_008_010, "秒杀失败,原因:商品不存在"); + + // ========== 秒杀时段 1-013-009-000 ========== + ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1_013_009_000, "秒杀时段不存在"); + ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1_013_009_001, "秒杀时段冲突"); + ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1_013_009_004, "秒杀时段已关闭"); + + // ========== 拼团活动 1-013-010-000 ========== + ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_010_000, "拼团活动不存在"); + ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_010_001, "存在商品参加了其它拼团活动"); + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1_013_010_002, "拼团活动已关闭不能修改"); + ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_010_003, "拼团活动未关闭或未结束,不能删除"); + ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_010_004, "拼团失败,原因:拼团活动已关闭"); + ErrorCode COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_010_005, "拼团失败,原因:拼团活动商品不存在"); + ErrorCode COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_010_006, "拼团失败,原因:拼团活动商品库存不足"); + + // ========== 拼团记录 1-013-011-000 ========== + ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1_013_011_000, "拼团不存在"); + ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1_013_011_001, "拼团失败,已参与过该拼团"); + ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_011_002, "拼团失败,父拼团不存在"); + ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1_013_011_003, "拼团失败,拼团人数已满"); + ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1_013_011_004, "拼团失败,原因:存在该活动正在进行的拼团记录"); + ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1_013_011_005, "拼团失败,活动未开始"); + ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_006, "拼团失败,活动已经结束"); + ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:单次限购超出"); + ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_008, "拼团失败,原因:超出总购买次数"); + ErrorCode COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID = new ErrorCode(1_013_011_009, "拼团失败,原因:存在未支付订单,请先支付"); + + // ========== 砍价活动 1-013-012-000 ========== + ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_012_000, "砍价活动不存在"); + ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_012_001, "存在商品参加了其它砍价活动"); + ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_012_002, "砍价活动已关闭,不能修改"); + ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_012_003, "砍价活动未关闭或未结束,不能删除"); + ErrorCode BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH = new ErrorCode(1_013_012_004, "砍价活动库存不足"); + ErrorCode BARGAIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_012_005, "砍价活动已关闭"); + ErrorCode BARGAIN_ACTIVITY_TIME_END = new ErrorCode(1_013_012_006, "砍价活动已经结束"); + + // ========== 砍价记录 1-013-013-000 ========== + ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1_013_013_000, "砍价记录不存在"); + ErrorCode BARGAIN_RECORD_CREATE_FAIL_EXISTS = new ErrorCode(1_013_013_001, "参与失败,您已经参与当前砍价活动"); + ErrorCode BARGAIN_RECORD_CREATE_FAIL_LIMIT = new ErrorCode(1_013_013_002, "参与失败,您已达到当前砍价活动的参与上限"); + ErrorCode BARGAIN_JOIN_RECORD_NOT_SUCCESS = new ErrorCode(1_013_013_004, "下单失败,砍价未成功"); + ErrorCode BARGAIN_JOIN_RECORD_ALREADY_ORDER = new ErrorCode(1_013_013_005, "下单失败,该砍价已经下单"); + + // ========== 砍价助力 1-013-014-000 ========== + ErrorCode BARGAIN_HELP_CREATE_FAIL_RECORD_NOT_IN_PROCESS = new ErrorCode(1_013_014_000, "助力失败,砍价记录不处于进行中"); + ErrorCode BARGAIN_HELP_CREATE_FAIL_RECORD_SELF = new ErrorCode(1_013_014_001, "助力失败,不能助力自己"); + ErrorCode BARGAIN_HELP_CREATE_FAIL_LIMIT = new ErrorCode(1_013_014_002, "助力失败,您已达到当前砍价活动的助力上限"); + ErrorCode BARGAIN_HELP_CREATE_FAIL_CONFLICT = new ErrorCode(1_013_014_003, "助力失败,请重试"); + ErrorCode BARGAIN_HELP_CREATE_FAIL_HELP_EXISTS = new ErrorCode(1_013_014_004, "助力失败,您已经助力过了"); + + // ========== 文章分类 1-013-015-000 ========== + ErrorCode ARTICLE_CATEGORY_NOT_EXISTS = new ErrorCode(1_013_015_000, "文章分类不存在"); + ErrorCode ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES = new ErrorCode(1_013_015_001, "文章分类删除失败,存在关联文章"); + + // ========== 文章管理 1-013-016-000 ========== + ErrorCode ARTICLE_NOT_EXISTS = new ErrorCode(1_013_016_000, "文章不存在"); + + // ========== 装修模板 1-013-017-000 ========== + ErrorCode DIY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_017_000, "装修模板不存在"); + ErrorCode DIY_TEMPLATE_NAME_USED = new ErrorCode(1_013_017_001, "装修模板名称({})已经被使用"); + ErrorCode DIY_TEMPLATE_USED_CANNOT_DELETE = new ErrorCode(1_013_017_002, "不能删除正在使用的装修模板"); + + // ========== 装修页面 1-013-018-000 ========== + ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在"); + ErrorCode DIY_PAGE_NAME_USED = new ErrorCode(1_013_018_001, "装修页面名称({})已经被使用"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java new file mode 100644 index 0000000..8a8338c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.enums.banner; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * Banner Position 枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum BannerPositionEnum implements IntArrayValuable { + + HOME_POSITION(1, "首页"), + SECKILL_POSITION(2, "秒杀活动页"), + COMBINATION_POSITION(3, "砍价活动页"), + DISCOUNT_POSITION(4, "限时折扣页"), + REWARD_POSITION(5, "满减送页"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BannerPositionEnum::getPosition).toArray(); + + /** + * 值 + */ + private final Integer position; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/bargain/BargainRecordStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/bargain/BargainRecordStatusEnum.java new file mode 100644 index 0000000..d5c22a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/bargain/BargainRecordStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.bargain; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 砍价记录的状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum BargainRecordStatusEnum implements IntArrayValuable { + + IN_PROGRESS(1, "砍价中"), + SUCCESS(2, "砍价成功"), + FAILED(3, "砍价失败"), // 活动到期时,会自动将到期的砍价全部设置为过期 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BargainRecordStatusEnum::getStatus).toArray(); + + /** + * 值 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java new file mode 100644 index 0000000..627e139 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.promotion.enums.combination; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 拼团状态枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum CombinationRecordStatusEnum implements IntArrayValuable { + + IN_PROGRESS(0, "进行中"), + SUCCESS(1, "拼团成功"), + FAILED(2, "拼团失败"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CombinationRecordStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isSuccess(Integer status) { + return ObjectUtil.equal(status, SUCCESS.getStatus()); + } + + public static boolean isInProgress(Integer status) { + return ObjectUtil.equal(status, IN_PROGRESS.getStatus()); + } + + public static boolean isFailed(Integer status) { + return ObjectUtil.equal(status, FAILED.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionActivityStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionActivityStatusEnum.java new file mode 100644 index 0000000..e45e37b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionActivityStatusEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +// TODO 芋艿:弱化这个状态 +/** + * 促销活动的状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum PromotionActivityStatusEnum implements IntArrayValuable { + + WAIT(10, "未开始"), + RUN(20, "进行中"), + END(30, "已结束"), + CLOSE(40, "已关闭"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionActivityStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionConditionTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionConditionTypeEnum.java new file mode 100644 index 0000000..05e62e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionConditionTypeEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.promotion.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 营销的条件类型枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum PromotionConditionTypeEnum implements IntArrayValuable { + + PRICE(10, "满 N 元"), + COUNT(20, "满 N 件"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionConditionTypeEnum::getType).toArray(); + + /** + * 类型值 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionDiscountTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionDiscountTypeEnum.java new file mode 100644 index 0000000..7da6b4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionDiscountTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PromotionDiscountTypeEnum implements IntArrayValuable { + + PRICE(1, "满减"), // 具体金额 + PERCENT(2, "折扣"), // 百分比 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionDiscountTypeEnum::getType).toArray(); + + /** + * 优惠类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java new file mode 100644 index 0000000..882dc4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 营销的商品范围枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PromotionProductScopeEnum implements IntArrayValuable { + + ALL(1, "通用券"), // 全部商品 + SPU(2, "商品券"), // 指定商品 + CATEGORY(3, "品类券"), // 指定品类 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray(); + + /** + * 范围值 + */ + private final Integer scope; + /** + * 范围名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java new file mode 100644 index 0000000..4524c19 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.promotion.enums.common; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 营销类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PromotionTypeEnum implements IntArrayValuable { + + SECKILL_ACTIVITY(1, "秒杀活动"), + BARGAIN_ACTIVITY(2, "砍价活动"), + COMBINATION_ACTIVITY(3, "拼团活动"), + + DISCOUNT_ACTIVITY(4, "限时折扣"), + REWARD_ACTIVITY(5, "满减送"), + + MEMBER_LEVEL(6, "会员折扣"), + COUPON(7, "优惠劵"), + POINT(8, "积分") + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionTypeEnum::getType).toArray(); + + /** + * 类型值 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java new file mode 100644 index 0000000..320345d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.coupon; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠劵状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CouponStatusEnum implements IntArrayValuable { + + UNUSED(1, "未使用"), + USED(2, "已使用"), + EXPIRE(3, "已过期"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray(); + + /** + * 值 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java new file mode 100644 index 0000000..1513e62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.enums.coupon; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠劵领取方式 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CouponTakeTypeEnum implements IntArrayValuable { + + USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 + ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 + REGISTER(3, "新人券"), // 注册时自动领取 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getValue).toArray(); + + /** + * 值 + */ + private final Integer value; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTemplateValidityTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTemplateValidityTypeEnum.java new file mode 100644 index 0000000..391515d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTemplateValidityTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.enums.coupon; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠劵模板的有限期类型的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CouponTemplateValidityTypeEnum implements IntArrayValuable { + + DATE(1, "固定日期"), + TERM(2, "领取之后"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTemplateValidityTypeEnum::getType).toArray(); + + /** + * 值 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/diy/DiyPageEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/diy/DiyPageEnum.java new file mode 100644 index 0000000..fa00ada --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/diy/DiyPageEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.diy; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 装修页面枚举 + * + * @author jason + */ +@AllArgsConstructor +@Getter +public enum DiyPageEnum implements IntArrayValuable { + + INDEX(1, "首页"), + MY(2, "我的"), + ; + + private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DiyPageEnum::getPage).toArray(); + + /** + * 页面编号 + */ + private final Integer page; + + /** + * 页面名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/pom.xml new file mode 100644 index 0000000..a3bf649 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/pom.xml @@ -0,0 +1,78 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + jar + yudao-module-promotion-biz + + ${project.artifactId} + + + promotion 模块,主要实现营销相关功能 + 例如:营销活动、banner 广告、优惠券、优惠码等功能。 + + + + + cn.iocoder.boot + yudao-module-promotion-api + ${revision} + + + cn.iocoder.boot + yudao-module-product-api + ${revision} + + + cn.iocoder.boot + yudao-module-trade-api + ${revision} + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java new file mode 100644 index 0000000..38b04fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.api.bargain; + +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 砍价活动 Api 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class BargainActivityApiImpl implements BargainActivityApi { + + @Resource + private BargainActivityService bargainActivityService; + + @Override + public void updateBargainActivityStock(Long id, Integer count) { + bargainActivityService.updateBargainActivityStock(id, count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java new file mode 100644 index 0000000..b3fba59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainRecordApiImpl.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.promotion.api.bargain; + +import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 砍价活动 API 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class BargainRecordApiImpl implements BargainRecordApi { + + @Resource + private BargainRecordService bargainRecordService; + + @Override + public BargainValidateJoinRespDTO validateJoinBargain(Long userId, Long bargainRecordId, Long skuId) { + return bargainRecordService.validateJoinBargain(userId, bargainRecordId, skuId); + } + + @Override + public void updateBargainRecordOrderId(Long id, Long orderId) { + bargainRecordService.updateBargainRecordOrderId(id, orderId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java new file mode 100644 index 0000000..dbf378c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.promotion.api.combination; + +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_RECORD_NOT_EXISTS; + +/** + * 拼团活动 API 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class CombinationRecordApiImpl implements CombinationRecordApi { + + @Resource + private CombinationRecordService combinationRecordService; + + @Override + public void validateCombinationRecord(Long userId, Long activityId, Long headId, Long skuId, Integer count) { + combinationRecordService.validateCombinationRecord(userId, activityId, headId, skuId, count); + } + + @Override + public CombinationRecordCreateRespDTO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { + return CombinationActivityConvert.INSTANCE.convert4(combinationRecordService.createCombinationRecord(reqDTO)); + } + + @Override + public boolean isCombinationRecordSuccess(Long userId, Long orderId) { + CombinationRecordDO record = combinationRecordService.getCombinationRecord(userId, orderId); + if (record == null) { + throw exception(COMBINATION_RECORD_NOT_EXISTS); + } + return CombinationRecordStatusEnum.isSuccess(record.getStatus()); + } + + @Override + public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) { + return combinationRecordService.validateJoinCombination(userId, activityId, headId, skuId, count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java new file mode 100644 index 0000000..9218a23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.promotion.api.coupon; + + +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 优惠劵 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CouponApiImpl implements CouponApi { + + @Resource + private CouponService couponService; + + @Override + public void useCoupon(CouponUseReqDTO useReqDTO) { + couponService.useCoupon(useReqDTO.getId(), useReqDTO.getUserId(), + useReqDTO.getOrderId()); + } + + @Override + public void returnUsedCoupon(Long id) { + couponService.returnUsedCoupon(id); + } + + @Override + public CouponRespDTO validateCoupon(CouponValidReqDTO validReqDTO) { + CouponDO coupon = couponService.validCoupon(validReqDTO.getId(), validReqDTO.getUserId()); + return CouponConvert.INSTANCE.convert(coupon); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java new file mode 100644 index 0000000..3ce5204 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.api.discount; + +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 限时折扣 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DiscountActivityApiImpl implements DiscountActivityApi { + + @Resource + private DiscountActivityService discountActivityService; + + @Override + public List getMatchDiscountProductList(Collection skuIds) { + return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java new file mode 100644 index 0000000..3aba954 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.api.reward; + +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 满减送活动 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class RewardActivityApiImpl implements RewardActivityApi { + + @Resource + private RewardActivityService rewardActivityService; + + @Override + public List getMatchRewardActivityList(Collection spuIds) { + return rewardActivityService.getMatchRewardActivityList(spuIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java new file mode 100644 index 0000000..24093ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.promotion.api.seckill; + +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 秒杀活动接口 Api 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class SeckillActivityApiImpl implements SeckillActivityApi { + + @Resource + private SeckillActivityService activityService; + + @Override + public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { + activityService.updateSeckillStockDecr(id, skuId, count); + } + + @Override + public void updateSeckillStockIncr(Long id, Long skuId, Integer count) { + activityService.updateSeckillStockIncr(id, skuId, count); + } + + @Override + public SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count) { + return activityService.validateJoinSeckill(activityId, skuId, count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleCategoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleCategoryController.java new file mode 100644 index 0000000..245e695 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleCategoryController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.*; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleCategoryConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import cn.iocoder.yudao.module.promotion.service.article.ArticleCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 文章分类") +@RestController +@RequestMapping("/promotion/article-category") +@Validated +public class ArticleCategoryController { + + @Resource + private ArticleCategoryService articleCategoryService; + + @PostMapping("/create") + @Operation(summary = "创建文章分类") + @PreAuthorize("@ss.hasPermission('promotion:article-category:create')") + public CommonResult createArticleCategory(@Valid @RequestBody ArticleCategoryCreateReqVO createReqVO) { + return success(articleCategoryService.createArticleCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新文章分类") + @PreAuthorize("@ss.hasPermission('promotion:article-category:update')") + public CommonResult updateArticleCategory(@Valid @RequestBody ArticleCategoryUpdateReqVO updateReqVO) { + articleCategoryService.updateArticleCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文章分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:article-category:delete')") + public CommonResult deleteArticleCategory(@RequestParam("id") Long id) { + articleCategoryService.deleteArticleCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得文章分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:article-category:query')") + public CommonResult getArticleCategory(@RequestParam("id") Long id) { + ArticleCategoryDO category = articleCategoryService.getArticleCategory(id); + return success(ArticleCategoryConvert.INSTANCE.convert(category)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取文章分类精简信息列表", description = "只包含被开启的文章分类,主要用于前端的下拉选项") + public CommonResult> getSimpleDeptList() { + // 获得分类列表,只要开启状态的 + List list = articleCategoryService.getArticleCategoryListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 降序排序后,返回给前端 + list.sort(Comparator.comparing(ArticleCategoryDO::getSort).reversed()); + return success(ArticleCategoryConvert.INSTANCE.convertList03(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得文章分类分页") + @PreAuthorize("@ss.hasPermission('promotion:article-category:query')") + public CommonResult> getArticleCategoryPage(@Valid ArticleCategoryPageReqVO pageVO) { + PageResult pageResult = articleCategoryService.getArticleCategoryPage(pageVO); + return success(ArticleCategoryConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleController.java new file mode 100644 index 0000000..f6dea04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/ArticleController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import cn.iocoder.yudao.module.promotion.service.article.ArticleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 文章管理") +@RestController +@RequestMapping("/promotion/article") +@Validated +public class ArticleController { + + @Resource + private ArticleService articleService; + + @PostMapping("/create") + @Operation(summary = "创建文章管理") + @PreAuthorize("@ss.hasPermission('promotion:article:create')") + public CommonResult createArticle(@Valid @RequestBody ArticleCreateReqVO createReqVO) { + return success(articleService.createArticle(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新文章管理") + @PreAuthorize("@ss.hasPermission('promotion:article:update')") + public CommonResult updateArticle(@Valid @RequestBody ArticleUpdateReqVO updateReqVO) { + articleService.updateArticle(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除文章管理") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:article:delete')") + public CommonResult deleteArticle(@RequestParam("id") Long id) { + articleService.deleteArticle(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得文章管理") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:article:query')") + public CommonResult getArticle(@RequestParam("id") Long id) { + ArticleDO article = articleService.getArticle(id); + return success(ArticleConvert.INSTANCE.convert(article)); + } + + @GetMapping("/page") + @Operation(summary = "获得文章管理分页") + @PreAuthorize("@ss.hasPermission('promotion:article:query')") + public CommonResult> getArticlePage(@Valid ArticlePageReqVO pageVO) { + PageResult pageResult = articleService.getArticlePage(pageVO); + return success(ArticleConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleBaseVO.java new file mode 100644 index 0000000..4c07e86 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleBaseVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 文章管理 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class ArticleBaseVO { + + @Schema(description = "文章分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15458") + @NotNull(message = "文章分类编号不能为空") + private Long categoryId; + + @Schema(description = "关联商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22378") + @NotNull(message = "关联商品不能为空") + private Long spuId; + + @Schema(description = "文章标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "这是一个标题") + @NotNull(message = "文章标题不能为空") + private String title; + + @Schema(description = "文章作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String author; + + @Schema(description = "文章封面图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + @NotNull(message = "文章封面图片地址不能为空") + private String picUrl; + + @Schema(description = "文章简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "这是一个简介") + private String introduction; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否热门(小程序)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否热门(小程序)不能为空") + private Boolean recommendHot; + + @Schema(description = "是否轮播图(小程序)", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否轮播图(小程序)不能为空") + private Boolean recommendBanner; + + @Schema(description = "文章内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "这是文章内容") + @NotNull(message = "文章内容不能为空") + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleCreateReqVO.java new file mode 100644 index 0000000..d598dd7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 文章管理创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleCreateReqVO extends ArticleBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticlePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticlePageReqVO.java new file mode 100644 index 0000000..9c75395 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticlePageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文章管理分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticlePageReqVO extends PageParam { + + @Schema(description = "文章分类编号", example = "15458") + private Long categoryId; + + @Schema(description = "关联商品编号", example = "22378") + private Long spuId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章作者") + private String author; + + @Schema(description = "状态", example = "2") + private Integer status; + + @Schema(description = "是否热门(小程序)") + private Boolean recommendHot; + + @Schema(description = "是否轮播图(小程序)") + private Boolean recommendBanner; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleRespVO.java new file mode 100644 index 0000000..3f9281a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文章管理 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleRespVO extends ArticleBaseVO { + + @Schema(description = "文章编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8606") + private Long id; + + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "99999") + private Integer browseCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleUpdateReqVO.java new file mode 100644 index 0000000..3efd593 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/article/ArticleUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 文章管理更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleUpdateReqVO extends ArticleBaseVO { + + @Schema(description = "文章编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8606") + @NotNull(message = "文章编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryBaseVO.java new file mode 100644 index 0000000..42bf116 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryBaseVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 文章分类 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class ArticleCategoryBaseVO { + + @Schema(description = "文章分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "秒杀") + @NotNull(message = "文章分类名称不能为空") + private String name; + + @Schema(description = "图标地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private String picUrl; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "排序不能为空") + private Integer sort; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryCreateReqVO.java new file mode 100644 index 0000000..a8dc1f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 文章分类创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleCategoryCreateReqVO extends ArticleCategoryBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryPageReqVO.java new file mode 100644 index 0000000..b161aae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 文章分类分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleCategoryPageReqVO extends PageParam { + + @Schema(description = "文章分类名称", example = "秒杀") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryRespVO.java new file mode 100644 index 0000000..af4b045 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 文章分类 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleCategoryRespVO extends ArticleCategoryBaseVO { + + @Schema(description = "文章分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19490") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategorySimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategorySimpleRespVO.java new file mode 100644 index 0000000..4e43326 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategorySimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 文章分类精简信息 Response VO") +@Data +public class ArticleCategorySimpleRespVO { + + @Schema(description = "文章分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19490") + private Long id; + + @Schema(description = "文章分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "秒杀") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryUpdateReqVO.java new file mode 100644 index 0000000..72a1b35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/article/vo/category/ArticleCategoryUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 文章分类更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ArticleCategoryUpdateReqVO extends ArticleCategoryBaseVO { + + @Schema(description = "文章分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19490") + @NotNull(message = "文章分类编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/BannerController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/BannerController.java new file mode 100644 index 0000000..8b6dae9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/BannerController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.banner.BannerConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import cn.iocoder.yudao.module.promotion.service.banner.BannerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - Banner 管理") +@RestController +@RequestMapping("/promotion/banner") +@Validated +public class BannerController { + + @Resource + private BannerService bannerService; + + @PostMapping("/create") + @Operation(summary = "创建 Banner") + @PreAuthorize("@ss.hasPermission('promotion:banner:create')") + public CommonResult createBanner(@Valid @RequestBody BannerCreateReqVO createReqVO) { + return success(bannerService.createBanner(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新 Banner") + @PreAuthorize("@ss.hasPermission('promotion:banner:update')") + public CommonResult updateBanner(@Valid @RequestBody BannerUpdateReqVO updateReqVO) { + bannerService.updateBanner(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除 Banner") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:banner:delete')") + public CommonResult deleteBanner(@RequestParam("id") Long id) { + bannerService.deleteBanner(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得 Banner") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:banner:query')") + public CommonResult getBanner(@RequestParam("id") Long id) { + BannerDO banner = bannerService.getBanner(id); + return success(BannerConvert.INSTANCE.convert(banner)); + } + + @GetMapping("/page") + @Operation(summary = "获得 Banner 分页") + @PreAuthorize("@ss.hasPermission('promotion:banner:query')") + public CommonResult> getBannerPage(@Valid BannerPageReqVO pageVO) { + PageResult pageResult = bannerService.getBannerPage(pageVO); + return success(BannerConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java new file mode 100644 index 0000000..0818257 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner.vo; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.banner.BannerPositionEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * Banner Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * @author xia + */ +@Data +public class BannerBaseVO { + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "标题不能为空") + private String title; + + @Schema(description = "跳转链接", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "跳转链接不能为空") + private String url; + + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "图片地址不能为空") + private String picUrl; + + @Schema(description = "position", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "position 不能为空") + @InEnum(BannerPositionEnum.class) + private Integer position; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "备注") + private String memo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerCreateReqVO.java new file mode 100644 index 0000000..180cdfe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerCreateReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * @author xia + */ +@Schema(description = "管理后台 - Banner 创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BannerCreateReqVO extends BannerBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java new file mode 100644 index 0000000..c2ac49d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner.vo; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - Banner 分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BannerPageReqVO extends PageParam { + + @Schema(description = "标题", example = "这是一个标题") + private String title; + + @Schema(description = "状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerRespVO.java new file mode 100644 index 0000000..2eee606 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - Banner Response VO") +@Data +@ToString(callSuper = true) +public class BannerRespVO extends BannerBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerUpdateReqVO.java new file mode 100644 index 0000000..266f28c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerUpdateReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.banner.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +/** + * @author xia + */ +@Schema(description = "管理后台 - Banner更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BannerUpdateReqVO extends BannerBaseVO { + + @Schema(description = "banner 编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "banner 编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java new file mode 100644 index 0000000..076a795 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.*; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainHelpService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 砍价活动") +@RestController +@RequestMapping("/promotion/bargain-activity") +@Validated +public class BargainActivityController { + + @Resource + private BargainActivityService bargainActivityService; + @Resource + private BargainRecordService bargainRecordService; + @Resource + private BargainHelpService bargainHelpService; + + @Resource + private ProductSpuApi spuApi; + + @PostMapping("/create") + @Operation(summary = "创建砍价活动") + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:create')") + public CommonResult createBargainActivity(@Valid @RequestBody BargainActivityCreateReqVO createReqVO) { + return success(bargainActivityService.createBargainActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新砍价活动") + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:update')") + public CommonResult updateBargainActivity(@Valid @RequestBody BargainActivityUpdateReqVO updateReqVO) { + bargainActivityService.updateBargainActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @Operation(summary = "关闭砍价活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:close')") + public CommonResult closeSeckillActivity(@RequestParam("id") Long id) { + bargainActivityService.closeBargainActivityById(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除砍价活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:delete')") + public CommonResult deleteBargainActivity(@RequestParam("id") Long id) { + bargainActivityService.deleteBargainActivity(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得砍价活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')") + public CommonResult getBargainActivity(@RequestParam("id") Long id) { + return success(BargainActivityConvert.INSTANCE.convert(bargainActivityService.getBargainActivity(id))); + } + + @GetMapping("/page") + @Operation(summary = "获得砍价活动分页") + @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')") + public CommonResult> getBargainActivityPage( + @Valid BargainActivityPageReqVO pageVO) { + // 查询砍价活动 + PageResult pageResult = bargainActivityService.getBargainActivityPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + List spuList = spuApi.getSpuList(convertList(pageResult.getList(), BargainActivityDO::getSpuId)); + // 统计数据 + Collection activityIds = convertList(pageResult.getList(), BargainActivityDO::getId); + Map recordUserCountMap = bargainRecordService.getBargainRecordUserCountMap(activityIds, null); + Map recordSuccessUserCountMap = bargainRecordService.getBargainRecordUserCountMap(activityIds, + BargainRecordStatusEnum.SUCCESS.getStatus()); + Map helpUserCountMap = bargainHelpService.getBargainHelpUserCountMapByActivity(activityIds); + return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, spuList, + recordUserCountMap, recordSuccessUserCountMap, helpUserCountMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainHelpController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainHelpController.java new file mode 100644 index 0000000..14265e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainHelpController.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpRespVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainHelpConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainHelpService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 砍价助力") +@RestController +@RequestMapping("/promotion/bargain-help") +@Validated +public class BargainHelpController { + + @Resource + private BargainHelpService bargainHelpService; + + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/page") + @Operation(summary = "获得砍价助力分页") + @PreAuthorize("@ss.hasPermission('promotion:bargain-help:query')") + public CommonResult> getBargainHelpPage(@Valid BargainHelpPageReqVO pageVO) { + PageResult pageResult = bargainHelpService.getBargainHelpPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + Map userMap = memberUserApi.getUserMap( + convertSet(pageResult.getList(), BargainHelpDO::getUserId)); + return success(BargainHelpConvert.INSTANCE.convertPage(pageResult, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainRecordController.java new file mode 100644 index 0000000..69781b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainRecordController.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainRecordConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainHelpService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 砍价记录") +@RestController +@RequestMapping("/promotion/bargain-record") +@Validated +public class BargainRecordController { + + @Resource + private BargainRecordService bargainRecordService; + @Resource + private BargainActivityService bargainActivityService; + @Resource + private BargainHelpService bargainHelpService; + + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/page") + @Operation(summary = "获得砍价记录分页") + @PreAuthorize("@ss.hasPermission('promotion:bargain-record:query')") + public CommonResult> getBargainRecordPage(@Valid BargainRecordPageReqVO pageVO) { + PageResult pageResult = bargainRecordService.getBargainRecordPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + Map userMap = memberUserApi.getUserMap( + convertSet(pageResult.getList(), BargainRecordDO::getUserId)); + List activityList = bargainActivityService.getBargainActivityList( + convertSet(pageResult.getList(), BargainRecordDO::getActivityId)); + Map helpCountMap = bargainHelpService.getBargainHelpUserCountMapByRecord( + convertSet(pageResult.getList(), BargainRecordDO::getId)); + return success(BargainRecordConvert.INSTANCE.convertPage(pageResult, helpCountMap, activityList, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityBaseVO.java new file mode 100644 index 0000000..9f7113f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityBaseVO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 砍价活动 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class BargainActivityBaseVO { + + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "砍得越多省得越多,是兄弟就来砍我") + @NotNull(message = "砍价名称不能为空") + private String name; + + @Schema(description = "商品 SPU 编号", example = "1") + @NotNull(message = "砍价商品不能为空") + private Long spuId; + + @Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + @NotNull(message = "商品 skuId 不能为空") + private Long skuId; + + @Schema(description = "砍价起始价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + @NotNull(message = "砍价起始价格不能为空") + private Integer bargainFirstPrice; + + @Schema(description = "砍价底价", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + @NotNull(message = "砍价底价不能为空") + private Integer bargainMinPrice; + + @Schema(description = "活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + @NotNull(message = "活动库存不能为空") + private Integer stock; + + @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218") + @NotNull(message = "总限购数量不能为空") + private Integer totalLimitCount; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]") + @NotNull(message = "活动开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]") + @NotNull(message = "活动结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "最大助力次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") + @NotNull(message = "最大助力次数不能为空") + private Integer helpMaxCount; + + @Schema(description = "最大帮砍次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") + @NotNull(message = "最大帮砍次数不能为空") + private Integer bargainCount; + + @Schema(description = "用户每次砍价的最小金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") + @NotNull(message = "用户每次砍价的最小金额不能为空") + private Integer randomMinPrice; + + @Schema(description = "用户每次砍价的最大金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") + @NotNull(message = "用户每次砍价的最大金额不能为空") + private Integer randomMaxPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityCreateReqVO.java new file mode 100644 index 0000000..83cb5ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 砍价活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainActivityCreateReqVO extends BargainActivityBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageItemRespVO.java new file mode 100644 index 0000000..721a31c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageItemRespVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 砍价活动的分页项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainActivityPageItemRespVO extends BargainActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long id; + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") + private String spuName; + @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "活动状态不能为空") + private Integer status; + + @Schema(description = "活动总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + private Integer totalStock; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59") + private LocalDateTime createTime; + + // ========== 统计字段 ========== + + @Schema(description = "总砍价的用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "999") + private Integer recordUserCount; + + @Schema(description = "成功砍价的用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "500") + private Integer recordSuccessUserCount; + + @Schema(description = "帮助砍价的用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Integer helpUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageReqVO.java new file mode 100644 index 0000000..66f2373 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 砍价活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainActivityPageReqVO extends PageParam { + + @Schema(description = "砍价名称", example = "赵六") + private String name; + + @Schema(description = "活动状态", example = "0") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityRespVO.java new file mode 100644 index 0000000..0295fdd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +@Schema(description = "管理后台 - 砍价活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainActivityRespVO extends BargainActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long id; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityUpdateReqVO.java new file mode 100644 index 0000000..b747029 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 砍价活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainActivityUpdateReqVO extends BargainActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + @NotNull(message = "活动编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpBaseVO.java new file mode 100644 index 0000000..41dd1c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpBaseVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 砍价助力 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BargainHelpBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5402") + private Long userId; + + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "16825") + private Long activityId; + + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1800") + private Long recordId; + + @Schema(description = "减少砍价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "32300") + private Integer reducePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpPageReqVO.java new file mode 100644 index 0000000..8afbe3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpPageReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 砍价助力分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainHelpPageReqVO extends PageParam { + + @Schema(description = "砍价记录编号", example = "1800") + private Long recordId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpRespVO.java new file mode 100644 index 0000000..ba07c59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/help/BargainHelpRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 砍价助力 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainHelpRespVO extends BargainHelpBaseVO { + + @Schema(description = "砍价助力编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25860") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 用户相关 ========== + + @Schema(description = "用户昵称", example = "老芋艿") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordBaseVO.java new file mode 100644 index 0000000..31650f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordBaseVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 砍价记录 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BargainRecordBaseVO { + + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "22690") + @NotNull(message = "砍价活动名称不能为空") + private Long activityId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9430") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23622") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29950") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "砍价起始价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "31160") + @NotNull(message = "砍价起始价格,单位:分不能为空") + private Integer bargainFirstPrice; + + @Schema(description = "当前砍价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22743") + @NotNull(message = "当前砍价,单位:分不能为空") + private Integer bargainPrice; + + @Schema(description = "砍价状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "砍价状态不能为空") + private Integer status; + + @Schema(description = "订单编号", example = "27845") + private Long orderId; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageItemRespVO.java new file mode 100644 index 0000000..608ed30 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageItemRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod; + +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 砍价记录的分页项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainRecordPageItemRespVO extends BargainRecordBaseVO { + + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59") + private LocalDateTime createTime; + + @Schema(description = "帮砍次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer helpCount; + + // ========== 用户相关 ========== + + @Schema(description = "用户昵称", example = "老芋艿") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + // ========== 活动相关 ========== + + private BargainActivityRespVO activity; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageReqVO.java new file mode 100644 index 0000000..47b6718 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/recrod/BargainRecordPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 砍价记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BargainRecordPageReqVO extends PageParam { + + @Schema(description = "砍价状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java new file mode 100644 index 0000000..7d442b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.*; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.hutool.core.collection.CollectionUtil.newArrayList; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 拼团活动") +@RestController +@RequestMapping("/promotion/combination-activity") +@Validated +public class CombinationActivityController { + + @Resource + private CombinationActivityService combinationActivityService; + @Resource + private CombinationRecordService combinationRecordService; + + @Resource + private ProductSpuApi productSpuApi; + + @PostMapping("/create") + @Operation(summary = "创建拼团活动") + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:create')") + public CommonResult createCombinationActivity(@Valid @RequestBody CombinationActivityCreateReqVO createReqVO) { + return success(combinationActivityService.createCombinationActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新拼团活动") + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:update')") + public CommonResult updateCombinationActivity(@Valid @RequestBody CombinationActivityUpdateReqVO updateReqVO) { + combinationActivityService.updateCombinationActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @Operation(summary = "关闭拼团活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:close')") + public CommonResult closeCombinationActivity(@RequestParam("id") Long id) { + combinationActivityService.closeCombinationActivityById(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除拼团活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:delete')") + public CommonResult deleteCombinationActivity(@RequestParam("id") Long id) { + combinationActivityService.deleteCombinationActivity(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得拼团活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')") + public CommonResult getCombinationActivity(@RequestParam("id") Long id) { + CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id); + List products = combinationActivityService.getCombinationProductListByActivityIds(newArrayList(id)); + return success(CombinationActivityConvert.INSTANCE.convert(activity, products)); + } + + @GetMapping("/page") + @Operation(summary = "获得拼团活动分页") + @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')") + public CommonResult> getCombinationActivityPage( + @Valid CombinationActivityPageReqVO pageVO) { + // 查询拼团活动 + PageResult pageResult = combinationActivityService.getCombinationActivityPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 统计数据 + Set activityIds = convertSet(pageResult.getList(), CombinationActivityDO::getId); + Map groupCountMap = combinationRecordService.getCombinationRecordCountMapByActivity( + activityIds, null, CombinationRecordDO.HEAD_ID_GROUP); + Map groupSuccessCountMap = combinationRecordService.getCombinationRecordCountMapByActivity( + activityIds, CombinationRecordStatusEnum.SUCCESS.getStatus(), CombinationRecordDO.HEAD_ID_GROUP); + Map recordCountMap = combinationRecordService.getCombinationRecordCountMapByActivity( + activityIds, null, null); + // 拼接数据 + List products = combinationActivityService.getCombinationProductListByActivityIds( + convertSet(pageResult.getList(), CombinationActivityDO::getId)); + List spus = productSpuApi.getSpuList( + convertSet(pageResult.getList(), CombinationActivityDO::getSpuId)); + return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, + groupCountMap, groupSuccessCountMap, recordCountMap, spus)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationRecordController.java new file mode 100644 index 0000000..45ad4e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationRecordController.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordSummaryVO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 拼团记录") +@RestController +@RequestMapping("/promotion/combination-record") +@Validated +public class CombinationRecordController { + + @Resource + private CombinationActivityService combinationActivityService; + @Resource + @Lazy + private CombinationRecordService combinationRecordService; + + @GetMapping("/page") + @Operation(summary = "获得拼团记录分页") + @PreAuthorize("@ss.hasPermission('promotion:combination-record:query')") + public CommonResult> getCombinationRecordPage( + @Valid CombinationRecordReqPageVO pageVO) { + PageResult recordPage = combinationRecordService.getCombinationRecordPage(pageVO); + // 拼接数据 + List activities = combinationActivityService.getCombinationActivityListByIds( + convertSet(recordPage.getList(), CombinationRecordDO::getActivityId)); + List products = combinationActivityService.getCombinationProductListByActivityIds( + convertSet(recordPage.getList(), CombinationRecordDO::getActivityId)); + return success(CombinationActivityConvert.INSTANCE.convert(recordPage, activities, products)); + } + + @GetMapping("/get-summary") + @Operation(summary = "获得拼团记录的概要信息", description = "用于拼团记录页面展示") + @PreAuthorize("@ss.hasPermission('promotion:combination-record:query')") + public CommonResult getCombinationRecordSummary() { + CombinationRecordSummaryVO summaryVO = new CombinationRecordSummaryVO(); + summaryVO.setUserCount(combinationRecordService.getCombinationUserCount()); // 获取拼团用户参与数量 + summaryVO.setSuccessCount(combinationRecordService.getCombinationRecordCount( // 获取成团记录 + CombinationRecordStatusEnum.SUCCESS.getStatus(), null, CombinationRecordDO.HEAD_ID_GROUP)); + summaryVO.setVirtualGroupCount(combinationRecordService.getCombinationRecordCount(// 获取虚拟成团记录 + null, Boolean.TRUE, CombinationRecordDO.HEAD_ID_GROUP)); + return success(summaryVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java new file mode 100644 index 0000000..4b3abea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 拼团活动 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class CombinationActivityBaseVO { + + @Schema(description = "拼团名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱") + @NotNull(message = "拼团名称不能为空") + private String name; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "拼团商品不能为空") + private Long spuId; + + @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218") + @NotNull(message = "总限购数量不能为空") + private Integer totalLimitCount; + + @Schema(description = "单次限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "28265") + @NotNull(message = "单次限购数量不能为空") + private Integer singleLimitCount; + + @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]") + @NotNull(message = "活动时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]") + @NotNull(message = "活动时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222") + @NotNull(message = "开团人数不能为空") + private Integer userSize; + + @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "虚拟成团不能为空") + private Boolean virtualGroup; + + @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "限制时长不能为空") + private Integer limitDuration; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java new file mode 100644 index 0000000..dff1a6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import java.util.List; + +@Schema(description = "管理后台 - 拼团活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO { + + @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageItemRespVO.java new file mode 100644 index 0000000..0151adf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageItemRespVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 拼团活动的分页项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationActivityPageItemRespVO extends CombinationActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + + // ========== 商品字段 ========== + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取 + example = "618大促") + private String spuName; + @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "https://www.iocoder.cn/xx.png") + private String picUrl; + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取 + example = "50") + private Integer marketPrice; + + // ========== 统计字段 ========== + + @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "33") + private Integer groupCount; + + @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer groupSuccessCount; + + @Schema(description = "购买次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer recordCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java new file mode 100644 index 0000000..bfb54b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 拼团活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationActivityPageReqVO extends PageParam { + + @Schema(description = "拼团名称", example = "赵六") + private String name; + + @Schema(description = "活动状态", example = "0") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java new file mode 100644 index 0000000..0ac77c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 拼团活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationActivityRespVO extends CombinationActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Integer userSize; + + @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java new file mode 100644 index 0000000..f4483ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 拼团活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationActivityUpdateReqVO extends CombinationActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + @NotNull(message = "活动编号不能为空") + private Long id; + + @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java new file mode 100644 index 0000000..452fb38 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 拼团商品 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class CombinationProductBaseVO { + + @Schema(description = "商品 spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") + @NotNull(message = "商品 spuId 不能为空") + private Long spuId; + + @Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") + @NotNull(message = "商品 skuId 不能为空") + private Long skuId; + + @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682") + @NotNull(message = "拼团价格不能为空") + private Integer combinationPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java new file mode 100644 index 0000000..02bcc07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 拼团商品分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationProductPageReqVO extends PageParam { + + @Schema(description = "拼团活动编号", example = "6829") + private Long activityId; + + @Schema(description = "商品 SPU 编号", example = "18731") + private Long spuId; + + @Schema(description = "商品 SKU 编号", example = "31675") + private Long skuId; + + @Schema(description = "拼团商品状态", example = "2") + private Integer activityStatus; + + @Schema(description = "活动开始时间点") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] activityStartTime; + + @Schema(description = "活动结束时间点") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] activityEndTime; + + @Schema(description = "拼团价格,单位分", example = "27682") + private Integer activePrice; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java new file mode 100644 index 0000000..eeac5c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 拼团商品 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationProductRespVO extends CombinationProductBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28322") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordBaseVO.java new file mode 100644 index 0000000..18c754d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordBaseVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 拼团记录 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class CombinationRecordBaseVO { + + @Schema(description = "拼团记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "拼团活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long activityId; + + @Schema(description = "团长编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long headId; + + // ========== 用户相关 ========== + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9430") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "用户昵称", example = "老芋艿") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + // ========== 商品相关 ========== + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23622") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29950") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "商品名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是大黄豆") + private String spuName; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime expireTime; + + @Schema(description = "可参团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer userSize; + + @Schema(description = "已参团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer userCount; + + @Schema(description = "拼团状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "是否虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean virtualGroup; + + @Schema(description = "开始时间 (订单付款后开始的时间)", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "结束时间(成团时间/失败时间)", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordPageItemRespVO.java new file mode 100644 index 0000000..7b1b10b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordPageItemRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod; + +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 拼团记录的分页项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationRecordPageItemRespVO extends CombinationRecordBaseVO { + + // ========== 活动相关 ========== + + private CombinationActivityRespVO activity; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPage2VO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPage2VO.java new file mode 100644 index 0000000..9e6fe91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPage2VO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 拼团记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationRecordReqPage2VO extends PageParam { + + @Schema(description = "团长编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "团长编号不能为空") + private Long headId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPageVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPageVO.java new file mode 100644 index 0000000..a66795d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPageVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 拼团记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CombinationRecordReqPageVO extends PageParam { + + @Schema(description = "活动状态", example = "1") + @InEnum(BargainRecordStatusEnum.class) + private Integer status; + + @Schema(description = "团长编号", example = "1024") + private Long headId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordSummaryVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordSummaryVO.java new file mode 100644 index 0000000..64d63af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordSummaryVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 拼团记录信息统计 Response VO") +@Data +public class CombinationRecordSummaryVO { + + @Schema(description = "所有拼团记录", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userCount; + + @Schema(description = "成团记录", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long successCount; + + @Schema(description = "虚拟成团记录", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long virtualGroupCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java new file mode 100644 index 0000000..8e0a9bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponSendReqVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 优惠劵") +@RestController +@RequestMapping("/promotion/coupon") +@Validated +public class CouponController { + + @Resource + private CouponService couponService; + @Resource + private MemberUserApi memberUserApi; + + @DeleteMapping("/delete") + @Operation(summary = "回收优惠劵") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:coupon:delete')") + public CommonResult deleteCoupon(@RequestParam("id") Long id) { + couponService.deleteCoupon(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得优惠劵分页") + @PreAuthorize("@ss.hasPermission('promotion:coupon:query')") + public CommonResult> getCouponPage(@Valid CouponPageReqVO pageVO) { + PageResult pageResult = couponService.getCouponPage(pageVO); + PageResult pageResulVO = CouponConvert.INSTANCE.convertPage(pageResult); + if (CollUtil.isEmpty(pageResulVO.getList())) { + return success(pageResulVO); + } + + // 读取用户信息,进行拼接 + Map userMap = memberUserApi.getUserMap(convertSet(pageResult.getList(), CouponDO::getUserId)); + pageResulVO.getList().forEach(itemRespVO -> MapUtils.findAndThen(userMap, itemRespVO.getUserId(), + userRespDTO -> itemRespVO.setNickname(userRespDTO.getNickname()))); + return success(pageResulVO); + } + + @PostMapping("/send") + @Operation(summary = "发送优惠劵") + @PreAuthorize("@ss.hasPermission('promotion:coupon:send')") + public CommonResult sendCoupon(@Valid @RequestBody CouponSendReqVO reqVO) { + couponService.takeCouponByAdmin(reqVO.getTemplateId(), reqVO.getUserIds()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java new file mode 100644 index 0000000..271d711 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.*; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 优惠劵模板") +@RestController +@RequestMapping("/promotion/coupon-template") +@Validated +public class CouponTemplateController { + + @Resource + private CouponTemplateService couponTemplateService; + + @PostMapping("/create") + @Operation(summary = "创建优惠劵模板") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:create')") + public CommonResult createCouponTemplate(@Valid @RequestBody CouponTemplateCreateReqVO createReqVO) { + return success(couponTemplateService.createCouponTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新优惠劵模板") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:update')") + public CommonResult updateCouponTemplate(@Valid @RequestBody CouponTemplateUpdateReqVO updateReqVO) { + couponTemplateService.updateCouponTemplate(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新优惠劵模板状态") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:update')") + public CommonResult updateCouponTemplateStatus(@Valid @RequestBody CouponTemplateUpdateStatusReqVO reqVO) { + couponTemplateService.updateCouponTemplateStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除优惠劵模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:delete')") + public CommonResult deleteCouponTemplate(@RequestParam("id") Long id) { + couponTemplateService.deleteCouponTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得优惠劵模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") + public CommonResult getCouponTemplate(@RequestParam("id") Long id) { + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(id); + return success(CouponTemplateConvert.INSTANCE.convert(couponTemplate)); + } + + @GetMapping("/page") + @Operation(summary = "获得优惠劵模板分页") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") + public CommonResult> getCouponTemplatePage(@Valid CouponTemplatePageReqVO pageVO) { + PageResult pageResult = couponTemplateService.getCouponTemplatePage(pageVO); + return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/list") + @Operation(summary = "获得优惠劵模板列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") + public CommonResult> getCouponTemplateList(@RequestParam("ids") Collection ids) { + List list = couponTemplateService.getCouponTemplateList(ids); + return success(CouponTemplateConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java new file mode 100644 index 0000000..0d74598 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** +* 优惠劵 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class CouponBaseVO { + + // ========== 基本信息 BEGIN ========== + @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Long templateId; + + @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") + @NotNull(message = "优惠劵名不能为空") + private String name; + + @Schema(description = "优惠码状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + // ========== 基本信息 END ========== + + // ========== 领取情况 BEGIN ========== + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "领取方式不能为空") + private Integer takeType; + // ========== 领取情况 END ========== + + // ========== 使用规则 BEGIN ========== + @Schema(description = "是否设置满多少金额可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 单位:分;0 - 不限制 + @NotNull(message = "是否设置满多少金额可用不能为空") + private Integer usePrice; + + @Schema(description = "固定日期 - 生效开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime validStartTime; + + @Schema(description = "固定日期 - 生效结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime validEndTime; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品范围不能为空") + @InEnum(PromotionProductScopeEnum.class) + private Integer productScope; + + @Schema(description = "商品范围编号的数组", example = "1,3") + private List productScopeValues; + // ========== 使用规则 END ========== + + // ========== 使用效果 BEGIN ========== + @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "优惠类型不能为空") + @InEnum(PromotionDiscountTypeEnum.class) + private Integer discountType; + + @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 + private Integer discountPercent; + + @Schema(description = "优惠金额", example = "10") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 + private Integer discountLimitPrice; + // ========== 使用效果 END ========== + + // ========== 使用情况 BEGIN ========== + + @Schema(description = "使用订单号", example = "4096") + private Long useOrderId; + + @Schema(description = "使用时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime useTime; + + // ========== 使用情况 END ========== + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java new file mode 100644 index 0000000..118736e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 优惠劵分页的每一项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponPageItemRespVO extends CouponRespVO { + + @Schema(description = "用户昵称", example = "老芋艿") + private String nickname; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java new file mode 100644 index 0000000..75aa2f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.Collection; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 优惠劵分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponPageReqVO extends PageParam { + + @Schema(description = "优惠劵模板编号", example = "2048") + private Long templateId; + + @Schema(description = "优惠码状态", example = "1") + @InEnum(value = CouponStatusEnum.class, message = "优惠劵状态,必须是 {value}") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "用户昵称", example = "芋艿") + private String nickname; + + @Schema(description = "用户编号", example = "1") + private Collection userIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java new file mode 100644 index 0000000..7c0fa6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 优惠劵 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponRespVO extends CouponBaseVO { + + @Schema(description = "优惠劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java new file mode 100644 index 0000000..bac879f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 优惠劵发放 Request VO") +@Data +@ToString(callSuper = true) +public class CouponSendReqVO { + + @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Long templateId; + + @Schema(description = "用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotEmpty(message = "用户编号列表不能为空") + private Set userIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java new file mode 100644 index 0000000..2529f79 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** +* 优惠劵模板 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class CouponTemplateBaseVO { + + @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") + @NotNull(message = "优惠劵名不能为空") + private String name; + + @Schema(description = "发行总量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") // -1 - 则表示不限制发放数量 + @NotNull(message = "发行总量不能为空") + private Integer totalCount; + + @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") // -1 - 则表示不限制 + @NotNull(message = "每人限领个数不能为空") + private Integer takeLimitCount; + + @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "领取方式不能为空") + private Integer takeType; + + @Schema(description = "是否设置满多少金额可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 单位:分;0 - 不限制 + @NotNull(message = "是否设置满多少金额可用不能为空") + private Integer usePrice; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品范围不能为空") + @InEnum(PromotionProductScopeEnum.class) + private Integer productScope; + + @Schema(description = "商品范围编号的数组", example = "[1, 3]") + private List productScopeValues; + + @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "生效日期类型不能为空") + @InEnum(CouponTemplateValidityTypeEnum.class) + private Integer validityType; + + @Schema(description = "固定日期 - 生效开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime validStartTime; + + @Schema(description = "固定日期 - 生效结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime validEndTime; + + @Schema(description = "领取日期 - 开始天数") + @Min(value = 0L, message = "开始天数必须大于 0") + private Integer fixedStartTerm; + + @Schema(description = "领取日期 - 结束天数") + @Min(value = 1L, message = "开始天数必须大于 1") + private Integer fixedEndTerm; + + @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "优惠类型不能为空") + @InEnum(PromotionDiscountTypeEnum.class) + private Integer discountType; + + @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 + private Integer discountPercent; + + @Schema(description = "优惠金额", example = "10") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 + private Integer discountLimitPrice; + + @AssertTrue(message = "商品范围编号的数组不能为空") + @JsonIgnore + public boolean isProductScopeValuesValid() { + return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时,可以为空 + || CollUtil.isNotEmpty(productScopeValues); + } + + @AssertTrue(message = "生效开始时间不能为空") + @JsonIgnore + public boolean isValidStartTimeValid() { + return ObjectUtil.notEqual(validityType, CouponTemplateValidityTypeEnum.DATE.getType()) + || validStartTime != null; + } + + @AssertTrue(message = "生效结束时间不能为空") + @JsonIgnore + public boolean isValidEndTimeValid() { + return ObjectUtil.notEqual(validityType, CouponTemplateValidityTypeEnum.DATE.getType()) + || validEndTime != null; + } + + @AssertTrue(message = "开始天数不能为空") + @JsonIgnore + public boolean isFixedStartTermValid() { + return ObjectUtil.notEqual(validityType, CouponTemplateValidityTypeEnum.TERM.getType()) + || fixedStartTerm != null; + } + + @AssertTrue(message = "结束天数不能为空") + @JsonIgnore + public boolean isFixedEndTermValid() { + return ObjectUtil.notEqual(validityType, CouponTemplateValidityTypeEnum.TERM.getType()) + || fixedEndTerm != null; + } + + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99") + @JsonIgnore + public boolean isDiscountPercentValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99); + } + + @AssertTrue(message = "优惠金额不能为空") + @JsonIgnore + public boolean isDiscountPriceValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PRICE.getType()) + || discountPrice != null; + } + + @AssertTrue(message = "折扣上限不能为空") + @JsonIgnore + public boolean isDiscountLimitPriceValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) + || discountLimitPrice != null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java new file mode 100644 index 0000000..d9c5c32 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 优惠劵模板创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponTemplateCreateReqVO extends CouponTemplateBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java new file mode 100644 index 0000000..1dad778 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 优惠劵模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponTemplatePageReqVO extends PageParam { + + @Schema(description = "优惠劵名", example = "你好") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "优惠类型", example = "1") + private Integer discountType; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "可以领取的类型", example = "[1, 2, 3]") + @InEnum(value = CouponTakeTypeEnum.class, message = "可以领取的类型,必须是 {value}") + private List canTakeTypes; + + @Schema(description = "商品范围", example = "1") + @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围,必须是 {value}") + private Integer productScope; + + @Schema(description = "商品范围编号", example = "1") + private Long productScopeValue; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java new file mode 100644 index 0000000..d2c9d71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 优惠劵模板 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponTemplateRespVO extends CouponTemplateBaseVO { + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "领取优惠券的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer takeCount; + + @Schema(description = "使用优惠券的次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Integer useCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java new file mode 100644 index 0000000..e57bf62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 优惠劵模板更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponTemplateUpdateReqVO extends CouponTemplateBaseVO { + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "模板编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java new file mode 100644 index 0000000..a2234e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 优惠劵模板更新状态 Request VO") +@Data +public class CouponTemplateUpdateStatusReqVO { + + @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Long id; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java new file mode 100644 index 0000000..9b0d9e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 限时折扣活动") +@RestController +@RequestMapping("/promotion/discount-activity") +@Validated +public class DiscountActivityController { + + @Resource + private DiscountActivityService discountActivityService; + + @Resource + private ProductSpuApi productSpuApi; + + @PostMapping("/create") + @Operation(summary = "创建限时折扣活动") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')") + public CommonResult createDiscountActivity(@Valid @RequestBody DiscountActivityCreateReqVO createReqVO) { + return success(discountActivityService.createDiscountActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新限时折扣活动") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:update')") + public CommonResult updateDiscountActivity(@Valid @RequestBody DiscountActivityUpdateReqVO updateReqVO) { + discountActivityService.updateDiscountActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @Operation(summary = "关闭限时折扣活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')") + public CommonResult closeRewardActivity(@RequestParam("id") Long id) { + discountActivityService.closeDiscountActivity(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除限时折扣活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:delete')") + public CommonResult deleteDiscountActivity(@RequestParam("id") Long id) { + discountActivityService.deleteDiscountActivity(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得限时折扣活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") + public CommonResult getDiscountActivity(@RequestParam("id") Long id) { + DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id); + if (discountActivity == null) { + return success(null); + } + // 拼接结果 + List discountProducts = discountActivityService.getDiscountProductsByActivityId(id); + return success(DiscountActivityConvert.INSTANCE.convert(discountActivity, discountProducts)); + } + + @GetMapping("/page") + @Operation(summary = "获得限时折扣活动分页") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") + public CommonResult> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) { + PageResult pageResult = discountActivityService.getDiscountActivityPage(pageVO); + + if (CollUtil.isEmpty(pageResult.getList())) { // TODO @zhangshuai:方法里的空行,目的是让代码分块,可以更清晰;所以上面这个空格可以不要,而下面判断之后的,空格,其实加下比较好;类似的还有 spuList、以及后面的 convert + return success(PageResult.empty(pageResult.getTotal())); + } + // 拼接数据 + List products = discountActivityService.getDiscountProductsByActivityId( + convertSet(pageResult.getList(), DiscountActivityDO::getId)); + + List spuList = productSpuApi.getSpuList( + convertSet(products, DiscountProductDO::getSpuId)); + + return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products, spuList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java new file mode 100644 index 0000000..a729905 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 限时折扣活动 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DiscountActivityBaseVO { + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "一个标题") + @NotNull(message = "活动标题不能为空") + private String name; + + @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "商品") + @Data + public static class Product { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "优惠类型不能为空") + @InEnum(PromotionDiscountTypeEnum.class) + private Integer discountType; + + @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 + private Integer discountPercent; + + @Schema(description = "优惠金额", example = "10") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99") + @JsonIgnore + public boolean isDiscountPercentValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99); + } + + @AssertTrue(message = "优惠金额不能为空") + @JsonIgnore + public boolean isDiscountPriceValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PRICE.getType()) + || discountPrice != null; + } + + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java new file mode 100644 index 0000000..4da80a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@Schema(description = "管理后台 - 限时折扣活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO { + + /** + * 商品列表 + */ + @NotEmpty(message = "商品列表不能为空") + @Valid + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java new file mode 100644 index 0000000..85a989c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 限时折扣活动的详细 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityDetailRespVO extends DiscountActivityRespVO { + + /** + * 商品列表 + */ + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java new file mode 100644 index 0000000..4463555 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 限时折扣活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityPageReqVO extends PageParam { + + @Schema(description = "活动标题", example = "一个标题") + private String name; + + @Schema(description = "活动状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java new file mode 100644 index 0000000..232454a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 限时折扣活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityRespVO extends DiscountActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "活动状态不能为空") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") // TODO @zhangshuai:属性和属性之间,最多空一行噢; + private Long spuId; + + @Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + + // ========== 商品字段 ========== + + // TODO @zhangshuai:一个优惠活动,会关联多个商品,所以它不用返回 spuName 哈; + // TODO 最终界面展示字段就:编号、活动名称、参与商品数、活动状态、开始时间、结束时间、操作 + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取 + example = "618大促") + private String spuName; + @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "https://www.iocoder.cn/xx.png") + private String picUrl; + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取 + example = "50") + private Integer marketPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java new file mode 100644 index 0000000..83ff6d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 限时折扣活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "活动编号不能为空") + private Long id; + + /** + * 商品列表 + */ + @NotEmpty(message = "商品列表不能为空") + @Valid + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyPageController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyPageController.java new file mode 100644 index 0000000..4da7064 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyPageController.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.*; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 装修页面") +@RestController +@RequestMapping("/promotion/diy-page") +@Validated +public class DiyPageController { + + @Resource + private DiyPageService diyPageService; + + @PostMapping("/create") + @Operation(summary = "创建装修页面") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:create')") + public CommonResult createDiyPage(@Valid @RequestBody DiyPageCreateReqVO createReqVO) { + return success(diyPageService.createDiyPage(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新装修页面") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:update')") + public CommonResult updateDiyPage(@Valid @RequestBody DiyPageUpdateReqVO updateReqVO) { + diyPageService.updateDiyPage(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除装修页面") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:diy-page:delete')") + public CommonResult deleteDiyPage(@RequestParam("id") Long id) { + diyPageService.deleteDiyPage(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得装修页面") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:query')") + public CommonResult getDiyPage(@RequestParam("id") Long id) { + DiyPageDO diyPage = diyPageService.getDiyPage(id); + return success(DiyPageConvert.INSTANCE.convert(diyPage)); + } + + @GetMapping("/list") + @Operation(summary = "获得装修页面列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:query')") + public CommonResult> getDiyPageList(@RequestParam("ids") Collection ids) { + List list = diyPageService.getDiyPageList(ids); + return success(DiyPageConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得装修页面分页") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:query')") + public CommonResult> getDiyPagePage(@Valid DiyPagePageReqVO pageVO) { + PageResult pageResult = diyPageService.getDiyPagePage(pageVO); + return success(DiyPageConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/get-property") + @Operation(summary = "获得装修页面属性") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:query')") + public CommonResult getDiyPageProperty(@RequestParam("id") Long id) { + DiyPageDO diyPage = diyPageService.getDiyPage(id); + return success(DiyPageConvert.INSTANCE.convertPropertyVo(diyPage)); + } + + @PutMapping("/update-property") + @Operation(summary = "更新装修页面属性") + @PreAuthorize("@ss.hasPermission('promotion:diy-page:update')") + public CommonResult updateDiyPageProperty(@Valid @RequestBody DiyPagePropertyUpdateRequestVO updateReqVO) { + diyPageService.updateDiyPageProperty(updateReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyTemplateController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyTemplateController.java new file mode 100644 index 0000000..04fefca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyTemplateController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.*; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService; +import cn.iocoder.yudao.module.promotion.service.diy.DiyTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 装修模板") +@RestController +@RequestMapping("/promotion/diy-template") +@Validated +public class DiyTemplateController { + + @Resource + private DiyTemplateService diyTemplateService; + @Resource + private DiyPageService diyPageService; + + @PostMapping("/create") + @Operation(summary = "创建装修模板") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:create')") + public CommonResult createDiyTemplate(@Valid @RequestBody DiyTemplateCreateReqVO createReqVO) { + return success(diyTemplateService.createDiyTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新装修模板") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:update')") + public CommonResult updateDiyTemplate(@Valid @RequestBody DiyTemplateUpdateReqVO updateReqVO) { + diyTemplateService.updateDiyTemplate(updateReqVO); + return success(true); + } + + @PutMapping("/use") + @Operation(summary = "使用装修模板") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:use')") + public CommonResult useDiyTemplate(@RequestParam("id") Long id) { + diyTemplateService.useDiyTemplate(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除装修模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:diy-template:delete')") + public CommonResult deleteDiyTemplate(@RequestParam("id") Long id) { + diyTemplateService.deleteDiyTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得装修模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:query')") + public CommonResult getDiyTemplate(@RequestParam("id") Long id) { + DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id); + return success(DiyTemplateConvert.INSTANCE.convert(diyTemplate)); + } + + @GetMapping("/page") + @Operation(summary = "获得装修模板分页") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:query')") + public CommonResult> getDiyTemplatePage(@Valid DiyTemplatePageReqVO pageVO) { + PageResult pageResult = diyTemplateService.getDiyTemplatePage(pageVO); + return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult)); + } + + // TODO @疯狂:这个要不和 getDiyTemplate 合并,然后 DiyTemplateRespVO 里面直接把 DiyPagePropertyRespVO 也加上。减少 VO 好了,管理后台 get 多返回点数据,也问题不大的。目的,还是想尽可能降低大家的理解成本哈; + @GetMapping("/get-property") + @Operation(summary = "获得装修模板属性") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:query')") + public CommonResult getDiyTemplateProperty(@RequestParam("id") Long id) { + DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id); + List pages = diyPageService.getDiyPageByTemplateId(id); + return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages)); + } + + // TODO @疯狂:这个接口,要不和 useDiyTemplate 合并成一个,然后 VO 改成我们新的 VO 规范。不改的字段,就不传递。 + @PutMapping("/update-property") + @Operation(summary = "更新装修模板属性") + @PreAuthorize("@ss.hasPermission('promotion:diy-template:update')") + public CommonResult updateDiyTemplateProperty(@Valid @RequestBody DiyTemplatePropertyUpdateRequestVO updateReqVO) { + diyTemplateService.updateDiyTemplateProperty(updateReqVO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageBaseVO.java new file mode 100644 index 0000000..66186b1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageBaseVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 装修页面 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class DiyPageBaseVO { + + @Schema(description = "装修模板编号", example = "26179") + private Long templateId; + + @Schema(description = "页面名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotNull(message = "页面名称不能为空") + private String name; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "预览图") + private List previewPicUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageCreateReqVO.java new file mode 100644 index 0000000..17d3b35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 装修页面创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyPageCreateReqVO extends DiyPageBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePageReqVO.java new file mode 100644 index 0000000..5c81b9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 装修页面分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyPagePageReqVO extends PageParam { + + @Schema(description = "页面名称", example = "王五") + private String name; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java new file mode 100644 index 0000000..2fdd546 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 装修页面属性 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyPagePropertyRespVO extends DiyPageBaseVO { + + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + private Long id; + + @Schema(description = "页面属性", example = "[]") + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java new file mode 100644 index 0000000..ebfa364 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 装修页面属性更新 Request VO") +@Data +@ToString(callSuper = true) +public class DiyPagePropertyUpdateRequestVO { + + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + @NotNull(message = "装修页面编号不能为空") + private Long id; + + @Schema(description = "页面属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + @NotBlank(message = "页面属性不能为空") + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageRespVO.java new file mode 100644 index 0000000..9e2d9af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 装修页面 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyPageRespVO extends DiyPageBaseVO { + + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12082") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageUpdateReqVO.java new file mode 100644 index 0000000..9909b57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/page/DiyPageUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 装修页面更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyPageUpdateReqVO extends DiyPageBaseVO { + + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12082") + @NotNull(message = "装修页面编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java new file mode 100644 index 0000000..2f7769c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 装修模板 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class DiyTemplateBaseVO { + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题") + @NotEmpty(message = "模板名称不能为空") + private String name; + + @Schema(description = "备注", example = "默认主题") + private String remark; + + @Schema(description = "预览图", example = "[https://www.iocoder.cn/1.jpg]") + private List previewPicUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateCreateReqVO.java new file mode 100644 index 0000000..659f9c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 装修模板创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyTemplateCreateReqVO extends DiyTemplateBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePageReqVO.java new file mode 100644 index 0000000..1099226 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePageReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 装修模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyTemplatePageReqVO extends PageParam { + + @Schema(description = "模板名称", example = "默认主题") + private String name; + + @Schema(description = "是否使用", example = "true") + private Boolean used; + + @Schema(description = "使用时间", example = "使用时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] usedTime; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java new file mode 100644 index 0000000..21dd46f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 装修模板属性 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyTemplatePropertyRespVO extends DiyTemplateBaseVO { + + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + private Long id; + + @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String property; + + @Schema(description = "模板页面", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]") + private List pages; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java new file mode 100644 index 0000000..84b80f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 装修模板属性更新 Request VO") +@Data +@ToString(callSuper = true) +public class DiyTemplatePropertyUpdateRequestVO { + + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + @NotNull(message = "装修模板编号不能为空") + private Long id; + + @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + @NotBlank(message = "模板属性不能为空") + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateRespVO.java new file mode 100644 index 0000000..e19089e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 装修模板 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyTemplateRespVO extends DiyTemplateBaseVO { + + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "是否使用", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean used; + + @Schema(description = "使用时间", example = "使用时间") + private LocalDateTime usedTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateUpdateReqVO.java new file mode 100644 index 0000000..887f2f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 装修模板更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiyTemplateUpdateReqVO extends DiyTemplateBaseVO { + + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + @NotNull(message = "装修模板编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java new file mode 100644 index 0000000..7827fd1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 满减送活动") +@RestController +@RequestMapping("/promotion/reward-activity") +@Validated +public class RewardActivityController { + + @Resource + private RewardActivityService rewardActivityService; + + @PostMapping("/create") + @Operation(summary = "创建满减送活动") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:create')") + public CommonResult createRewardActivity(@Valid @RequestBody RewardActivityCreateReqVO createReqVO) { + return success(rewardActivityService.createRewardActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新满减送活动") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:update')") + public CommonResult updateRewardActivity(@Valid @RequestBody RewardActivityUpdateReqVO updateReqVO) { + rewardActivityService.updateRewardActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @Operation(summary = "关闭满减送活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:close')") + public CommonResult closeRewardActivity(@RequestParam("id") Long id) { + rewardActivityService.closeRewardActivity(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除满减送活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:delete')") + public CommonResult deleteRewardActivity(@RequestParam("id") Long id) { + rewardActivityService.deleteRewardActivity(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得满减送活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')") + public CommonResult getRewardActivity(@RequestParam("id") Long id) { + RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id); + return success(RewardActivityConvert.INSTANCE.convert(rewardActivity)); + } + + @GetMapping("/page") + @Operation(summary = "获得满减送活动分页") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')") + public CommonResult> getRewardActivityPage(@Valid RewardActivityPageReqVO pageVO) { + PageResult pageResult = rewardActivityService.getRewardActivityPage(pageVO); + return success(RewardActivityConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java new file mode 100644 index 0000000..01d1c80 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Future; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 满减送活动 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class RewardActivityBaseVO { + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "满啦满啦") + @NotNull(message = "活动标题不能为空") + private String name; + + @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Future(message = "结束时间必须大于当前时间") + private LocalDateTime endTime; + + @Schema(description = "备注", example = "biubiubiu") + private String remark; + + @Schema(description = "条件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "条件类型不能为空") + @InEnum(value = PromotionConditionTypeEnum.class, message = "条件类型必须是 {value}") + private Integer conditionType; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品范围不能为空") + @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围必须是 {value}") + private Integer productScope; + + @Schema(description = "商品 SPU 编号的数组", example = "1,2,3") + private List productSpuIds; + + /** + * 优惠规则的数组 + */ + @Valid // 校验下子对象 + private List rules; + + @Schema(description = "优惠规则") + @Data + public static class Rule { + + @Schema(description = "优惠门槛", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 1. 满 N 元,单位:分; 2. 满 N 件 + @Min(value = 1L, message = "优惠门槛必须大于等于 1") + private Integer limit; + + @Schema(description = "优惠价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @Min(value = 1L, message = "优惠价格必须大于等于 1") + private Integer discountPrice; + + @Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean freeDelivery; + + @Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @Min(value = 1L, message = "赠送的积分必须大于等于 1") + private Integer point; + + @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") + private List couponIds; + + @Schema(description = "赠送的优惠券数量的数组", example = "1,2,3") + private List couponCounts; + + @AssertTrue(message = "优惠劵和数量必须一一对应") + @JsonIgnore + public boolean isCouponCountsValid() { + return CollUtil.size(couponCounts) == CollUtil.size(couponCounts); + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java new file mode 100644 index 0000000..0710e46 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 满减送活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityCreateReqVO extends RewardActivityBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java new file mode 100644 index 0000000..7052c9c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 满减送活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityPageReqVO extends PageParam { + + @Schema(description = "活动标题", example = "满啦满啦") + private String name; + + @Schema(description = "活动状态", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java new file mode 100644 index 0000000..67bf121 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 满减送活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityRespVO extends RewardActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer id; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java new file mode 100644 index 0000000..3185ec8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 满减送活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityUpdateReqVO extends RewardActivityBaseVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "活动编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java new file mode 100644 index 0000000..f0db690 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 秒杀活动") +@RestController +@RequestMapping("/promotion/seckill-activity") +@Validated +public class SeckillActivityController { + + @Resource + private SeckillActivityService seckillActivityService; + @Resource + private ProductSpuApi productSpuApi; + + @PostMapping("/create") + @Operation(summary = "创建秒杀活动") + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:create')") + public CommonResult createSeckillActivity(@Valid @RequestBody SeckillActivityCreateReqVO createReqVO) { + return success(seckillActivityService.createSeckillActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新秒杀活动") + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:update')") + public CommonResult updateSeckillActivity(@Valid @RequestBody SeckillActivityUpdateReqVO updateReqVO) { + seckillActivityService.updateSeckillActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @Operation(summary = "关闭秒杀活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:close')") + public CommonResult closeSeckillActivity(@RequestParam("id") Long id) { + seckillActivityService.closeSeckillActivity(id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除秒杀活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:delete')") + public CommonResult deleteSeckillActivity(@RequestParam("id") Long id) { + seckillActivityService.deleteSeckillActivity(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得秒杀活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')") + public CommonResult getSeckillActivity(@RequestParam("id") Long id) { + SeckillActivityDO activity = seckillActivityService.getSeckillActivity(id); + List products = seckillActivityService.getSeckillProductListByActivityId(id); + return success(SeckillActivityConvert.INSTANCE.convert(activity, products)); + } + + @GetMapping("/page") + @Operation(summary = "获得秒杀活动分页") + @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')") + public CommonResult> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) { + // 查询活动列表 + PageResult pageResult = seckillActivityService.getSeckillActivityPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + List products = seckillActivityService.getSeckillProductListByActivityId( + convertSet(pageResult.getList(), SeckillActivityDO::getId)); + List spuList = productSpuApi.getSpuList( + convertSet(pageResult.getList(), SeckillActivityDO::getSpuId)); + return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java new file mode 100644 index 0000000..56d6db2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 秒杀时段") +@RestController +@RequestMapping("/promotion/seckill-config") +@Validated +public class SeckillConfigController { + + @Resource + private SeckillConfigService seckillConfigService; + + @PostMapping("/create") + @Operation(summary = "创建秒杀时段") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:create')") + public CommonResult createSeckillConfig(@Valid @RequestBody SeckillConfigCreateReqVO createReqVO) { + return success(seckillConfigService.createSeckillConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新秒杀时段") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:update')") + public CommonResult updateSeckillConfig(@Valid @RequestBody SeckillConfigUpdateReqVO updateReqVO) { + seckillConfigService.updateSeckillConfig(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "修改时段配置状态") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:update')") + public CommonResult updateSeckillConfigStatus(@Valid @RequestBody SeckillConfigUpdateStatusReqVo reqVO) { + seckillConfigService.updateSeckillConfigStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除秒杀时段") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:delete')") + public CommonResult deleteSeckillConfig(@RequestParam("id") Long id) { + seckillConfigService.deleteSeckillConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得秒杀时段") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:query')") + public CommonResult getSeckillConfig(@RequestParam("id") Long id) { + SeckillConfigDO seckillConfig = seckillConfigService.getSeckillConfig(id); + return success(SeckillConfigConvert.INSTANCE.convert(seckillConfig)); + } + + @GetMapping("/list") + @Operation(summary = "获得所有秒杀时段列表") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:query')") + public CommonResult> getSeckillConfigList() { + List list = seckillConfigService.getSeckillConfigList(); + return success(SeckillConfigConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获得所有开启状态的秒杀时段精简列表", description = "主要用于前端的下拉选项") + public CommonResult> getListAllSimple() { + List list = seckillConfigService.getSeckillConfigListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + return success(SeckillConfigConvert.INSTANCE.convertList1(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得秒杀时间段分页") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:query')") + public CommonResult> getSeckillActivityPage(@Valid SeckillConfigPageReqVO pageVO) { + PageResult pageResult = seckillConfigService.getSeckillConfigPage(pageVO); + return success(SeckillConfigConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java new file mode 100644 index 0000000..8aada5a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 秒杀活动基地签证官 + * 秒杀活动 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class SeckillActivityBaseVO { + + @Schema(description = "秒杀活动商品 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") + @NotNull(message = "秒杀活动商品不能为空") + private Long spuId; + + @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") + @NotNull(message = "秒杀活动名称不能为空") + private String name; + + @Schema(description = "备注", example = "清仓大甩卖割韭菜") + private String remark; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "活动开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "活动结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "秒杀时段 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]") + @NotNull(message = "秒杀时段不能为空") + private List configIds; + + @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12877") + private Integer totalLimitCount; + + @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683") + private Integer singleLimitCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java new file mode 100644 index 0000000..9b6e729 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + + +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 秒杀活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO { + + @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityDetailRespVO.java new file mode 100644 index 0000000..c3cc2eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityDetailRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 秒杀活动的详细 Response VO") +@Data +@ToString(callSuper = true) +public class SeckillActivityDetailRespVO extends SeckillActivityBaseVO{ + + @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityPageReqVO.java new file mode 100644 index 0000000..ac634a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +@Schema(description = "管理后台 - 秒杀活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillActivityPageReqVO extends PageParam { + + @Schema(description = "秒杀活动名称", example = "晚九点限时秒杀") + private String name; + + @Schema(description = "活动状态", example = "进行中") + private Integer status; + + @Schema(description = "秒杀时段id", example = "1") + private Long configId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java new file mode 100644 index 0000000..742c73b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 秒杀活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillActivityRespVO extends SeckillActivityBaseVO { + + @Schema(description = "秒杀活动 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354") + private Integer totalPrice; + + @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer stock; + + @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer totalStock; + + @Schema(description = "新增订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer orderCount; + + @Schema(description = "付款人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer userCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 商品字段 ========== + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取 + example = "618大促") + private String spuName; + @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "https://www.iocoder.cn/xx.png") + private String picUrl; + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取 + example = "50") + private Integer marketPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java new file mode 100644 index 0000000..bf2ca35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 秒杀活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO { + + @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java new file mode 100644 index 0000000..78a1c51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import java.time.LocalTime; +import java.util.List; + +/** + * 秒杀时段 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class SeckillConfigBaseVO { + + @Schema(description = "秒杀时段名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "早上场") + @NotNull(message = "秒杀时段名称不能为空") + private String name; + + @Schema(description = "开始时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "09:00:00") + @NotNull(message = "开始时间点不能为空") + private String startTime; + + @Schema(description = "结束时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "16:00:00") + @NotNull(message = "结束时间点不能为空") + private String endTime; + + @Schema(description = "秒杀轮播图", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]") + @NotNull(message = "秒杀轮播图不能为空") + private List sliderPicUrls; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "状态不能为空") + private Integer status; + + @AssertTrue(message = "秒杀时段开始时间和结束时间不能相等") + @JsonIgnore + public boolean isValidStartTimeValid() { + return !LocalTime.parse(startTime).equals(LocalTime.parse(endTime)); + } + + @AssertTrue(message = "秒杀时段开始时间不能在结束时间之后") + @JsonIgnore + public boolean isValidEndTimeValid() { + return !LocalTime.parse(startTime).isAfter(LocalTime.parse(endTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigCreateReqVO.java new file mode 100644 index 0000000..979ee69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 秒杀时段创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillConfigCreateReqVO extends SeckillConfigBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java new file mode 100644 index 0000000..9221138 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 秒杀时段分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillConfigPageReqVO extends PageParam { + + @Schema(description = "秒杀时段名称", example = "上午场") + private String name; + + @Schema(description = "状态", example = "0") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigRespVO.java new file mode 100644 index 0000000..5411536 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 秒杀时段 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillConfigRespVO extends SeckillConfigBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "秒杀活动数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer seckillActivityCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigSimpleRespVO.java new file mode 100644 index 0000000..069f39e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigSimpleRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 秒杀时段配置精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SeckillConfigSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "秒杀时段名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "早上场") + @NotNull(message = "秒杀时段名称不能为空") + private String name; + + @Schema(description = "开始时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "09:00:00") + private String startTime; + + @Schema(description = "结束时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "16:00:00") + private String endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateReqVO.java new file mode 100644 index 0000000..5b11dc4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 秒杀时段更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillConfigUpdateReqVO extends SeckillConfigBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateStatusReqVo.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateStatusReqVo.java new file mode 100644 index 0000000..0547cb1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigUpdateStatusReqVo.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 修改时段配置状态 Request VO") +@Data +public class SeckillConfigUpdateStatusReqVo { + + @Schema(description = "时段配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "时段配置编号不能为空") + private Long id; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java new file mode 100644 index 0000000..6584b79 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 秒杀参与商品 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author HUIHUI + */ +@Data +public class SeckillProductBaseVO { + + @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") + @NotNull(message = "商品sku_id不能为空") + private Long skuId; + + @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "6689") + @NotNull(message = "秒杀金额,单位:分不能为空") + private Integer seckillPrice; + + @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "秒杀库存不能为空") + private Integer stock; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductRespVO.java new file mode 100644 index 0000000..96b7eec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 秒杀参与商品 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillProductRespVO extends SeckillProductBaseVO { + + @Schema(description = "秒杀参与商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "256") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.http new file mode 100644 index 0000000..0dda88c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.http @@ -0,0 +1,5 @@ +### /promotion/activity/list-by-spu-ids 获得多个商品,近期参与的每个活动 +GET {{appApi}}/promotion/activity/list-by-spu-ids?spuIds=222&spuIds=633 +Authorization: Bearer {{appToken}} +Content-Type: application/json +tenant-id: {{appTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java new file mode 100644 index 0000000..38dd72b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.promotion.controller.app.activity; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +@Tag(name = "用户 APP - 营销活动") // 用于提供跨多个活动的 HTTP 接口 +@RestController +@RequestMapping("/promotion/activity") +@Validated +public class AppActivityController { + + @Resource + private CombinationActivityService combinationActivityService; + @Resource + private SeckillActivityService seckillActivityService; + @Resource + private BargainActivityService bargainActivityService; + @Resource + private DiscountActivityService discountActivityService; + @Resource + private RewardActivityService rewardActivityService; + + @GetMapping("/list-by-spu-id") + @Operation(summary = "获得单个商品,近期参与的每个活动") + @Parameter(name = "spuId", description = "商品编号", required = true) + public CommonResult> getActivityListBySpuId(@RequestParam("spuId") Long spuId) { + // 每种活动,只返回一个 + return success(getAppActivityList(Collections.singletonList(spuId))); + } + + @GetMapping("/list-by-spu-ids") + @Operation(summary = "获得多个商品,近期参与的每个活动") + @Parameter(name = "spuIds", description = "商品编号数组", required = true) + public CommonResult>> getActivityListBySpuIds(@RequestParam("spuIds") List spuIds) { + if (CollUtil.isEmpty(spuIds)) { + return success(MapUtil.empty()); + } + // 每种活动,只返回一个;key 为 SPU 编号 + return success(convertMultiMap(getAppActivityList(spuIds), AppActivityRespVO::getSpuId)); + } + + private List getAppActivityList(Collection spuIds) { + if (CollUtil.isEmpty(spuIds)) { + return new ArrayList<>(); + } + // 获取开启的且开始的且没有结束的活动 + List activityList = new ArrayList<>(); + LocalDateTime now = LocalDateTime.now(); + // 1. 拼团活动 + getCombinationActivities(spuIds, now, activityList); + // 2. 秒杀活动 + getSeckillActivities(spuIds, now, activityList); + // 3. 砍价活动 + getBargainActivities(spuIds, now, activityList); + // 4. 限时折扣活动 + getDiscountActivities(spuIds, now, activityList); + // 5. 满减送活动 + getRewardActivities(spuIds, now, activityList); + return activityList; + } + + private void getCombinationActivities(Collection spuIds, LocalDateTime now, List activityList) { + List combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(combinationActivities)) { + return; + } + + combinationActivities.forEach(item -> { + activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.COMBINATION_ACTIVITY.getType(), + item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime())); + }); + } + + private void getSeckillActivities(Collection spuIds, LocalDateTime now, List activityList) { + List seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(seckillActivities)) { + return; + } + + seckillActivities.forEach(item -> { + activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(), + item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime())); + }); + } + + private void getBargainActivities(Collection spuIds, LocalDateTime now, List activityList) { + List bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isNotEmpty(bargainActivities)) { + return; + } + + bargainActivities.forEach(item -> { + activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(), + item.getName(), item.getSpuId(), item.getStartTime(), item.getEndTime())); + }); + } + + private void getDiscountActivities(Collection spuIds, LocalDateTime now, List activityList) { + List discountActivities = discountActivityService.getDiscountActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(discountActivities)) { + return; + } + + List products = discountActivityService.getDiscountProductsByActivityId( + convertSet(discountActivities, DiscountActivityDO::getId)); + Map productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId); + discountActivities.forEach(item -> activityList.add(new AppActivityRespVO(item.getId(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), + item.getName(), productMap.get(item.getId()), item.getStartTime(), item.getEndTime()))); + } + + private void getRewardActivities(Collection spuIds, LocalDateTime now, List activityList) { + // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部 + List rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now); + if (CollUtil.isEmpty(rewardActivityList)) { + return; + } + + Map> spuIdAndActivityMap = spuIds.stream() + .collect(Collectors.toMap( + spuId -> spuId, + spuId -> rewardActivityList.stream() + .filter(activity -> activity.getProductSpuIds().contains(spuId)) + .max(Comparator.comparing(RewardActivityDO::getCreateTime)))); + for (Long supId : spuIdAndActivityMap.keySet()) { + if (!spuIdAndActivityMap.get(supId).isPresent()) { + continue; + } + + RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get(); + activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), + rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime())); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/vo/AppActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/vo/AppActivityRespVO.java new file mode 100644 index 0000000..6a67a66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/vo/AppActivityRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 营销活动 Response VO") +@AllArgsConstructor +@NoArgsConstructor +@Data +public class AppActivityRespVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "活动类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; // 对应 PromotionTypeEnum 枚举 + + @Schema(description = "活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大促") + private String name; + + @Schema(description = "spu 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "618") + private Long spuId; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java new file mode 100644 index 0000000..482b497 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.controller.app.article; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.category.AppArticleCategoryRespVO; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleCategoryConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import cn.iocoder.yudao.module.promotion.service.article.ArticleCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 文章分类") +@RestController +@RequestMapping("/promotion/article-category") +@Validated +public class AppArticleCategoryController { + + @Resource + private ArticleCategoryService articleCategoryService; + + @RequestMapping("/list") + @Operation(summary = "获得文章分类列表") + public CommonResult> getArticleCategoryList() { + List categoryList = articleCategoryService.getArticleCategoryListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + categoryList.sort(Comparator.comparing(ArticleCategoryDO::getSort)); // 按 sort 降序排列 + return success(ArticleCategoryConvert.INSTANCE.convertList04(categoryList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java new file mode 100644 index 0000000..a318bfd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.promotion.controller.app.article; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticleRespVO; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import cn.iocoder.yudao.module.promotion.service.article.ArticleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 文章") +@RestController +@RequestMapping("/promotion/article") +@Validated +public class AppArticleController { + + @Resource + private ArticleService articleService; + + @RequestMapping("/list") + @Operation(summary = "获得文章详情列表") + @Parameters({ + @Parameter(name = "recommendHot", description = "是否热门", example = "false"), // 场景一:查看指定的文章 + @Parameter(name = "recommendBanner", description = "是否轮播图", example = "false") // 场景二:查看指定的文章 + }) + public CommonResult> getArticleList( + @RequestParam(value = "recommendHot", required = false) Boolean recommendHot, + @RequestParam(value = "recommendBanner", required = false) Boolean recommendBanner) { + return success(ArticleConvert.INSTANCE.convertList03( + articleService.getArticleCategoryListByRecommend(recommendHot, recommendBanner))); + } + + @RequestMapping("/page") + @Operation(summary = "获得文章详情分页") + public CommonResult> getArticlePage(AppArticlePageReqVO pageReqVO) { + return success(ArticleConvert.INSTANCE.convertPage02(articleService.getArticlePage(pageReqVO))); + } + + @RequestMapping("/get") + @Operation(summary = "获得文章详情") + @Parameters({ + @Parameter(name = "id", description = "文章编号", example = "1024"), + @Parameter(name = "title", description = "文章标题", example = "1024"), + }) + public CommonResult getArticle(@RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "title", required = false) String title) { + ArticleDO article = id != null ? articleService.getArticle(id) + : articleService.getLastArticleByTitle(title); + return success(BeanUtils.toBean(article, AppArticleRespVO.class)); + } + + @PutMapping("/add-browse-count") + @Operation(summary = "增加文章浏览量") + @Parameter(name = "id", description = "文章编号", example = "1024") + public CommonResult addBrowseCount(@RequestParam("id") Long id) { + articleService.addArticleBrowseCount(id); + return success(true); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticlePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticlePageReqVO.java new file mode 100644 index 0000000..f548ae9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticlePageReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.controller.app.article.vo.article; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用 App - 文章的分页 Request VO") +@Data +public class AppArticlePageReqVO extends PageParam { + + @Schema(description = "分类编号", example = "2048") + private Long categoryId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java new file mode 100644 index 0000000..2c77fdc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.promotion.controller.app.article.vo.article; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "应用 App - 文章 Response VO") +@Data +public class AppArticleRespVO { + + @Schema(description = "文章编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "文章标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码 - 促销模块") + private String title; + + @Schema(description = "文章作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String author; + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long categoryId; + + @Schema(description = "图文封面", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "文章简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是简介") + private String introduction; + + @Schema(description = "文章内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是详细") + private String content; + + @Schema(description = "发布时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer browseCount; + + @Schema(description = "关联的商品 SPU 编号", example = "1024") + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java new file mode 100644 index 0000000..e0f34e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.promotion.controller.app.article.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用 App - 文章分类 Response VO") +@Data +public class AppArticleCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术") + private String name; + + @Schema(description = "分类图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java new file mode 100644 index 0000000..4ccaa2c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.promotion.controller.app.banner; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.promotion.controller.app.banner.vo.AppBannerRespVO; +import cn.iocoder.yudao.module.promotion.convert.banner.BannerConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import cn.iocoder.yudao.module.promotion.service.banner.BannerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController +@RequestMapping("/promotion/banner") +@Tag(name = "用户 APP - 首页 Banner") +@Validated +public class AppBannerController { + + @Resource + private BannerService bannerService; + + @GetMapping("/list") + @Operation(summary = "获得 banner 列表") + @Parameter(name = "position", description = "Banner position", example = "1") + public CommonResult> getBannerList(@RequestParam("position") Integer position) { + List bannerList = bannerService.getBannerListByPosition(position); + return success(BannerConvert.INSTANCE.convertList01(bannerList)); + } + + @PutMapping("/add-browse-count") + @Operation(summary = "增加 Banner 点击量") + @Parameter(name = "id", description = "Banner 编号", example = "1024") + public CommonResult addBrowseCount(@RequestParam("id") Long id) { + bannerService.addBannerBrowseCount(id); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java new file mode 100644 index 0000000..cc36d87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.app.banner.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - Banner Response VO") +@Data +public class AppBannerRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "标题不能为空") + private String title; + + @Schema(description = "跳转链接", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "跳转链接不能为空") + private String url; + + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "图片地址不能为空") + private String picUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainActivityController.java new file mode 100644 index 0000000..0de5ba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainActivityController.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "用户 App - 砍价活动") +@RestController +@RequestMapping("/promotion/bargain-activity") +@Validated +public class AppBargainActivityController { + + /** + * {@link AppBargainActivityRespVO} 缓存,通过它异步刷新 {@link #getBargainActivityList0(Integer)} 所要的首页数据 + */ + private final LoadingCache> bargainActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader>() { + + @Override + public List load(Integer count) { + return getBargainActivityList0(count); + } + + }); + + @Resource + private BargainActivityService bargainActivityService; + @Resource + private BargainRecordService bargainRecordService; + + @Resource + private ProductSpuApi spuApi; + + @GetMapping("/list") + @Operation(summary = "获得砍价活动列表", description = "用于小程序首页") + @Parameter(name = "count", description = "需要展示的数量", example = "6") + public CommonResult> getBargainActivityList( + @RequestParam(name = "count", defaultValue = "6") Integer count) { + return success(bargainActivityListCache.getUnchecked(count)); + } + + private ListgetBargainActivityList0(Integer count) { + List list = bargainActivityService.getBargainActivityListByCount(count); + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 拼接数据 + List spuList = spuApi.getSpuList(convertList(list, BargainActivityDO::getSpuId)); + return BargainActivityConvert.INSTANCE.convertAppList(list, spuList); + } + + @GetMapping("/page") + @Operation(summary = "获得砍价活动分页") + public CommonResult> getBargainActivityPage(PageParam pageReqVO) { + PageResult result = bargainActivityService.getBargainActivityPage(pageReqVO); + if (CollUtil.isEmpty(result.getList())) { + return success(PageResult.empty(result.getTotal())); + } + // 拼接数据 + List spuList = spuApi.getSpuList(convertList(result.getList(), BargainActivityDO::getSpuId)); + return success(BargainActivityConvert.INSTANCE.convertAppPage(result, spuList)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得砍价活动详情") + @Parameter(name = "id", description = "活动编号", example = "1") + public CommonResult getBargainActivityDetail(@RequestParam("id") Long id) { + BargainActivityDO activity = bargainActivityService.getBargainActivity(id); + if (activity == null) { + return success(null); + } + // 拼接数据 + Integer successUserCount = bargainRecordService.getBargainRecordUserCount(id, BargainRecordStatusEnum.SUCCESS.getStatus()); + ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId()); + return success(BargainActivityConvert.INSTANCE.convert(activity, successUserCount, spu)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.http new file mode 100644 index 0000000..2e401e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.http @@ -0,0 +1,9 @@ +### /promotion/bargain-record/create 创建砍价助力 +POST {{appApi}}/promotion/bargain-help/create +Authorization: Bearer test248 +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "recordId": 26 +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.java new file mode 100644 index 0000000..48d19ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainHelpController.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpRespVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainHelpConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainHelpService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 砍价助力") +@RestController +@RequestMapping("/promotion/bargain-help") +@Validated +public class AppBargainHelpController { + + @Resource + private BargainHelpService bargainHelpService; + + @Resource + private MemberUserApi memberUserApi; + + @PostMapping("/create") + @Operation(summary = "创建砍价助力", description = "给拼团记录砍一刀") // 返回结果为砍价金额,单位:分 + public CommonResult createBargainHelp(@RequestBody AppBargainHelpCreateReqVO reqVO) { + BargainHelpDO help = bargainHelpService.createBargainHelp(getLoginUserId(), reqVO); + return success(help.getReducePrice()); + } + + @GetMapping("/list") + @Operation(summary = "获得砍价助力列表") + @Parameter(name = "recordId", description = "砍价记录编号", required = true, example = "111") + public CommonResult> getBargainHelpList(@RequestParam("recordId") Long recordId) { + List helps = bargainHelpService.getBargainHelpListByRecordId(recordId); + if (CollUtil.isEmpty(helps)) { + return success(Collections.emptyList()); + } + helps.sort((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())); // 倒序展示 + + // 拼接数据 + Map userMap = memberUserApi.getUserMap( + convertSet(helps, BargainHelpDO::getUserId)); + return success(BargainHelpConvert.INSTANCE.convertList(helps, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.http new file mode 100644 index 0000000..46cbe3c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.http @@ -0,0 +1,9 @@ +### /promotion/bargain-record/create 创建砍价记录 +POST {{appApi}}/promotion/bargain-record/create +Authorization: Bearer {{appToken}} +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "activityId": 1 +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.java new file mode 100644 index 0000000..b4805e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.java @@ -0,0 +1,162 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordSummaryRespVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainRecordConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainHelpService; +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService; +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 砍价记录") +@RestController +@RequestMapping("/promotion/bargain-record") +@Validated +public class AppBargainRecordController { + + @Resource + private BargainHelpService bargainHelpService; + @Resource + private BargainRecordService bargainRecordService; + @Resource + private BargainActivityService bargainActivityService; + + @Resource + private TradeOrderApi tradeOrderApi; + @Resource + private MemberUserApi memberUserApi; + @Resource + private ProductSpuApi productSpuApi; + + @GetMapping("/get-summary") + @Operation(summary = "获得砍价记录的概要信息", description = "用于小程序首页") + public CommonResult getBargainRecordSummary() { + // 砍价成功的用户数量 + Integer successUserCount = bargainRecordService.getBargainRecordUserCount( + BargainRecordStatusEnum.SUCCESS.getStatus()); + if (successUserCount == 0) { + return success(new AppBargainRecordSummaryRespVO().setSuccessUserCount(0) + .setSuccessList(Collections.emptyList())); + } + // 砍价成功的用户列表 + List successList = bargainRecordService.getBargainRecordList( + BargainRecordStatusEnum.SUCCESS.getStatus(), 7); + List activityList = bargainActivityService.getBargainActivityList( + convertSet(successList, BargainRecordDO::getActivityId)); + Map userMap = memberUserApi.getUserMap( + convertSet(successList, BargainRecordDO::getUserId)); + // 拼接返回 + return success(BargainRecordConvert.INSTANCE.convert(successUserCount, successList, activityList, userMap)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得砍价记录的明细") + @Parameters({ + @Parameter(name = "id", description = "砍价记录编号", example = "111"), // 场景一:查看指定的砍价记录 + @Parameter(name = "activityId", description = "砍价活动编号", example = "222") // 场景二:查看指定的砍价活动 + }) + public CommonResult getBargainRecordDetail( + @RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "activityId", required = false) Long activityId) { + // 1. 查询砍价记录 + 砍价活动 + Assert.isTrue(id != null || activityId != null, "砍价记录编号和活动编号不能同时为空"); + BargainRecordDO record = id != null ? bargainRecordService.getBargainRecord(id) + : bargainRecordService.getLastBargainRecord(getLoginUserId(), activityId); + if (activityId == null || record != null) { + activityId = record.getActivityId(); + } + // 2. 查询助力记录 + Long userId = getLoginUserId(); + Integer helpAction = getHelpAction(userId, record, activityId); + // 3. 如果是自己的订单,则查询订单信息 + TradeOrderRespDTO order = record != null && record.getOrderId() != null && record.getUserId().equals(getLoginUserId()) + ? tradeOrderApi.getOrder(record.getOrderId()) : null; + // TODO 继续查询别的字段 + + // 拼接返回 + return success(BargainRecordConvert.INSTANCE.convert02(record, helpAction, order)); + } + + private Integer getHelpAction(Long userId, BargainRecordDO record, Long activityId) { + // 0.1 如果没有活动,无法帮砍 + if (activityId == null) { + return null; + } + // 0.2 如果是自己的砍价记录,无法帮砍 + if (record != null && record.getUserId().equals(userId)) { + return null; + } + + // 1. 判断是否已经助力 + if (record != null + && bargainHelpService.getBargainHelp(record.getId(), userId) != null) { + return AppBargainRecordDetailRespVO.HELP_ACTION_SUCCESS; + } + // 2. 判断是否满助力 + BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId); + if (activity != null + && bargainHelpService.getBargainHelpCountByActivity(activityId, userId) >= activity.getBargainCount()) { + return AppBargainRecordDetailRespVO.HELP_ACTION_FULL; + } + // 3. 允许助力 + return AppBargainRecordDetailRespVO.HELP_ACTION_NONE; + } + + @GetMapping("/page") + @Operation(summary = "获得砍价记录的分页") + public CommonResult> getBargainRecordPage(PageParam pageParam) { + PageResult pageResult = bargainRecordService.getBargainRecordPage(getLoginUserId(), pageParam); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + List activityList = bargainActivityService.getBargainActivityList( + convertSet(pageResult.getList(), BargainRecordDO::getActivityId)); + List spuList = productSpuApi.getSpuList( + convertSet(pageResult.getList(), BargainRecordDO::getSpuId)); + List orderList = tradeOrderApi.getOrderList( + convertSet(pageResult.getList(), BargainRecordDO::getOrderId)); + return success(BargainRecordConvert.INSTANCE.convertPage02(pageResult, activityList, spuList, orderList)); + } + + @PostMapping("/create") + @Operation(summary = "创建砍价记录", description = "参与砍价活动") + @PreAuthenticated + public CommonResult createBargainRecord(@RequestBody AppBargainRecordCreateReqVO reqVO) { + Long recordId = bargainRecordService.createBargainRecord(getLoginUserId(), reqVO); + return success(recordId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityDetailRespVO.java new file mode 100644 index 0000000..78322f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityDetailRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 砍价活动的明细 Response VO") +@Data +public class AppBargainActivityDetailRespVO { + + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价") + private String name; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long skuId; + + @Schema(description = "商品价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer price; + + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要吃西红柿") + private String description; + + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") + private Integer stock; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") // 从 SPU 的 picUrl 读取 + private String picUrl; + + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") // 从 SPU 的 marketPrice 读取 + private Integer marketPrice; + + @Schema(description = "砍价起始价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer bargainFirstPrice; + + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer bargainMinPrice; + + @Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer successUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityRespVO.java new file mode 100644 index 0000000..f6e0193 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/activity/AppBargainActivityRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 砍价活动 Response VO") +@Data +public class AppBargainActivityRespVO { + + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大砍价") + private String name; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long skuId; + + @Schema(description = "砍价库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") + private Integer stock; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "4096") + private String picUrl; + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取 + example = "50") + private Integer marketPrice; + + @Schema(description = "砍价最低金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer bargainMinPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpCreateReqVO.java new file mode 100644 index 0000000..3699266 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpCreateReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 砍价助力的创建 Request VO") +@Data +public class AppBargainHelpCreateReqVO { + + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "砍价记录编号不能为空") + private Long recordId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpRespVO.java new file mode 100644 index 0000000..c7bb20f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/help/AppBargainHelpRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 砍价助力 Response VO") +@Data +public class AppBargainHelpRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "助力用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String nickname; + + @Schema(description = "助力用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String avatar; + + @Schema(description = "助力用户的砍价金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer reducePrice; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordCreateReqVO.java new file mode 100644 index 0000000..cc1e448 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordCreateReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 砍价记录的创建 Request VO") +@Data +public class AppBargainRecordCreateReqVO { + + @Schema(description = "砍价活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "砍价活动编号不能为空") + private Long activityId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordDetailRespVO.java new file mode 100644 index 0000000..2f408b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordDetailRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 砍价记录的明细 Response VO") +@Data +public class AppBargainRecordDetailRespVO { + + public static final int HELP_ACTION_NONE = 1; // 帮砍动作 - 未帮砍,可以帮砍 + public static final int HELP_ACTION_FULL = 2; // 帮砍动作 - 未帮砍,无法帮砍(可帮砍次数已满) + public static final int HELP_ACTION_SUCCESS = 3; // 帮砍动作 - 已帮砍 + + // ========== 砍价记录 ========== + + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long skuId; + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private Long activityId; + + @Schema(description = "砍价起始价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + private Integer bargainFirstPrice; + + @Schema(description = "当前砍价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "23") + private Integer bargainPrice; + + @Schema(description = "砍价记录状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + // ========== 订单相关 ========== 注意:只有是自己的砍价记录,才会返回,保证隐私性 + + @Schema(description = "订单编号", example = "1024") + private Long orderId; + + @Schema(description = "支付状态", example = "true") + private Boolean payStatus; + + @Schema(description = "支付订单编号", example = "1024") + private Long payOrderId; + + // ========== 助力记录 ========== + + private Integer helpAction; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordRespVO.java new file mode 100644 index 0000000..6aa6cd9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 砍价记录的 Response VO") +@Data +public class AppBargainRecordRespVO { + + @Schema(description = "砍价记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long skuId; + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901") + private Long activityId; + + @Schema(description = "砍价记录状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "当前价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "102") + private Integer bargainPrice; + + // ========== 活动相关 ========== + + @Schema(description = "活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String activityName; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + // ========== 订单相关 ========== + + @Schema(description = "订单编号", example = "1024") + private Long orderId; + + @Schema(description = "支付状态", example = "true") + private Boolean payStatus; + + @Schema(description = "支付订单编号", example = "1024") + private Long payOrderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordSummaryRespVO.java new file mode 100644 index 0000000..8523e00 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/vo/record/AppBargainRecordSummaryRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 砍价记录的简要概括 Response VO") +@Data +public class AppBargainRecordSummaryRespVO { + + @Schema(description = "砍价用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer successUserCount; + + @Schema(description = "成功砍价的记录", requiredMode = Schema.RequiredMode.REQUIRED) // 只返回最近的 7 个 + private List successList; + + @Schema(description = "成功砍价记录") + @Data + public static class Record { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王**") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + @Schema(description = "活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "天蚕土豆") + private String activityName; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java new file mode 100644 index 0000000..6534c4e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationActivityController.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "用户 APP - 拼团活动") +@RestController +@RequestMapping("/promotion/combination-activity") +@Validated +public class AppCombinationActivityController { + + /** + * {@link AppCombinationActivityRespVO} 缓存,通过它异步刷新 {@link #getCombinationActivityList0(Integer)} 所要的首页数据 + */ + private final LoadingCache> combinationActivityListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader>() { + + @Override + public List load(Integer count) { + return getCombinationActivityList0(count); + } + + }); + + @Resource + private CombinationActivityService activityService; + + @Resource + private ProductSpuApi spuApi; + + @GetMapping("/list") + @Operation(summary = "获得拼团活动列表", description = "用于小程序首页") + @Parameter(name = "count", description = "需要展示的数量", example = "6") + public CommonResult> getCombinationActivityList( + @RequestParam(name = "count", defaultValue = "6") Integer count) { + return success(combinationActivityListCache.getUnchecked(count)); + } + + private List getCombinationActivityList0(Integer count) { + List activityList = activityService.getCombinationActivityListByCount(count); + if (CollUtil.isEmpty(activityList)) { + return Collections.emptyList(); + } + // 拼接返回 + List productList = activityService.getCombinationProductListByActivityIds( + convertList(activityList, CombinationActivityDO::getId)); + List spuList = spuApi.getSpuList(convertList(activityList, CombinationActivityDO::getSpuId)); + return CombinationActivityConvert.INSTANCE.convertAppList(activityList, productList, spuList); + } + + @GetMapping("/page") + @Operation(summary = "获得拼团活动分页") + public CommonResult> getCombinationActivityPage(PageParam pageParam) { + PageResult pageResult = activityService.getCombinationActivityPage(pageParam); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 拼接返回 + List productList = activityService.getCombinationProductListByActivityIds( + convertList(pageResult.getList(), CombinationActivityDO::getId)); + List spuList = spuApi.getSpuList(convertList(pageResult.getList(), CombinationActivityDO::getSpuId)); + return success(CombinationActivityConvert.INSTANCE.convertAppPage(pageResult, productList, spuList)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得拼团活动明细") + @Parameter(name = "id", description = "活动编号", required = true, example = "1024") + public CommonResult getCombinationActivityDetail(@RequestParam("id") Long id) { + // 1. 获取活动 + CombinationActivityDO activity = activityService.getCombinationActivity(id); + if (activity == null + || ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + return success(null); + } + + // 2. 获取活动商品 + List products = activityService.getCombinationProductsByActivityId(activity.getId()); + return success(CombinationActivityConvert.INSTANCE.convert3(activity, products)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java new file mode 100644 index 0000000..7901eb1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java @@ -0,0 +1,142 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordSummaryRespVO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.context.annotation.Lazy; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 拼团活动") +@RestController +@RequestMapping("/promotion/combination-record") +@Validated +public class AppCombinationRecordController { + + @Resource + private CombinationRecordService combinationRecordService; + @Resource + @Lazy + private TradeOrderApi tradeOrderApi; + + @GetMapping("/get-summary") + @Operation(summary = "获得拼团记录的概要信息", description = "用于小程序首页") + public CommonResult getCombinationRecordSummary() { + AppCombinationRecordSummaryRespVO summary = new AppCombinationRecordSummaryRespVO(); + // 1. 获得拼团参与用户数量 + Long userCount = combinationRecordService.getCombinationUserCount(); + if (userCount == 0) { + summary.setAvatars(Collections.emptyList()); + summary.setUserCount(userCount); + return success(summary); + } + summary.setUserCount(userCount); + + // 2. 获得拼团记录头像 + List records = combinationRecordService.getLatestCombinationRecordList( + AppCombinationRecordSummaryRespVO.AVATAR_COUNT); + summary.setAvatars(convertList(records, CombinationRecordDO::getAvatar)); + return success(summary); + } + + @GetMapping("/get-head-list") + @Operation(summary = "获得最近 n 条拼团记录(团长发起的)") + @Parameters({ + @Parameter(name = "activityId", description = "拼团活动编号"), + @Parameter(name = "status", description = "拼团状态"), // 对应 CombinationRecordStatusEnum 枚举 + @Parameter(name = "count", description = "数量") + }) + public CommonResult> getHeadCombinationRecordList( + @RequestParam(value = "activityId", required = false) Long activityId, + @RequestParam("status") Integer status, + @RequestParam(value = "count", defaultValue = "20") @Max(20) Integer count) { + List list = combinationRecordService.getHeadCombinationRecordList(activityId, status, count); + return success(BeanUtils.toBean(list, AppCombinationRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得我的拼团记录分页") + @PreAuthenticated + public CommonResult> getCombinationRecordPage( + @Valid AppCombinationRecordPageReqVO pageReqVO) { + PageResult pageResult = combinationRecordService.getCombinationRecordPage( + getLoginUserId(), pageReqVO); + return success(BeanUtils.toBean(pageResult, AppCombinationRecordRespVO.class)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得拼团记录明细") + @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024") + public CommonResult getCombinationRecordDetail(@RequestParam("id") Long id) { + // 1. 查找这条拼团记录 + CombinationRecordDO record = combinationRecordService.getCombinationRecordById(id); + if (record == null) { + return success(null); + } + + // 2. 查找该拼团的参团记录 + CombinationRecordDO headRecord; + List memberRecords; + if (Objects.equals(record.getHeadId(), CombinationRecordDO.HEAD_ID_GROUP)) { // 情况一:团长 + headRecord = record; + memberRecords = combinationRecordService.getCombinationRecordListByHeadId(record.getId()); + } else { // 情况二:团员 + headRecord = combinationRecordService.getCombinationRecordById(record.getHeadId()); + memberRecords = combinationRecordService.getCombinationRecordListByHeadId(headRecord.getId()); + } + + // 3. 拼接数据 + return success(CombinationActivityConvert.INSTANCE.convert(getLoginUserId(), headRecord, memberRecords)); + } + + @GetMapping("/cancel") + @Operation(summary = "取消拼团") + @Parameter(name = "id", description = "拼团记录编号", required = true, example = "1024") + public CommonResult cancelCombinationRecord(@RequestParam("id") Long id) { + Long userId = getLoginUserId(); + // 1、查找这条拼团记录 + CombinationRecordDO record = combinationRecordService.getCombinationRecordByIdAndUser(userId, id); + if (record == null) { + return success(Boolean.FALSE); + } + // 1.1、需要先校验拼团记录未完成; + if (!CombinationRecordStatusEnum.isInProgress(record.getStatus())) { + return success(Boolean.FALSE); + } + + // 2. 取消已支付的订单 + tradeOrderApi.cancelPaidOrder(userId, record.getOrderId()); + // 3. 取消拼团记录 + combinationRecordService.cancelCombinationRecord(userId, record.getId(), record.getHeadId()); + return success(Boolean.TRUE); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityDetailRespVO.java new file mode 100644 index 0000000..e2996b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityDetailRespVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 拼团活动明细 Response VO") +@Data +public class AppCombinationActivityDetailRespVO { + + @Schema(description = "拼团活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "拼团活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大拼团") + private String name; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "拼团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private Integer userSize; + + @Schema(description = "成功的拼团数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer successCount; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "总共限购数量", example = "10") + private Integer totalLimitCount; + + @Schema(description = "单次限购数量", example = "5") + private Integer singleLimitCount; + + @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + + @Schema(description = "商品信息") + @Data + public static class Product { + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") + private Long skuId; + + @Schema(description = "拼团金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer combinationPrice; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityRespVO.java new file mode 100644 index 0000000..64462a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/activity/AppCombinationActivityRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 拼团活动 Response VO") +@Data +public class AppCombinationActivityRespVO { + + @Schema(description = "拼团活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "拼团活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大拼团") + private String name; + + @Schema(description = "拼团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private Integer userSize; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") + // 从 SPU 的 picUrl 读取 + private String picUrl; + + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + // 从 SPU 的 marketPrice 读取 + private Integer marketPrice; + + @Schema(description = "拼团金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer combinationPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordDetailRespVO.java new file mode 100644 index 0000000..7c310a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordDetailRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 拼团记录详细 Response VO") +@Data +public class AppCombinationRecordDetailRespVO { + + @Schema(description = "团长的拼团记录", requiredMode = Schema.RequiredMode.REQUIRED) + private AppCombinationRecordRespVO headRecord; + + @Schema(description = "成员的拼团记录", requiredMode = Schema.RequiredMode.REQUIRED) + private List memberRecords; + + @Schema(description = "当前用户参团记录对应的订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long orderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordPageReqVO.java new file mode 100644 index 0000000..7f7169b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 App - 拼团记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppCombinationRecordPageReqVO extends PageParam { + + @Schema(description = "拼团状态", example = "1") + @InEnum(value = CombinationRecordStatusEnum.class, message = "拼团状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordRespVO.java new file mode 100644 index 0000000..8e4496a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 拼团记录 Response VO") +@Data +public class AppCombinationRecordRespVO { + + @Schema(description = "拼团记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "拼团活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long activityId; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String avatar; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expireTime; + + @Schema(description = "可参团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer userSize; + + @Schema(description = "已参团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer userCount; + + @Schema(description = "拼团状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long orderId; + + @Schema(description = "商品名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是大黄豆") + private String spuName; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer count; + + @Schema(description = "拼团金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer combinationPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordSummaryRespVO.java new file mode 100644 index 0000000..d9ea03d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/vo/record/AppCombinationRecordSummaryRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 拼团记录的简要概括 Response VO") +@Data +public class AppCombinationRecordSummaryRespVO { + + /** + * 加载 {@link #avatars} 的数量 + */ + public static final Integer AVATAR_COUNT = 7; + + @Schema(description = "拼团用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userCount; + + @Schema(description = "拼团用户头像列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List avatars; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java new file mode 100644 index 0000000..5320c4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.*; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 优惠劵") +@RestController +@RequestMapping("/promotion/coupon") +@Validated +public class AppCouponController { + + @Resource + private CouponService couponService; + @Resource + private CouponTemplateService couponTemplateService; + + @PostMapping("/take") + @Operation(summary = "领取优惠劵") + @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024") + @PreAuthenticated + public CommonResult takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) { + // 1. 领取优惠劵 + Long userId = getLoginUserId(); + couponService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); + + // 2. 检查是否可以继续领取 + CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId()); + boolean canTakeAgain = true; + if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) { + Integer takeCount = couponService.getTakeCount(reqVO.getTemplateId(), userId); + canTakeAgain = takeCount < couponTemplate.getTakeLimitCount(); + } + return success(canTakeAgain); + } + + @GetMapping("/match-list") + @Operation(summary = "获得匹配指定商品的优惠劵列表", description = "用于下单页,展示优惠劵列表") + public CommonResult> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { + // todo: 优化:优惠金额倒序 + List list = couponService.getMatchCouponList(getLoginUserId(), matchReqVO); + return success(BeanUtils.toBean(list, AppCouponMatchRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "我的优惠劵列表") + @PreAuthenticated + public CommonResult> getCouponPage(AppCouponPageReqVO pageReqVO) { + PageResult pageResult = couponService.getCouponPage( + CouponConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()))); + return success(BeanUtils.toBean(pageResult, AppCouponRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得优惠劵") + @Parameter(name = "id", description = "优惠劵编号", required = true, example = "1024") + @PreAuthenticated + public CommonResult getCoupon(@RequestParam("id") Long id) { + CouponDO coupon = couponService.getCoupon(getLoginUserId(), id); + return success(BeanUtils.toBean(coupon, AppCouponRespVO.class)); + } + + @GetMapping(value = "/get-unused-count") + @Operation(summary = "获得未使用的优惠劵数量") + @PreAuthenticated + public CommonResult getUnusedCouponCount() { + return success(couponService.getUnusedCouponCount(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java new file mode 100644 index 0000000..163b12d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java @@ -0,0 +1,141 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplateRespVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; + +@Tag(name = "用户 App - 优惠劵模板") +@RestController +@RequestMapping("/promotion/coupon-template") +@Validated +public class AppCouponTemplateController { + + @Resource + private CouponTemplateService couponTemplateService; + @Resource + private CouponService couponService; + + @Resource + private ProductSpuApi productSpuApi; + + @GetMapping("/get") + @Operation(summary = "获得优惠劵模版") + @Parameter(name = "id", description = "优惠券模板编号", required = true, example = "1024") + public CommonResult getCouponTemplate(Long id) { + CouponTemplateDO template = couponTemplateService.getCouponTemplate(id); + if (template == null) { + return success(null); + } + // 处理是否可领取 + Map canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), singletonList(template)); + return success(BeanUtils.toBean(template, AppCouponTemplateRespVO.class) + .setCanTake(canCanTakeMap.get(template.getId()))); + } + + @GetMapping("/list") + @Operation(summary = "获得优惠劵模版列表") + @Parameters({ + @Parameter(name = "spuId", description = "商品 SPU 编号"), // 目前主要给商品详情使用 + @Parameter(name = "productScope", description = "使用类型"), + @Parameter(name = "count", description = "数量", required = true) + }) + public CommonResult> getCouponTemplateList( + @RequestParam(value = "spuId", required = false) Long spuId, + @RequestParam(value = "productScope", required = false) Integer productScope, + @RequestParam(value = "count", required = false, defaultValue = "10") Integer count) { + // 1.1 处理查询条件:商品范围编号 + Long productScopeValue = getProductScopeValue(productScope, spuId); + // 1.2 处理查询条件:领取方式 = 直接领取 + List canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getValue()); + + // 2. 查询 + List list = couponTemplateService.getCouponTemplateList(canTakeTypes, productScope, + productScopeValue, count); + + // 3.1 领取数量 + Map canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), list); + // 3.2 拼接返回 + return success(CouponTemplateConvert.INSTANCE.convertAppList(list, canCanTakeMap)); + } + + @GetMapping("/list-by-ids") + @Operation(summary = "获得优惠劵模版列表") + @Parameter(name = "ids", description = "优惠券模板编号列表") + public CommonResult> getCouponTemplateList( + @RequestParam(value = "ids", required = false) Set ids) { + // 1. 查询 + List list = couponTemplateService.getCouponTemplateList(ids); + + // 2.1 领取数量 + Map canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), list); + // 2.2 拼接返回 + return success(CouponTemplateConvert.INSTANCE.convertAppList(list, canCanTakeMap)); + } + + @GetMapping("/page") + @Operation(summary = "获得优惠劵模版分页") + public CommonResult> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) { + // 1.1 处理查询条件:商品范围编号 + Long productScopeValue = getProductScopeValue(pageReqVO.getProductScope(), pageReqVO.getSpuId()); + // 1.2 处理查询条件:领取方式 = 直接领取 + List canTakeTypes = singletonList(CouponTakeTypeEnum.USER.getValue()); + + // 2. 分页查询 + PageResult pageResult = couponTemplateService.getCouponTemplatePage( + CouponTemplateConvert.INSTANCE.convert(pageReqVO, canTakeTypes, pageReqVO.getProductScope(), productScopeValue)); + + // 3.1 领取数量 + Map canCanTakeMap = couponService.getUserCanCanTakeMap(getLoginUserId(), pageResult.getList()); + // 3.2 拼接返回 + return success(CouponTemplateConvert.INSTANCE.convertAppPage(pageResult, canCanTakeMap)); + } + + /** + * 获得商品的使用范围编号 + * + * @param productScope 商品范围 + * @param spuId 商品 SPU 编号 + * @return 商品范围编号 + */ + private Long getProductScopeValue(Integer productScope, Long spuId) { + // 通用券:没有商品范围 + if (ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) { + return null; + } + // 品类券:查询商品的品类编号 + if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) { + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId); + return spu != null ? spu.getCategoryId() : null; + } + // 商品卷:直接返回 + return spuId; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java new file mode 100644 index 0000000..9d36e3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 优惠劵的匹配 Request VO") +@Data +public class AppCouponMatchReqVO { + + @Schema(description = "商品金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商品金额不能为空") + private Integer price; + + @Schema(description = "商品 SPU 编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotEmpty(message = "商品 SPU 编号不能为空") + private List spuIds; + + @Schema(description = "商品 SKU 编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotEmpty(message = "商品 SKU 编号不能为空") + private List skuIds; + + @Schema(description = "分类编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[10, 20]") + @NotEmpty(message = "分类编号不能为空") + private List categoryIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchRespVO.java new file mode 100644 index 0000000..da60390 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponMatchRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 优惠劵 Response VO") +@Data +public class AppCouponMatchRespVO extends AppCouponRespVO { + + @Schema(description = "是否匹配", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean match; + + @Schema(description = "匹配条件的提示", example = "所结算商品没有符合条件的商品") + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java new file mode 100644 index 0000000..0c42395 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 App - 优惠劵分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppCouponPageReqVO extends PageParam { + + @Schema(description = "优惠劵状态", example = "1") + @InEnum(value = CouponStatusEnum.class, message = "优惠劵状态,必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponRespVO.java new file mode 100644 index 0000000..7a5f249 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 优惠劵 Response VO") +@Data +public class AppCouponRespVO { + + @Schema(description = "优惠劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") + private String name; + + @Schema(description = "优惠劵状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 参见 CouponStatusEnum 枚举 + private Integer status; + + @Schema(description = "是否设置满多少金额可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 单位:分;0 - 不限制 + private Integer usePrice; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer productScope; + + @Schema(description = "商品范围编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private List productScopeValues; + + @Schema(description = "固定日期 - 生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "固定日期 - 生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer discountType; + + @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 + private Integer discountPercent; + + @Schema(description = "优惠金额", example = "10") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 + private Integer discountLimitPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponTakeReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponTakeReqVO.java new file mode 100644 index 0000000..0f71fe2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponTakeReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 优惠劵领取 Request VO") +@Data +public class AppCouponTakeReqVO { + + @Schema(description = "优惠劵模板编号", example = "1") + @NotNull(message = "优惠劵模板编号不能为空") + private Long templateId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java new file mode 100644 index 0000000..d98b2f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplatePageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 App - 优惠劵模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppCouponTemplatePageReqVO extends PageParam { + + @Schema(description = "商品范围", example = "1") + @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围,必须是 {value}") + private Integer productScope; + + @Schema(description = "商品标号", example = "1") + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java new file mode 100644 index 0000000..d333944 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template; + +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 优惠劵模板 Response VO") +@Data +public class AppCouponTemplateRespVO { + + @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") + private String name; + + @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") // -1 - 则表示不限制 + private Integer takeLimitCount; + + @Schema(description = "是否设置满多少金额可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") // 单位:分;0 - 不限制 + private Integer usePrice; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer productScope; + + @Schema(description = "商品范围编号的数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private List productScopeValues; + + @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer validityType; + + @Schema(description = "固定日期 - 生效开始时间") + private LocalDateTime validStartTime; + + @Schema(description = "固定日期 - 生效结束时间") + private LocalDateTime validEndTime; + + @Schema(description = "领取日期 - 开始天数") + @Min(value = 0L, message = "开始天数必须大于 0") + private Integer fixedStartTerm; + + @Schema(description = "领取日期 - 结束天数") + @Min(value = 1L, message = "开始天数必须大于 1") + private Integer fixedEndTerm; + + @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer discountType; + + @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 + private Integer discountPercent; + + @Schema(description = "优惠金额", example = "10") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 + private Integer discountLimitPrice; + + // ========== 用户相关字段 ========== + + @Schema(description = "是否可以领取", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean canTake; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyPageController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyPageController.java new file mode 100644 index 0000000..384dea4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyPageController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.controller.app.diy; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.app.diy.vo.AppDiyPagePropertyRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 装修页面") +@RestController +@RequestMapping("/promotion/diy-page") +@Validated +public class AppDiyPageController { + + @Resource + private DiyPageService diyPageService; + + @GetMapping("/get") + @Operation(summary = "获得装修页面") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getDiyPage(@RequestParam("id") Long id) { + DiyPageDO diyPage = diyPageService.getDiyPage(id); + return success(BeanUtils.toBean(diyPage, AppDiyPagePropertyRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyTemplateController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyTemplateController.java new file mode 100644 index 0000000..0bf37c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyTemplateController.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.promotion.controller.app.diy; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.promotion.controller.app.diy.vo.AppDiyTemplatePropertyRespVO; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.diy.DiyPageEnum; +import cn.iocoder.yudao.module.promotion.service.diy.DiyPageService; +import cn.iocoder.yudao.module.promotion.service.diy.DiyTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; + +@Tag(name = "用户 APP - 装修模板") +@RestController +@RequestMapping("/promotion/diy-template") +@Validated +public class AppDiyTemplateController { + + @Resource + private DiyTemplateService diyTemplateService; + @Resource + private DiyPageService diyPageService; + + // TODO @疯狂:要不要把 used 和 get 接口合并哈;不传递 id,直接拿默认; + @GetMapping("/used") + @Operation(summary = "使用中的装修模板") + public CommonResult getUsedDiyTemplate() { + DiyTemplateDO diyTemplate = diyTemplateService.getUsedDiyTemplate(); + return success(buildVo(diyTemplate)); + } + + @GetMapping("/get") + @Operation(summary = "获得装修模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getDiyTemplate(@RequestParam("id") Long id) { + DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id); + return success(buildVo(diyTemplate)); + } + + private AppDiyTemplatePropertyRespVO buildVo(DiyTemplateDO diyTemplate) { + if (diyTemplate == null) { + return null; + } + // 查询模板下的页面 + List pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId()); + String home = findFirst(pages, page -> DiyPageEnum.INDEX.getName().equals(page.getName()), DiyPageDO::getProperty); + String user = findFirst(pages, page -> DiyPageEnum.MY.getName().equals(page.getName()), DiyPageDO::getProperty); + // 拼接返回 + return DiyTemplateConvert.INSTANCE.convertPropertyVo2(diyTemplate, home, user); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyPagePropertyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyPagePropertyRespVO.java new file mode 100644 index 0000000..fb896d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyPagePropertyRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.app.diy.vo; + +import com.fasterxml.jackson.annotation.JsonRawValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "用户 App - 装修页面属性 Response VO") +@Data +@ToString(callSuper = true) +public class AppDiyPagePropertyRespVO { + + @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + private Long id; + + @Schema(description = "页面名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "页面属性", example = "[]") + @JsonRawValue + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java new file mode 100644 index 0000000..aa237e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.promotion.controller.app.diy.vo; + +import com.fasterxml.jackson.annotation.JsonRawValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "用户 App - 装修模板属性 Response VO") +@Data +@ToString(callSuper = true) +public class AppDiyTemplatePropertyRespVO { + + @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209") + private Long id; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题") + private String name; + + @Schema(description = "模板属性", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + @JsonRawValue + private String property; + + @Schema(description = "首页", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + @JsonRawValue + private String home; + + @Schema(description = "我的", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + @JsonRawValue + private String user; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/AppRewardActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/AppRewardActivityController.java new file mode 100644 index 0000000..1607a4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/AppRewardActivityController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.controller.app.reward; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.app.reward.vo.AppRewardActivityRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 满减送活动") +@RestController +@RequestMapping("/promotion/reward-activity") +@Validated +public class AppRewardActivityController { + + @Resource + private RewardActivityService rewardActivityService; + + @GetMapping("/get") + @Operation(summary = "获得满减送活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getRewardActivity(@RequestParam("id") Long id) { + RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id); + return success(BeanUtils.toBean(rewardActivity, AppRewardActivityRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java new file mode 100644 index 0000000..acaa522 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.controller.app.reward.vo; + +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 满减送活动 Response VO") +@Data +public class AppRewardActivityRespVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer id; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "满啦满啦") + private String name; + + @Schema(description = "条件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer conditionType; + + @Schema(description = "商品范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer productScope; + + @Schema(description = "商品 SPU 编号的数组", example = "1,2,3") + private List productSpuIds; + + @Schema(description = "优惠规则的数组") + private List rules; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java new file mode 100644 index 0000000..1b49453 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java @@ -0,0 +1,152 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.context.annotation.Lazy; +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; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween; + +@Tag(name = "用户 App - 秒杀活动") +@RestController +@RequestMapping("/promotion/seckill-activity") +@Validated +public class AppSeckillActivityController { + + /** + * {@link AppSeckillActivityNowRespVO} 缓存,通过它异步刷新 {@link #getNowSeckillActivity()} 所要的首页数据 + */ + private final LoadingCache nowSeckillActivityCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public AppSeckillActivityNowRespVO load(String key) { + return getNowSeckillActivity0(); + } + + }); + + @Resource + private SeckillActivityService activityService; + @Resource + @Lazy + private SeckillConfigService configService; + + @Resource + private ProductSpuApi spuApi; + + @GetMapping("/get-now") + @Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用") + public CommonResult getNowSeckillActivity() { + return success(nowSeckillActivityCache.getUnchecked("")); // 缓存 + } + + private AppSeckillActivityNowRespVO getNowSeckillActivity0() { + // 1. 获取当前时间处在哪个秒杀阶段 + SeckillConfigDO config = configService.getCurrentSeckillConfig(); + if (config == null) { // 时段不存在直接返回 null + return new AppSeckillActivityNowRespVO(); + } + + // 2.1 查询满足当前阶段的活动 + List activityList = activityService.getSeckillActivityListByConfigIdAndStatus(config.getId(), CommonStatusEnum.ENABLE.getStatus()); + List productList = activityService.getSeckillProductListByActivityId( + convertList(activityList, SeckillActivityDO::getId)); + // 2.2 获取 spu 信息 + List spuList = spuApi.getSpuList(convertList(activityList, SeckillActivityDO::getSpuId)); + return SeckillActivityConvert.INSTANCE.convert(config, activityList, productList, spuList); + } + + @GetMapping("/page") + @Operation(summary = "获得秒杀活动分页") + public CommonResult> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) { + // 1. 查询满足当前阶段的活动 + PageResult pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + List productList = activityService.getSeckillProductListByActivityId( + convertList(pageResult.getList(), SeckillActivityDO::getId)); + + // 2. 拼接数据 + List spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId)); + return success(SeckillActivityConvert.INSTANCE.convertPage02(pageResult, productList, spuList)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得秒杀活动明细") + @Parameter(name = "id", description = "活动编号", required = true, example = "1024") + public CommonResult getSeckillActivity(@RequestParam("id") Long id) { + // 1. 获取活动 + SeckillActivityDO activity = activityService.getSeckillActivity(id); + if (activity == null + || ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + return success(null); + } + + // 2. 获取时间段 + List configs = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()); + configs.removeIf(config -> !CollUtil.contains(activity.getConfigIds(), config.getId())); + // 2.1 优先使用当前时间段 + SeckillConfigDO config = findFirst(configs, config0 -> isBetween(config0.getStartTime(), config0.getEndTime())); + // 2.2 如果没有,则获取最后一个,因为倾向优先展示“未开始” > “已结束” + if (config == null) { + config = CollUtil.getLast(configs); + } + if (config == null) { + return null; + } + // 3. 计算开始时间、结束时间 + LocalDate nowDate; + // 3.1 如果在活动日期范围内,则以今天为 nowDate + if (LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) { + nowDate = LocalDate.now(); + } else { + // 3.2 如果不在活动时间范围内,则直接以活动的 endTime 作为 nowDate,因为还是倾向优先展示“未开始” > “已结束” + nowDate = activity.getEndTime().toLocalDate(); + } + LocalDateTime startTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getStartTime())); + LocalDateTime endTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getEndTime())); + + // 4. 拼接数据 + List productList = activityService.getSeckillProductListByActivityId(activity.getId()); + return success(SeckillActivityConvert.INSTANCE.convert3(activity, productList, startTime, endTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java new file mode 100644 index 0000000..12ff309 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 秒杀时间段") +@RestController +@RequestMapping("/promotion/seckill-config") +@Validated +public class AppSeckillConfigController { + @Resource + private SeckillConfigService configService; + + @GetMapping("/list") + @Operation(summary = "获得秒杀时间段列表") + public CommonResult> getSeckillConfigList() { + List list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(SeckillConfigConvert.INSTANCE.convertList2(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java new file mode 100644 index 0000000..ebb5ac5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 秒杀活动的详细 Response VO") +@Data +public class AppSeckillActivityDetailRespVO { + + @Schema(description = "秒杀活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "晚九点限时秒杀") + private String name; + + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "总共限购数量", example = "10") + private Integer totalLimitCount; + + @Schema(description = "单次限购数量", example = "5") + private Integer singleLimitCount; + + @Schema(description = "秒杀库存(剩余)", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer stock; + + @Schema(description = "秒杀库存(总计)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer totalStock; + + @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List products; + + @Schema(description = "商品信息") + @Data + public static class Product { + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") + private Long skuId; + + @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer seckillPrice; + + @Schema(description = "秒杀限量库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer stock; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityNowRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityNowRespVO.java new file mode 100644 index 0000000..5dad129 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityNowRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity; + +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 当前秒杀活动 Response VO") +@Data +public class AppSeckillActivityNowRespVO { + + @Schema(description = "秒杀时间段", requiredMode = Schema.RequiredMode.REQUIRED) + private AppSeckillConfigRespVO config; + + @Schema(description = "秒杀活动数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List activities; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityPageReqVO.java new file mode 100644 index 0000000..158f11f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityPageReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 App - 商品评价分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppSeckillActivityPageReqVO extends PageParam { + + @Schema(description = "秒杀配置编号", example = "1024") + private Long configId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityRespVO.java new file mode 100644 index 0000000..68e7ff8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 秒杀活动 Response VO") +@Data +public class AppSeckillActivityRespVO { + + @Schema(description = "秒杀活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "晚九点限时秒杀") + private String name; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取 + example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取 + example = "50") + private Integer marketPrice; + + @Schema(description = "秒杀活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "秒杀库存(剩余)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer stock; + @Schema(description = "秒杀库存(总共)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer totalStock; + + @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer seckillPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/config/AppSeckillConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/config/AppSeckillConfigRespVO.java new file mode 100644 index 0000000..c981f84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/config/AppSeckillConfigRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 秒杀时间段 Response VO") +@Data +public class AppSeckillConfigRespVO { + + @Schema(description = "秒杀时间段编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "开始时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "09:00") + private String startTime; + @Schema(description = "结束时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "09:59") + private String endTime; + + @Schema(description = "轮播图", requiredMode = Schema.RequiredMode.REQUIRED) + private List sliderPicUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleCategoryConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleCategoryConvert.java new file mode 100644 index 0000000..b5ac4f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleCategoryConvert.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.promotion.convert.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.*; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.category.AppArticleCategoryRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 文章分类 Convert + * + * @author HUIHUI + */ +@Mapper +public interface ArticleCategoryConvert { + + ArticleCategoryConvert INSTANCE = Mappers.getMapper(ArticleCategoryConvert.class); + + ArticleCategoryDO convert(ArticleCategoryCreateReqVO bean); + + ArticleCategoryDO convert(ArticleCategoryUpdateReqVO bean); + + ArticleCategoryRespVO convert(ArticleCategoryDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList03(List list); + + List convertList04(List categoryList); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleConvert.java new file mode 100644 index 0000000..7f4867f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleConvert.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.convert.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticleRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 文章管理 Convert + * + * @author HUIHUI + */ +@Mapper +public interface ArticleConvert { + + ArticleConvert INSTANCE = Mappers.getMapper(ArticleConvert.class); + + ArticleDO convert(ArticleCreateReqVO bean); + + ArticleDO convert(ArticleUpdateReqVO bean); + + ArticleRespVO convert(ArticleDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + AppArticleRespVO convert01(ArticleDO article); + + PageResult convertPage02(PageResult articlePage); + + List convertList03(List articleCategoryListByRecommendHotAndRecommendBanner); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java new file mode 100644 index 0000000..d2d7536 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.promotion.convert.banner; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.banner.vo.AppBannerRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface BannerConvert { + + BannerConvert INSTANCE = Mappers.getMapper(BannerConvert.class); + + List convertList(List list); + + PageResult convertPage(PageResult pageResult); + + BannerRespVO convert(BannerDO banner); + + BannerDO convert(BannerCreateReqVO createReqVO); + + BannerDO convert(BannerUpdateReqVO updateReqVO); + + List convertList01(List bannerList); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainActivityConvert.java new file mode 100644 index 0000000..69f1ce2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainActivityConvert.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.promotion.convert.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; + +/** + * 拼团活动 Convert + * + * @author HUIHUI + */ +@Mapper +public interface BargainActivityConvert { + + BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class); + + BargainActivityDO convert(BargainActivityBaseVO bean); + + BargainActivityDO convert(BargainActivityUpdateReqVO bean); + + BargainActivityRespVO convert(BargainActivityDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult page, List spuList, + Map recordUserCountMap, Map recordSuccessUserCountMap, + Map helpUserCountMap) { + PageResult result = convertPage(page); + // 拼接关联属性 + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + result.getList().forEach(item -> { + findAndThen(spuMap, item.getSpuId(), spu -> { + item.setPicUrl(spu.getPicUrl()).setSpuName(spu.getName()); + }); + // 设置统计字段 + item.setRecordUserCount(recordUserCountMap.getOrDefault(item.getId(), 0)) + .setRecordSuccessUserCount(recordSuccessUserCountMap.getOrDefault(item.getId(), 0)) + .setHelpUserCount(helpUserCountMap.getOrDefault(item.getId(), 0)); + }); + return result; + } + + AppBargainActivityDetailRespVO convert1(BargainActivityDO bean); + + default AppBargainActivityDetailRespVO convert(BargainActivityDO bean, Integer successUserCount, ProductSpuRespDTO spu) { + AppBargainActivityDetailRespVO detail = convert1(bean).setSuccessUserCount(successUserCount); + if (spu != null) { + detail.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()); + } + return detail; + } + + PageResult convertAppPage(PageResult page); + + default PageResult convertAppPage(PageResult page, List spuList) { + PageResult result = convertAppPage(page); + // 拼接关联属性 + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + List list = CollectionUtils.convertList(result.getList(), item -> { + findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + }); + result.setList(list); + return result; + } + + List convertAppList(List list); + + default List convertAppList(List list, List spuList) { + List activityList = convertAppList(list); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + return CollectionUtils.convertList(activityList, item -> { + findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainHelpConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainHelpConvert.java new file mode 100644 index 0000000..6ec71ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainHelpConvert.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.promotion.convert.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 砍价助力 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BargainHelpConvert { + + BargainHelpConvert INSTANCE = Mappers.getMapper(BargainHelpConvert.class); + + default PageResult convertPage(PageResult page, + Map userMap) { + PageResult pageResult = convertPage(page); + // 拼接数据 + pageResult.getList().forEach(record -> + MapUtils.findAndThen(userMap, record.getUserId(), + user -> record.setNickname(user.getNickname()).setAvatar(user.getAvatar()))); + return pageResult; + } + PageResult convertPage(PageResult page); + + default List convertList(List helps, + Map userMap) { + List helpVOs = convertList02(helps); + helpVOs.forEach(help -> + MapUtils.findAndThen(userMap, help.getUserId(), + user -> help.setNickname(user.getNickname()).setAvatar(user.getAvatar()))); + return helpVOs; + } + List convertList02(List helps); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainRecordConvert.java new file mode 100644 index 0000000..5c1bf75 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainRecordConvert.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.promotion.convert.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordSummaryRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 砍价记录 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BargainRecordConvert { + + BargainRecordConvert INSTANCE = Mappers.getMapper(BargainRecordConvert.class); + + default PageResult convertPage(PageResult page, + Map helpCountMap, + List activityList, + Map userMap) { + PageResult pageResult = convertPage(page); + // 拼接数据 + Map activityMap = convertMap(activityList, BargainActivityDO::getId); + pageResult.getList().forEach(record -> { + MapUtils.findAndThen(userMap, record.getUserId(), + user -> record.setNickname(user.getNickname()).setAvatar(user.getAvatar())); + record.setActivity(BargainActivityConvert.INSTANCE.convert(activityMap.get(record.getActivityId()))) + .setHelpCount(helpCountMap.getOrDefault(record.getId(), 0)); + }); + return pageResult; + } + PageResult convertPage(PageResult page); + + default PageResult convertPage02(PageResult page, + List activityList, + List spuList, + List orderList) { + PageResult pageResult = convertPage02(page); + // 拼接数据 + Map activityMap = convertMap(activityList, BargainActivityDO::getId); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map orderMap = convertMap(orderList, TradeOrderRespDTO::getId); + pageResult.getList().forEach(record -> { + MapUtils.findAndThen(activityMap, record.getActivityId(), + activity -> record.setActivityName(activity.getName()).setEndTime(activity.getEndTime())); + MapUtils.findAndThen(spuMap, record.getSpuId(), + spu -> record.setPicUrl(record.getPicUrl())); + MapUtils.findAndThen(orderMap, record.getOrderId(), + order -> record.setPayStatus(order.getPayStatus()).setPayOrderId(order.getPayOrderId())); + }); + return pageResult; + } + PageResult convertPage02(PageResult page); + + default AppBargainRecordSummaryRespVO convert(Integer successUserCount, List successList, + List activityList, Map userMap) { + AppBargainRecordSummaryRespVO summary = new AppBargainRecordSummaryRespVO().setSuccessUserCount(successUserCount); + Map activityMap = convertMap(activityList, BargainActivityDO::getId); + summary.setSuccessList(CollectionUtils.convertList(successList, record -> { + AppBargainRecordSummaryRespVO.Record recordVO = new AppBargainRecordSummaryRespVO.Record(); + MapUtils.findAndThen(userMap, record.getUserId(), + user -> recordVO.setNickname(user.getNickname()).setAvatar(user.getAvatar())); + MapUtils.findAndThen(activityMap, record.getActivityId(), + activity -> recordVO.setActivityName(activity.getName())); + return recordVO; + })); + return summary; + } + + @Mapping(source = "record.id", target = "id") + @Mapping(source = "record.userId", target = "userId") + @Mapping(source = "record.status", target = "status") + AppBargainRecordDetailRespVO convert02(BargainRecordDO record, Integer helpAction, TradeOrderRespDTO order); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java new file mode 100644 index 0000000..965459b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java @@ -0,0 +1,227 @@ +package cn.iocoder.yudao.module.promotion.convert.combination; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; + +/** + * 拼团活动 Convert + * + * @author HUIHUI + */ +@Mapper +public interface CombinationActivityConvert { + + CombinationActivityConvert INSTANCE = Mappers.getMapper(CombinationActivityConvert.class); + + CombinationActivityDO convert(CombinationActivityCreateReqVO bean); + + CombinationActivityDO convert(CombinationActivityUpdateReqVO bean); + + CombinationActivityRespVO convert(CombinationActivityDO bean); + + CombinationProductRespVO convert(CombinationProductDO bean); + + default CombinationActivityRespVO convert(CombinationActivityDO activity, List products) { + return convert(activity).setProducts(convertList2(products)); + } + + List convertList(List list); + + default PageResult convertPage(PageResult page, + List productList, + Map groupCountMap, + Map groupSuccessCountMap, + Map recordCountMap, + List spuList) { + PageResult pageResult = convertPage(page); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + pageResult.getList().forEach(item -> { + MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()) + .setMarketPrice(spu.getMarketPrice())); + item.setProducts(convertList2(productList)); + // 设置统计字段 + item.setGroupCount(groupCountMap.getOrDefault(item.getId(), 0)) + .setGroupSuccessCount(groupSuccessCountMap.getOrDefault(item.getId(), 0)) + .setRecordCount(recordCountMap.getOrDefault(item.getId(), 0)); + }); + return pageResult; + } + + PageResult convertPage(PageResult page); + + List convertList2(List productDOs); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(target = "activityId", source = "activity.id"), + @Mapping(target = "spuId", source = "activity.spuId"), + @Mapping(target = "skuId", source = "product.skuId"), + @Mapping(target = "combinationPrice", source = "product.combinationPrice"), + @Mapping(target = "activityStartTime", source = "activity.startTime"), + @Mapping(target = "activityEndTime", source = "activity.endTime") + }) + CombinationProductDO convert(CombinationActivityDO activity, CombinationProductBaseVO product); + + default List convertList(List products, CombinationActivityDO activity) { + return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus())); + } + + default List convertList(List updateProductVOs, + List products, CombinationActivityDO activity) { + Map productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId); + return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO) + .setId(productMap.get(updateProductVO.getSkuId())) + .setActivityStatus(activity.getStatus())); + } + + CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO); + + default CombinationRecordCreateRespDTO convert4(CombinationRecordDO combinationRecord) { + return new CombinationRecordCreateRespDTO().setCombinationActivityId(combinationRecord.getActivityId()) + .setCombinationRecordId(combinationRecord.getId()).setCombinationHeadId(combinationRecord.getHeadId()); + } + + default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO, + CombinationActivityDO activity, MemberUserRespDTO user, + ProductSpuRespDTO spu, ProductSkuRespDTO sku) { + return convert(reqDTO).setVirtualGroup(false) + .setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus()) // 创建后默认状态为进行中 + .setUserSize(activity.getUserSize()).setUserCount(1) // 默认就是 1 插入后会接着更新一次所有的拼团记录 + // 用户信息 + .setNickname(user.getNickname()).setAvatar(user.getAvatar()) + // 商品信息 + .setSpuName(spu.getName()).setPicUrl(sku.getPicUrl()); + } + + List convertAppList(List list); + + default List convertAppList(List list, + List productList, + List spuList) { + List activityList = convertAppList(list); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, CombinationProductDO::getActivityId); + return CollectionUtils.convertList(activityList, item -> { + // 设置 product 信息 + item.setCombinationPrice(getMinValue(productMap.get(item.getId()), CombinationProductDO::getCombinationPrice)); + // 设置 SPU 信息 + findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + }); + } + + PageResult convertAppPage(PageResult result); + + default PageResult convertAppPage(PageResult result, + List productList, + List spuList) { + PageResult appPage = convertAppPage(result); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, CombinationProductDO::getActivityId); + List list = CollectionUtils.convertList(appPage.getList(), item -> { + // 设置 product 信息 + item.setCombinationPrice(getMinValue(productMap.get(item.getId()), CombinationProductDO::getCombinationPrice)); + // 设置 SPU 信息 + findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + }); + appPage.setList(list); + return appPage; + } + + AppCombinationActivityDetailRespVO convert2(CombinationActivityDO combinationActivity); + + List convertList1(List products); + + default AppCombinationActivityDetailRespVO convert3(CombinationActivityDO combinationActivity, List products) { + return convert2(combinationActivity).setProducts(convertList1(products)); + } + + List convertList3(List records); + + AppCombinationRecordRespVO convert(CombinationRecordDO record); + + PageResult convert(PageResult result); + + default PageResult convert(PageResult recordPage, List activities, List products) { + PageResult result = convert(recordPage); + // 拼接关联属性 + Map activityMap = convertMap(activities, CombinationActivityDO::getId); + Map> productsMap = convertMultiMap(products, CombinationProductDO::getActivityId); + result.setList(CollectionUtils.convertList(result.getList(), item -> { + findAndThen(activityMap, item.getActivityId(), activity -> { + item.setActivity(convert(activity).setProducts(convertList2(productsMap.get(item.getActivityId())))); + }); + return item; + })); + return result; + } + + default AppCombinationRecordDetailRespVO convert(Long userId, CombinationRecordDO headRecord, List memberRecords) { + AppCombinationRecordDetailRespVO respVO = new AppCombinationRecordDetailRespVO() + .setHeadRecord(convert(headRecord)).setMemberRecords(convertList3(memberRecords)); + // 处理自己参与拼团的 orderId + CombinationRecordDO userRecord = CollectionUtils.findFirst(memberRecords, r -> ObjectUtil.equal(r.getUserId(), userId)); + if (userRecord == null && ObjectUtil.equal(headRecord.getUserId(), userId)) { + userRecord = headRecord; + } + respVO.setOrderId(userRecord == null ? null : userRecord.getOrderId()); + return respVO; + } + + /** + * 转换生成虚拟成团虚拟记录 + * + * @param headRecord 虚拟成团团长记录 + * @return 虚拟记录列表 + */ + default List convertVirtualRecordList(CombinationRecordDO headRecord) { + int count = headRecord.getUserSize() - headRecord.getUserCount(); + List createRecords = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + // 基础信息和团长保持一致 + CombinationRecordDO newRecord = convert5(headRecord); + // 虚拟信息 + newRecord.setCount(0) // 会单独更新下,在后续的 Service 逻辑里 + .setUserId(0L).setNickname("").setAvatar("").setOrderId(0L); + createRecords.add(newRecord); + } + return createRecords; + } + @Mapping(target = "id", ignore = true) + CombinationRecordDO convert5(CombinationRecordDO headRecord); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java new file mode 100644 index 0000000..542a77e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.promotion.convert.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 优惠劵 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface CouponConvert { + + CouponConvert INSTANCE = Mappers.getMapper(CouponConvert.class); + + PageResult convertPage(PageResult page); + + CouponRespDTO convert(CouponDO bean); + + default CouponDO convert(CouponTemplateDO template, Long userId) { + CouponDO couponDO = new CouponDO() + .setTemplateId(template.getId()) + .setName(template.getName()) + .setTakeType(template.getTakeType()) + .setUsePrice(template.getUsePrice()) + .setProductScope(template.getProductScope()) + .setProductScopeValues(template.getProductScopeValues()) + .setDiscountType(template.getDiscountType()) + .setDiscountPercent(template.getDiscountPercent()) + .setDiscountPrice(template.getDiscountPrice()) + .setDiscountLimitPrice(template.getDiscountLimitPrice()) + .setStatus(CouponStatusEnum.UNUSED.getStatus()) + .setUserId(userId); + if (CouponTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) { + couponDO.setValidStartTime(template.getValidStartTime()); + couponDO.setValidEndTime(template.getValidEndTime()); + } else if (CouponTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) { + couponDO.setValidStartTime(LocalDateTime.now().plusDays(template.getFixedStartTerm())); + couponDO.setValidEndTime(LocalDateTime.now().plusDays(template.getFixedEndTerm())); + } + return couponDO; + } + + CouponPageReqVO convert(AppCouponPageReqVO pageReqVO, Collection userIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java new file mode 100644 index 0000000..c6b86da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.promotion.convert.coupon; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplateRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 优惠劵模板 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface CouponTemplateConvert { + + CouponTemplateConvert INSTANCE = Mappers.getMapper(CouponTemplateConvert.class); + + CouponTemplateDO convert(CouponTemplateCreateReqVO bean); + + CouponTemplateDO convert(CouponTemplateUpdateReqVO bean); + + CouponTemplateRespVO convert(CouponTemplateDO bean); + + PageResult convertPage(PageResult page); + + CouponTemplatePageReqVO convert(AppCouponTemplatePageReqVO pageReqVO, List canTakeTypes, Integer productScope, Long productScopeValue); + + PageResult convertAppPage(PageResult pageResult); + + List convertAppList(List list); + + default PageResult convertAppPage(PageResult pageResult, Map userCanTakeMap) { + PageResult result = convertAppPage(pageResult); + copyTo(result.getList(), userCanTakeMap); + return result; + } + + default List convertAppList(List list, Map userCanTakeMap) { + List result = convertAppList(list); + copyTo(result, userCanTakeMap); + return result; + } + + default void copyTo(List list, Map userCanTakeMap) { + for (AppCouponTemplateRespVO template : list) { + // 检查已领取数量是否超过限领数量 + template.setCanTake(MapUtil.getBool(userCanTakeMap, template.getId(), false)); + } + } + + List convertList(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java new file mode 100644 index 0000000..0ecbd92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.promotion.convert.discount; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 限时折扣活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountActivityConvert { + + DiscountActivityConvert INSTANCE = Mappers.getMapper(DiscountActivityConvert.class); + + DiscountActivityDO convert(DiscountActivityCreateReqVO bean); + + DiscountActivityDO convert(DiscountActivityUpdateReqVO bean); + + DiscountActivityRespVO convert(DiscountActivityDO bean); + + List convertList(List list); + List convertList2(List list); + + List convertList02(List list); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult page, + List discountProductDOList, + List spuList) { + PageResult pageResult = convertPage(page); + + // 拼接商品 TODO @zhangshuai:类似空行的问题,也可以看看 + Map discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId); + Map spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId); + pageResult.getList().forEach(item -> { + item.setProducts(convertList2(discountProductDOList)); + item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId()); + if (item.getSpuId() != null) { + MapUtils.findAndThen(spuMap, item.getSpuId(), + spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + } + + }); + return pageResult; + } + + DiscountProductDO convert(DiscountActivityBaseVO.Product bean); + + default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List products){ + if ( activity == null && products == null ) { + return null; + } + + DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO(); + + if ( activity != null ) { + discountActivityDetailRespVO.setName( activity.getName() ); + discountActivityDetailRespVO.setStartTime( activity.getStartTime() ); + discountActivityDetailRespVO.setEndTime( activity.getEndTime() ); + discountActivityDetailRespVO.setRemark( activity.getRemark() ); + discountActivityDetailRespVO.setId( activity.getId() ); + discountActivityDetailRespVO.setStatus( activity.getStatus() ); + discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() ); + } + if (!products.isEmpty()) { + discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId()); + } + discountActivityDetailRespVO.setProducts( convertList2( products ) ); + + return discountActivityDetailRespVO; + } + + // =========== 比较是否相等 ========== + /** + * 比较两个限时折扣商品是否相等 + * + * @param productDO 数据库中的商品 + * @param productVO 前端传入的商品 + * @return 是否匹配 + */ + @SuppressWarnings("DuplicatedCode") + default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) { + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { + return false; + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); + } + return true; + } + + /** + * 比较两个限时折扣商品是否相等 + * 注意,比较时忽略 id 编号 + * + * @param productDO 商品 1 + * @param productVO 商品 2 + * @return 是否匹配 + */ + @SuppressWarnings("DuplicatedCode") + default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) { + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { + return false; + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); + } + return true; + } + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyPageConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyPageConvert.java new file mode 100644 index 0000000..3443fd8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyPageConvert.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.promotion.convert.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.*; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 装修页面 Convert + * + * @author owen + */ +@Mapper +public interface DiyPageConvert { + + DiyPageConvert INSTANCE = Mappers.getMapper(DiyPageConvert.class); + + DiyPageDO convert(DiyPageCreateReqVO bean); + + DiyPageDO convert(DiyPageUpdateReqVO bean); + + DiyPageRespVO convert(DiyPageDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + DiyPageCreateReqVO convertCreateVo(Long templateId, String name, String remark); + + DiyPagePropertyRespVO convertPropertyVo(DiyPageDO diyPage); + + DiyPageDO convert(DiyPagePropertyUpdateRequestVO updateReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyTemplateConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyTemplateConvert.java new file mode 100644 index 0000000..a579c60 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/diy/DiyTemplateConvert.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.convert.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.*; +import cn.iocoder.yudao.module.promotion.controller.app.diy.vo.AppDiyTemplatePropertyRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 装修模板 Convert + * + * @author owen + */ +@Mapper +public interface DiyTemplateConvert { + + DiyTemplateConvert INSTANCE = Mappers.getMapper(DiyTemplateConvert.class); + + DiyTemplateDO convert(DiyTemplateCreateReqVO bean); + + DiyTemplateDO convert(DiyTemplateUpdateReqVO bean); + + DiyTemplateRespVO convert(DiyTemplateDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + DiyTemplatePropertyRespVO convertPropertyVo(DiyTemplateDO diyTemplate, List pages); + + AppDiyTemplatePropertyRespVO convertPropertyVo2(DiyTemplateDO diyTemplate, String home, String user); + + DiyTemplateDO convert(DiyTemplatePropertyUpdateRequestVO updateReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java new file mode 100644 index 0000000..5343656 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.convert.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 满减送活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface RewardActivityConvert { + + RewardActivityConvert INSTANCE = Mappers.getMapper(RewardActivityConvert.class); + + RewardActivityDO convert(RewardActivityCreateReqVO bean); + + RewardActivityDO convert(RewardActivityUpdateReqVO bean); + + RewardActivityRespVO convert(RewardActivityDO bean); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java new file mode 100644 index 0000000..4f53cf3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java @@ -0,0 +1,141 @@ +package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; + +/** + * 秒杀活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface SeckillActivityConvert { + + SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class); + + SeckillActivityDO convert(SeckillActivityCreateReqVO bean); + + SeckillActivityDO convert(SeckillActivityUpdateReqVO bean); + + SeckillActivityRespVO convert(SeckillActivityDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult page, + List seckillProducts, + List spuList) { + PageResult pageResult = convertPage(page); + // 拼接商品 + Map spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId); + pageResult.getList().forEach(item -> { + item.setProducts(convertList2(seckillProducts)); + MapUtils.findAndThen(spuMap, item.getSpuId(), + spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + }); + return pageResult; + } + + SeckillActivityDetailRespVO convert1(SeckillActivityDO activity); + + default SeckillActivityDetailRespVO convert(SeckillActivityDO activity, List products) { + return convert1(activity).setProducts(convertList2(products)); + } + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(target = "activityId", source = "activity.id"), + @Mapping(target = "configIds", source = "activity.configIds"), + @Mapping(target = "spuId", source = "activity.spuId"), + @Mapping(target = "skuId", source = "product.skuId"), + @Mapping(target = "seckillPrice", source = "product.seckillPrice"), + @Mapping(target = "stock", source = "product.stock"), + @Mapping(target = "activityStartTime", source = "activity.startTime"), + @Mapping(target = "activityEndTime", source = "activity.endTime") + }) + SeckillProductDO convert(SeckillActivityDO activity, SeckillProductBaseVO product); + + default List convertList(List products, SeckillActivityDO activity) { + return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus())); + } + + List convertList2(List list); + + List convertList3(List activityList); + + default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List activityList, + List productList, List spuList) { + AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO(); + respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig)); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId); + respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> { + // product 信息 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice)); + // spu 信息 + findAndThen(spuMap, item.getSpuId(), spu -> + item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + })); + return respVO; + } + + PageResult convertPage1(PageResult pageResult); + + default PageResult convertPage02(PageResult pageResult, List productList, List spuList) { + PageResult result = convertPage1(pageResult); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId); + List list = CollectionUtils.convertList(result.getList(), item -> { + // product 信息 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice)); + // spu 信息 + findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); + return item; + }); + result.setList(list); + return result; + } + + AppSeckillActivityDetailRespVO convert2(SeckillActivityDO seckillActivity); + + List convertList1(List products); + + default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO activity, List products, + LocalDateTime startTime, LocalDateTime endTime) { + return convert2(activity) + .setProducts(convertList1(products)) + .setStartTime(startTime).setEndTime(endTime); + } + + SeckillValidateJoinRespDTO convert02(SeckillActivityDO activity, SeckillProductDO product); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillconfig/SeckillConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillconfig/SeckillConfigConvert.java new file mode 100644 index 0000000..f8dd774 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillconfig/SeckillConfigConvert.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 秒杀时段 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface SeckillConfigConvert { + + SeckillConfigConvert INSTANCE = Mappers.getMapper(SeckillConfigConvert.class); + + SeckillConfigDO convert(SeckillConfigCreateReqVO bean); + + SeckillConfigDO convert(SeckillConfigUpdateReqVO bean); + + SeckillConfigRespVO convert(SeckillConfigDO bean); + + List convertList(List list); + + List convertList1(List list); + + PageResult convertPage(PageResult page); + + List convertList2(List list); + + AppSeckillConfigRespVO convert1(SeckillConfigDO filteredConfig); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleCategoryDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleCategoryDO.java new file mode 100644 index 0000000..c79b86d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleCategoryDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.article; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文章分类 DO + * + * @author HUIHUI + */ +@TableName("promotion_article_category") +@KeySequence("promotion_article_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArticleCategoryDO extends BaseDO { + + /** + * 文章分类编号 + */ + @TableId + private Long id; + /** + * 文章分类名称 + */ + private String name; + /** + * 图标地址 + */ + private String picUrl; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 排序 + */ + private Integer sort; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleDO.java new file mode 100644 index 0000000..426d9d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/article/ArticleDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.article; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 文章管理 DO + * + * @author HUIHUI + */ +@TableName("promotion_article") +@KeySequence("promotion_article_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ArticleDO extends BaseDO { + + /** + * 文章管理编号 + */ + @TableId + private Long id; + /** + * 分类编号 ArticleCategoryDO#id + */ + private Long categoryId; + /** + * 关联商品编号 ProductSpuDO#id + */ + private Long spuId; + /** + * 文章标题 + */ + private String title; + /** + * 文章作者 + */ + private String author; + /** + * 文章封面图片地址 + */ + private String picUrl; + /** + * 文章简介 + */ + private String introduction; + /** + * 浏览次数 + */ + private Integer browseCount; + /** + * 排序 + */ + private Integer sort; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 是否热门(小程序) + */ + private Boolean recommendHot; + /** + * 是否轮播图(小程序) + */ + private Boolean recommendBanner; + /** + * 文章内容 + */ + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java new file mode 100644 index 0000000..fad9385 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.banner; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.banner.BannerPositionEnum; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * banner DO + * + * @author xia + */ +@TableName("promotion_banner") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BannerDO extends BaseDO { + + /** + * 编号 + */ + private Long id; + /** + * 标题 + */ + private String title; + /** + * 跳转链接 + */ + private String url; + /** + * 图片链接 + */ + private String picUrl; + /** + * 排序 + */ + private Integer sort; + + /** + * 状态 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 定位 {@link BannerPositionEnum} + */ + private Integer position; + + /** + * 备注 + */ + private String memo; + + /** + * 点击次数 + */ + private Integer browseCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainActivityDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainActivityDO.java new file mode 100644 index 0000000..37259eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainActivityDO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 砍价活动 DO + * + * @author HUIHUI + */ +@TableName("promotion_bargain_activity") +@KeySequence("promotion_bargain_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BargainActivityDO extends BaseDO { + + /** + * 砍价活动编号 + */ + @TableId + private Long id; + + /** + * 砍价活动名称 + */ + private String name; + + /** + * 活动开始时间 + */ + private LocalDateTime startTime; + /** + * 活动结束时间 + */ + private LocalDateTime endTime; + + /** + * 活动状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 砍价起始价格,单位:分 + */ + private Integer bargainFirstPrice; + /** + * 砍价底价,单位:分 + */ + private Integer bargainMinPrice; + + /** + * 砍价库存(剩余库存砍价时扣减) + */ + private Integer stock; + /** + * 砍价总库存 + */ + private Integer totalStock; + + /** + * 砍价人数 + * + * 需要多少人,砍价才能成功,即 {@link BargainRecordDO#getStatus()} 更新为 {@link BargainRecordDO#getStatus()} 成功状态 + */ + private Integer helpMaxCount; + /** + * 帮砍次数 + * + * 单个活动,用户可以帮砍的次数。 + * 例如说:帮砍次数为 1 时,A 和 B 同时将该活动链接发给 C,C 只能帮其中一个人砍价。 + */ + private Integer bargainCount; + + /** + * 总限购数量 + */ + private Integer totalLimitCount; + /** + * 用户每次砍价的最小金额,单位:分 + */ + private Integer randomMinPrice; + /** + * 用户每次砍价的最大金额,单位:分 + */ + private Integer randomMaxPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainHelpDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainHelpDO.java new file mode 100644 index 0000000..8419f34 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainHelpDO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 砍价助力 DO + * + * @author HUIHUI + */ +@TableName("promotion_bargain_help") +@KeySequence("promotion_bargain_help_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BargainHelpDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 砍价活动编号 + * + * 关联 {@link BargainActivityDO#getId()} 字段 + */ + private Long activityId; + /** + * 砍价记录编号 + * + * 关联 {@link BargainRecordDO#getId()} 字段 + */ + private Long recordId; + + /** + * 用户编号 + */ + private Long userId; + /** + * 减少价格,单位:分 + */ + private Integer reducePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainRecordDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainRecordDO.java new file mode 100644 index 0000000..e5f574d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainRecordDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 砍价记录 DO TODO + * + * @author HUIHUI + */ +@TableName("promotion_bargain_record") +@KeySequence("promotion_bargain_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BargainRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + + /** + * 砍价活动编号 + * + * 关联 {@link BargainActivityDO#getId()} 字段 + */ + private Long activityId; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + + /** + * 砍价起始价格,单位:分 + */ + private Integer bargainFirstPrice; + /** + * 当前砍价,单位:分 + */ + private Integer bargainPrice; + + /** + * 砍价状态 + * + * 砍价成功的条件是:(2 选 1) + * 1. 砍价到 {@link BargainActivityDO#getBargainMinPrice()} 底价 + * 2. 助力人数到达 {@link BargainActivityDO#getHelpMaxCount()} 人 + * + * 枚举 {@link BargainRecordStatusEnum} + */ + private Integer status; + /** + * 结束时间 + */ + private LocalDateTime endTime; + + /** + * 订单编号 + */ + private Long orderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java new file mode 100644 index 0000000..5236b30 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.combination; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 拼团活动 DO + * + * @author HUIHUI + */ +@TableName("promotion_combination_activity") +@KeySequence("promotion_combination_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CombinationActivityDO extends BaseDO { + + /** + * 活动编号 + */ + @TableId + private Long id; + /** + * 拼团名称 + */ + private String name; + /** + * 商品 SPU 编号 + * + * 关联 ProductSpuDO 的 id + */ + private Long spuId; + /** + * 总限购数量 + */ + private Integer totalLimitCount; + /** + * 单次限购数量 + */ + private Integer singleLimitCount; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 结束时间 + */ + private LocalDateTime endTime; + /** + * 几人团 + */ + private Integer userSize; + /** + * 虚拟成团 + */ + private Boolean virtualGroup; + /** + * 活动状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 限制时长(小时) + */ + private Integer limitDuration; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java new file mode 100644 index 0000000..d793bb6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.combination; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 拼团商品 DO + * + * @author HUIHUI + */ +@TableName("promotion_combination_product") +@KeySequence("promotion_combination_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CombinationProductDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 拼团活动编号 + */ + private Long activityId; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 拼团价格,单位分 + */ + private Integer combinationPrice; + + /** + * 拼团商品状态 + * + * 关联 {@link CombinationActivityDO#getStatus()} + */ + private Integer activityStatus; + /** + * 活动开始时间点 + * + * 冗余 {@link CombinationActivityDO#getStartTime()} + */ + private LocalDateTime activityStartTime; + /** + * 活动结束时间点 + * + * 冗余 {@link CombinationActivityDO#getEndTime()} + */ + private LocalDateTime activityEndTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java new file mode 100644 index 0000000..e1ba90b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.combination; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +// TODO 芋艿:把字段的顺序,和 do 顺序对齐下 +/** + * 拼团记录 DO + * + * 1. 用户参与拼团时,会创建一条记录 + * 2. 团长的拼团记录,和参团人的拼团记录,通过 {@link #headId} 关联 + * + * @author HUIHUI + */ +@TableName("promotion_combination_record") +@KeySequence("promotion_combination_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CombinationRecordDO extends BaseDO { + + /** + * 团长编号 - 团长 + */ + public static final Long HEAD_ID_GROUP = 0L; + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + + /** + * 拼团活动编号 + * + * 关联 {@link CombinationActivityDO#getId()} + */ + private Long activityId; + /** + * 拼团商品单价 + * + * 冗余 {@link CombinationProductDO#getCombinationPrice()} + */ + private Integer combinationPrice; + /** + * SPU 编号 + */ + private Long spuId; + /** + * 商品名字 + */ + private String spuName; + /** + * 商品图片 + */ + private String picUrl; + /** + * SKU 编号 + */ + private Long skuId; + /** + * 购买的商品数量 + */ + private Integer count; + + /** + * 用户编号 + */ + private Long userId; + + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户头像 + */ + private String avatar; + + /** + * 团长编号 + * + * 关联 {@link CombinationRecordDO#getId()} + * + * 如果是团长,则它的值是 {@link #HEAD_ID_GROUP} + */ + private Long headId; + /** + * 开团状态 + * + * 关联 {@link CombinationRecordStatusEnum} + */ + private Integer status; + /** + * 订单编号 + */ + private Long orderId; + /** + * 开团需要人数 + * + * 关联 {@link CombinationActivityDO#getUserSize()} + */ + private Integer userSize; + /** + * 已加入拼团人数 + */ + private Integer userCount; + /** + * 是否虚拟成团 + * + * 默认为 false。 + * 拼团过期都还没有成功,如果 {@link CombinationActivityDO#getVirtualGroup()} 为 true,则执行虚拟成团的逻辑,才会更新该字段为 true + */ + private Boolean virtualGroup; + + /** + * 过期时间 + * + * 基于 {@link CombinationRecordDO#getStartTime()} + {@link CombinationActivityDO#getLimitDuration()} 计算 + */ + private LocalDateTime expireTime; + /** + * 开始时间 (订单付款后开始的时间) + */ + private LocalDateTime startTime; + /** + * 结束时间(成团时间/失败时间) + */ + private LocalDateTime endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java new file mode 100644 index 0000000..31cef2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java @@ -0,0 +1,142 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 优惠劵 DO + * + * @author 芋道源码 + */ +@TableName(value = "promotion_coupon", autoResultMap = true) +@KeySequence("promotion_coupon_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class CouponDO extends BaseDO { + + // ========== 基本信息 BEGIN ========== + /** + * 优惠劵编号 + */ + private Long id; + /** + * 优惠劵模板编号 + * + * 关联 {@link CouponTemplateDO#getId()} + */ + private Long templateId; + /** + * 优惠劵名 + * + * 冗余 {@link CouponTemplateDO#getName()} + */ + private String name; + /** + * 优惠码状态 + * + * 枚举 {@link CouponStatusEnum} + */ + // TODO 芋艿:已作废? + private Integer status; + + // TODO 芋艿:发放 adminid? + + // ========== 基本信息 END ========== + + // ========== 领取情况 BEGIN ========== + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 字段 + */ + private Long userId; + /** + * 领取类型 + * + * 枚举 {@link CouponTakeTypeEnum} + */ + private Integer takeType; + // ========== 领取情况 END ========== + + // ========== 使用规则 BEGIN ========== + /** + * 是否设置满多少金额可用,单位:分 + * + * 冗余 {@link CouponTemplateDO#getUsePrice()} + */ + private Integer usePrice; + /** + * 生效开始时间 + */ + private LocalDateTime validStartTime; + /** + * 生效结束时间 + */ + private LocalDateTime validEndTime; + /** + * 商品范围 + * + * 枚举 {@link PromotionProductScopeEnum} + */ + private Integer productScope; + /** + * 商品范围编号的数组 + * + * 冗余 {@link CouponTemplateDO#getProductScopeValues()} + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List productScopeValues; + // ========== 使用规则 END ========== + + // ========== 使用效果 BEGIN ========== + /** + * 折扣类型 + * + * 冗余 {@link CouponTemplateDO#getDiscountType()} + */ + private Integer discountType; + /** + * 折扣百分比 + * + * 冗余 {@link CouponTemplateDO#getDiscountPercent()} + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + * + * 冗余 {@link CouponTemplateDO#getDiscountPrice()} + */ + private Integer discountPrice; + /** + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 + * + * 冗余 {@link CouponTemplateDO#getDiscountLimitPrice()} + */ + private Integer discountLimitPrice; + // ========== 使用效果 END ========== + + // ========== 使用情况 BEGIN ========== + /** + * 使用订单号 + */ + private Long useOrderId; + /** + * 使用时间 + */ + private LocalDateTime useTime; + + // ========== 使用情况 END ========== + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java new file mode 100644 index 0000000..ad4ebab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java @@ -0,0 +1,166 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +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 java.time.LocalDateTime; +import java.util.List; + +/** + * 优惠劵模板 DO + * + * 当用户领取时,会生成 {@link CouponDO} 优惠劵 + * + * @author 芋道源码 + */ +@TableName(value = "promotion_coupon_template", autoResultMap = true) +@KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class CouponTemplateDO extends BaseDO { + + // ========== 基本信息 BEGIN ========== + /** + * 模板编号,自增唯一 + */ + @TableId + private Long id; + /** + * 优惠劵名 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + // TODO 芋艿:要不要改成 3 个状态?? + private Integer status; + + // ========== 基本信息 END ========== + + // ========== 领取规则 BEGIN ========== + /** + * 发放数量 + * + * -1 - 则表示不限制发放数量 + */ + private Integer totalCount; + /** + * 每人限领个数 + * + * -1 - 则表示不限制 + */ + private Integer takeLimitCount; + /** + * 领取方式 + * + * 枚举 {@link CouponTakeTypeEnum} + */ + private Integer takeType; + // ========== 领取规则 END ========== + + // ========== 使用规则 BEGIN ========== + /** + * 是否设置满多少金额可用,单位:分 + * + * 0 - 不限制 + * 大于 0 - 多少金额可用 + */ + private Integer usePrice; + /** + * 商品范围 + * + * 枚举 {@link PromotionProductScopeEnum} + */ + private Integer productScope; + /** + * 商品范围编号的数组 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List productScopeValues; + /** + * 生效日期类型 + * + * 枚举 {@link CouponTemplateValidityTypeEnum} + */ + private Integer validityType; + /** + * 固定日期 - 生效开始时间 + * + * 当 {@link #validityType} 为 {@link CouponTemplateValidityTypeEnum#DATE} + */ + private LocalDateTime validStartTime; + /** + * 固定日期 - 生效结束时间 + * + * 当 {@link #validityType} 为 {@link CouponTemplateValidityTypeEnum#DATE} + */ + private LocalDateTime validEndTime; + /** + * 领取日期 - 开始天数 + * + * 当 {@link #validityType} 为 {@link CouponTemplateValidityTypeEnum#TERM} + */ + private Integer fixedStartTerm; + /** + * 领取日期 - 结束天数 + * + * 当 {@link #validityType} 为 {@link CouponTemplateValidityTypeEnum#TERM} + */ + private Integer fixedEndTerm; + // ========== 使用规则 END ========== + + // ========== 使用效果 BEGIN ========== + /** + * 折扣类型 + * + * 枚举 {@link PromotionDiscountTypeEnum} + */ + private Integer discountType; + /** + * 折扣百分比 + * + * 例如,80% 为 80 + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + * + * 当 {@link #discountType} 为 {@link PromotionDiscountTypeEnum#PRICE} 生效 + */ + private Integer discountPrice; + /** + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 + * + * 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。 + */ + private Integer discountLimitPrice; + // ========== 使用效果 END ========== + + // ========== 统计信息 BEGIN ========== + /** + * 领取优惠券的数量 + */ + private Integer takeCount; + /** + * 使用优惠券的次数 + */ + private Integer useCount; + // ========== 统计信息 END ========== + + // TODO 芋艿:领取开始时间、领取结束时间 + + // TODO 芋艿:要不要加描述 +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountActivityDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountActivityDO.java new file mode 100644 index 0000000..956a223 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountActivityDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 限时折扣活动 DO + * + * 一个活动下,可以有 {@link DiscountProductDO} 商品; + * 一个商品,在指定时间段内,只能属于一个活动; + * + * @author 芋道源码 + */ +@TableName(value = "promotion_discount_activity", autoResultMap = true) +@KeySequence("promotion_discount_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DiscountActivityDO extends BaseDO { + + /** + * 活动编号,主键自增 + */ + @TableId + private Long id; + /** + * 活动标题 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + * + * 活动被关闭后,不允许再次开启。 + */ + private Integer status; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 结束时间 + */ + private LocalDateTime endTime; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java new file mode 100644 index 0000000..12b6822 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 限时折扣商品 DO + * + * @author 芋道源码 + */ +@TableName(value = "promotion_discount_product", autoResultMap = true) +@KeySequence("promotion_discount_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DiscountProductDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + + /** + * 限时折扣活动的编号 + * + * 关联 {@link DiscountActivityDO#getId()} + */ + private Long activityId; + + /** + * 商品 SPU 编号 + * + * 关联 ProductSpuDO 的 id 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + * + * 关联 ProductSkuDO 的 id 编号 + */ + private Long skuId; + + /** + * 折扣类型 + * + * 枚举 {@link PromotionDiscountTypeEnum} + */ + private Integer discountType; + /** + * 折扣百分比 + * + * 例如,80% 为 80 + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + * + * 当 {@link #discountType} 为 {@link PromotionDiscountTypeEnum#PRICE} 生效 + */ + private Integer discountPrice; + + /** + * 活动状态 + * + * 关联 {@link DiscountActivityDO#getStatus()} + */ + private Integer activityStatus; + /** + * 活动开始时间点 + * + * 冗余 {@link DiscountActivityDO#getStartTime()} + */ + private LocalDateTime activityStartTime; + /** + * 活动结束时间点 + * + * 冗余 {@link DiscountActivityDO#getEndTime()} + */ + private LocalDateTime activityEndTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java new file mode 100644 index 0000000..e1c0dd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.diy; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.List; + +/** + * 装修页面 DO + * + * @author owen + */ +@TableName(value = "promotion_diy_page", autoResultMap = true) +@KeySequence("promotion_diy_page_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DiyPageDO extends BaseDO { + + /** + * 装修页面编号 + */ + @TableId + private Long id; + /** + * 装修模板编号 + * + * 关联 {@link DiyTemplateDO#getId()} + */ + private Long templateId; + /** + * 页面名称 + */ + private String name; + /** + * 备注 + */ + private String remark; + /** + * 预览图,多个逗号分隔 + */ + @TableField(typeHandler = StringListTypeHandler.class) + private List previewPicUrls; + /** + * 页面属性,JSON 格式 + */ + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java new file mode 100644 index 0000000..1b7e1d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.diy; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 装修模板 DO + * + * 1. 新建一个模版,下面可以包含多个 {@link DiyPageDO} 页面,例如说首页、我的 + * 2. 如果需要使用某个模版,则将 {@link #used} 设置为 true,表示已使用,有且仅有一个 + * + * @author owen + */ +@TableName(value = "promotion_diy_template", autoResultMap = true) +@KeySequence("promotion_diy_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DiyTemplateDO extends BaseDO { + + /** + * 装修模板编号 + */ + @TableId + private Long id; + /** + * 模板名称 + */ + private String name; + /** + * 是否使用 + */ + private Boolean used; + /** + * 使用时间 + */ + private LocalDateTime usedTime; + /** + * 备注 + */ + private String remark; + + /** + * 预览图 + */ + @TableField(typeHandler = StringListTypeHandler.class) + private List previewPicUrls; + /** + * uni-app 底部导航属性,JSON 格式 + */ + private String property; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java new file mode 100644 index 0000000..0c0b477 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 满减送活动 DO + * + * @author 芋道源码 + */ +@TableName(value = "promotion_reward_activity", autoResultMap = true) +@KeySequence("promotion_reward_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class RewardActivityDO extends BaseDO { + + /** + * 活动编号,主键自增 + */ + @TableId + private Long id; + /** + * 活动标题 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link PromotionActivityStatusEnum} + */ + private Integer status; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 结束时间 + */ + private LocalDateTime endTime; + /** + * 备注 + */ + private String remark; + /** + * 条件类型 + * + * 枚举 {@link PromotionConditionTypeEnum} + */ + private Integer conditionType; + /** + * 商品范围 + * + * 枚举 {@link PromotionProductScopeEnum} + */ + private Integer productScope; + /** + * 商品 SPU 编号的数组 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List productSpuIds; + /** + * 优惠规则的数组 + */ + @TableField(typeHandler = RuleTypeHandler.class) + private List rules; + + /** + * 优惠规则 + */ + @Data + public static class Rule implements Serializable { + + /** + * 优惠门槛 + * + * 1. 满 N 元,单位:分 + * 2. 满 N 件 + */ + private Integer limit; + /** + * 优惠价格,单位:分 + */ + private Integer discountPrice; + /** + * 是否包邮 + */ + private Boolean freeDelivery; + /** + * 赠送的积分 + */ + private Integer point; + /** + * 赠送的优惠劵编号的数组 + */ + private List couponIds; + /** + * 赠送的优惠券数量的数组 + */ + private List couponCounts; + + } + + // TODO @芋艿:可以找一些新的思路 + public static class RuleTypeHandler extends AbstractJsonTypeHandler> { + + @Override + protected List parse(String json) { + return JsonUtils.parseArray(json, Rule.class); + } + + @Override + protected String toJson(List obj) { + return JsonUtils.toJsonString(obj); + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java new file mode 100644 index 0000000..76a08ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +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 lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 秒杀活动 DO + * + * @author halfninety + */ +@TableName(value = "promotion_seckill_activity", autoResultMap = true) +@KeySequence("promotion_seckill_activity_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SeckillActivityDO extends BaseDO { + + /** + * 秒杀活动编号 + */ + @TableId + private Long id; + /** + * 秒杀活动商品 + */ + private Long spuId; + /** + * 秒杀活动名称 + */ + private String name; + /** + * 活动状态 + * + * 枚举 {@link CommonStatusEnum 对应的类} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 活动开始时间 + */ + private LocalDateTime startTime; + /** + * 活动结束时间 + */ + private LocalDateTime endTime; + /** + * 排序 + */ + private Integer sort; + /** + * 秒杀时段 id + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List configIds; + + /** + * 总限购数量 + */ + private Integer totalLimitCount; + /** + * 单次限够数量 + */ + private Integer singleLimitCount; + + /** + * 秒杀库存(剩余库存秒杀时扣减) + */ + private Integer stock; + /** + * 秒杀总库存 + */ + private Integer totalStock; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillConfigDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillConfigDO.java new file mode 100644 index 0000000..73efb7a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillConfigDO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 秒杀时段 DO + * + * @author 芋道源码 + */ +@TableName(value = "promotion_seckill_config", autoResultMap = true) +@KeySequence("promotion_seckill_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SeckillConfigDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 秒杀时段名称 + */ + private String name; + /** + * 开始时间点 + */ + private String startTime; + /** + * 结束时间点 + */ + private String endTime; + /** + * 秒杀轮播图 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List sliderPicUrls; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum 对应的类} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillProductDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillProductDO.java new file mode 100644 index 0000000..45a2d9e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillProductDO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 秒杀参与商品 DO + * + * @author HUIHUI + */ +@TableName("promotion_seckill_product") +@KeySequence("promotion_seckill_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SeckillProductDO extends BaseDO { + + /** + * 秒杀参与商品编号 + */ + @TableId + private Long id; + /** + * 秒杀活动 id + * + * 关联 {@link SeckillActivityDO#getId()} + */ + private Long activityId; + /** + * 秒杀时段 id + * + * 关联 {@link SeckillConfigDO#getId()} + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List configIds; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 秒杀金额,单位:分 + */ + private Integer seckillPrice; + /** + * 秒杀库存 + */ + private Integer stock; + + /** + * 秒杀商品状态 + * + * 枚举 {@link CommonStatusEnum 对应的类} + */ + private Integer activityStatus; + /** + * 活动开始时间点 + */ + private LocalDateTime activityStartTime; + /** + * 活动结束时间点 + */ + private LocalDateTime activityEndTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleCategoryMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleCategoryMapper.java new file mode 100644 index 0000000..d39264b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleCategoryMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 文章分类 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface ArticleCategoryMapper extends BaseMapperX { + + default PageResult selectPage(ArticleCategoryPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ArticleCategoryDO::getName, reqVO.getName()) + .eqIfPresent(ArticleCategoryDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(ArticleCategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ArticleCategoryDO::getSort)); + } + + default List selectListByStatus(Integer status) { + return selectList(ArticleCategoryDO::getStatus, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleMapper.java new file mode 100644 index 0000000..4ee8247 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 文章管理 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface ArticleMapper extends BaseMapperX { + + default PageResult selectPage(ArticlePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ArticleDO::getCategoryId, reqVO.getCategoryId()) + .eqIfPresent(ArticleDO::getTitle, reqVO.getTitle()) + .eqIfPresent(ArticleDO::getAuthor, reqVO.getAuthor()) + .eqIfPresent(ArticleDO::getStatus, reqVO.getStatus()) + .eqIfPresent(ArticleDO::getSpuId, reqVO.getSpuId()) + .eqIfPresent(ArticleDO::getRecommendHot, reqVO.getRecommendHot()) + .eqIfPresent(ArticleDO::getRecommendBanner, reqVO.getRecommendBanner()) + .betweenIfPresent(ArticleDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ArticleDO::getId)); + } + + default List selectList(Boolean recommendHot, Boolean recommendBanner) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ArticleDO::getRecommendHot, recommendHot) + .eqIfPresent(ArticleDO::getRecommendBanner, recommendBanner)); + } + + default List selectListByTitle(String title) { + return selectList(ArticleDO::getTitle, title); + } + + default PageResult selectPage(AppArticlePageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(ArticleDO::getCategoryId, pageReqVO.getCategoryId())); + } + + default void updateBrowseCount(Long id) { + update(null, new LambdaUpdateWrapper() + .eq(ArticleDO::getId, id) + .setSql("browse_count = browse_count + 1")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java new file mode 100644 index 0000000..74bd3c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.banner; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * Banner Mapper + * + * @author xia + */ +@Mapper +public interface BannerMapper extends BaseMapperX { + + default PageResult selectPage(BannerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BannerDO::getTitle, reqVO.getTitle()) + .eqIfPresent(BannerDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BannerDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BannerDO::getSort)); + } + + default void updateBrowseCount(Long id) { + update(null, new LambdaUpdateWrapper() + .eq(BannerDO::getId, id) + .setSql("browse_count = browse_count + 1")); + } + + default List selectBannerListByPosition(Integer position) { + return selectList(new LambdaQueryWrapperX().eq(BannerDO::getPosition, position)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java new file mode 100644 index 0000000..72d604e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java @@ -0,0 +1,120 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 砍价活动 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface BargainActivityMapper extends BaseMapperX { + + default PageResult selectPage(BargainActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BargainActivityDO::getName, reqVO.getName()) + .eqIfPresent(BargainActivityDO::getStatus, reqVO.getStatus()) + .orderByDesc(BargainActivityDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(BargainActivityDO::getStatus, status); + } + + /** + * 更新活动库存 + * + * @param id 活动编号 + * @param count 扣减的库存数量 + * @return 影响的行数 + */ + default int updateStock(Long id, int count) { + // 情况一:增加库存 + if (count > 0) { + return update(null, new LambdaUpdateWrapper() + .eq(BargainActivityDO::getId, id) + .setSql("stock = stock + " + count)); + } + // 情况二:扣减库存 + count = -count; // 取正 + return update(null, new LambdaUpdateWrapper() + .eq(BargainActivityDO::getId, id) + .ge(BargainActivityDO::getStock, count) + .setSql("stock = stock - " + count)); + } + + /** + * 查询处在 now 日期时间且是 status 状态的活动分页 + * + * @param pageReqVO 分页参数 + * @param status 状态 + * @param now 当前日期时间 + * @return 活动分页 + */ + default PageResult selectPage(PageParam pageReqVO, Integer status, LocalDateTime now) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(BargainActivityDO::getStatus, status) + .le(BargainActivityDO::getStartTime, now) + .ge(BargainActivityDO::getEndTime, now)); + } + + /** + * 查询处在 now 日期时间且是 status 状态的活动分页 + * + * @param status 状态 + * @param now 当前日期时间 + * @return 活动分页 + */ + default List selectList(Integer count, Integer status, LocalDateTime now) { + return selectList(new LambdaQueryWrapperX() + .eq(BargainActivityDO::getStatus, status) + .le(BargainActivityDO::getStartTime, now) + .ge(BargainActivityDO::getEndTime, now) + .last("LIMIT " + count)); + } + + /** + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + * + * @param spuIds spu 编号 + * @param status 状态 + * @return 包含 spuId 和 activityId 的 map 对象列表 + */ + default List> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection spuIds, Integer status) { + return selectMaps(new QueryWrapper() + .select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id + .in("spu_id", spuIds) + .eq("status", status) + .groupBy("spu_id")); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(BargainActivityDO::getId, ids) + .lt(BargainActivityDO::getStartTime, dateTime) + .gt(BargainActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(BargainActivityDO::getCreateTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainHelpMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainHelpMapper.java new file mode 100644 index 0000000..8d01ba3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainHelpMapper.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Mapper +public interface BargainHelpMapper extends BaseMapperX { + + default Long selectCountByUserIdAndActivityId(Long userId, Long activityId) { + return selectCount(new LambdaQueryWrapper<>(BargainHelpDO.class) + .eq(BargainHelpDO::getUserId, userId) + .eq(BargainHelpDO::getActivityId, activityId)); + } + + default Long selectUserCountMapByRecordId(Long recordId) { + return selectCount(BargainHelpDO::getRecordId, recordId); + } + + default BargainHelpDO selectByUserIdAndRecordId(Long userId, Long recordId) { + return selectOne(new LambdaQueryWrapper<>(BargainHelpDO.class) + .eq(BargainHelpDO::getUserId, userId) + .eq(BargainHelpDO::getRecordId, recordId)); + } + + default Map selectUserCountMapByActivityId(Collection activityIds) { + // SQL count 查询 + List> result = selectMaps(new QueryWrapper() + .select("COUNT(DISTINCT(user_id)) AS userCount, activity_id AS activityId") + .in("activity_id", activityIds) + .groupBy("activity_id")); + if (CollUtil.isEmpty(result)) { + return Collections.emptyMap(); + } + // 转换数据 + return CollectionUtils.convertMap(result, + record -> MapUtil.getLong(record, "activityId"), + record -> MapUtil.getInt(record, "userCount" )); + } + + default Map selectUserCountMapByRecordId(Collection recordIds) { + // SQL count 查询 + List> result = selectMaps(new QueryWrapper() + .select("COUNT(1) AS userCount, record_id AS recordId") + .in("record_id", recordIds) + .groupBy("record_id")); + if (CollUtil.isEmpty(result)) { + return Collections.emptyMap(); + } + // 转换数据 + return CollectionUtils.convertMap(result, + record -> MapUtil.getLong(record, "recordId"), + record -> MapUtil.getInt(record, "userCount" )); + } + + default PageResult selectPage(BargainHelpPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BargainHelpDO::getRecordId, reqVO.getRecordId()) + .orderByDesc(BargainHelpDO::getId)); + } + + default List selectListByRecordId(Long recordId) { + return selectList(new LambdaQueryWrapperX() + .eq(BargainHelpDO::getRecordId, recordId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainRecordMapper.java new file mode 100644 index 0000000..17560db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainRecordMapper.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 砍价记录 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface BargainRecordMapper extends BaseMapperX { + + default BargainRecordDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(BargainRecordDO::getId, id, + BargainRecordDO::getUserId, userId); + } + + default List selectListByUserIdAndActivityIdAndStatus( + Long userId, Long activityId, Integer status) { + return selectList(new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getUserId, userId) + .eq(BargainRecordDO::getActivityId, activityId) + .eq(BargainRecordDO::getStatus, status)); + } + + default BargainRecordDO selectLastByUserIdAndActivityId(Long userId, Long activityId) { + return selectOne(new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getUserId, userId) + .eq(BargainRecordDO::getActivityId, activityId) + .orderByDesc(BargainRecordDO::getId) + .last("LIMIT 1")); + } + + default Long selectCountByUserIdAndActivityIdAndStatus( + Long userId, Long activityId, Integer status) { + return selectCount(new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getUserId, userId) + .eq(BargainRecordDO::getActivityId, activityId) + .eq(BargainRecordDO::getStatus, status)); + } + + default int updateByIdAndBargainPrice(Long id, Integer whereBargainPrice, BargainRecordDO updateObj) { + return update(updateObj, new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getId, id) + .eq(BargainRecordDO::getBargainPrice, whereBargainPrice)); + } + + default Map selectUserCountByActivityIdsAndStatus(Collection activityIds, Integer status) { + // SQL count 查询 + List> result = selectMaps(new QueryWrapper() + .select("COUNT(DISTINCT(user_id)) AS userCount, activity_id AS activityId") + .in("activity_id", activityIds) + .eq(status != null, "status", status) + .groupBy("activity_id")); + if (CollUtil.isEmpty(result)) { + return Collections.emptyMap(); + } + // 转换数据 + return CollectionUtils.convertMap(result, + record -> MapUtil.getLong(record, "activityId"), + record -> MapUtil.getInt(record, "userCount" )); + } + + @Select("SELECT COUNT(DISTINCT(user_id)) FROM promotion_bargain_record " + + "WHERE status = #{status}") + Integer selectUserCountByStatus(@Param("status") Integer status); + + @Select("SELECT COUNT(DISTINCT(user_id)) FROM promotion_bargain_record " + + "WHERE activity_id = #{activityId} " + + "AND status = #{status}") + Integer selectUserCountByActivityIdAndStatus(@Param("activityId") Long activityId, + @Param("status") Integer status); + + default PageResult selectPage(BargainRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BargainRecordDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BargainRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BargainRecordDO::getId)); + } + + default PageResult selectBargainRecordPage(Long userId, PageParam pageParam) { + return selectPage(pageParam, new LambdaQueryWrapperX() + .eq(BargainRecordDO::getUserId, userId) + .orderByDesc(BargainRecordDO::getId)); + } + + default List selectListByStatusAndCount(Integer status, Integer count) { + return selectList(new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getStatus, status) + .last("LIMIT " + count)); + } + + /** + * 更新砍价的订单编号,前提是 orderId 原本是空的 + * + * @param id 砍价记录编号 + * @param orderId 订单编号 + * @return 更新数量 + */ + default int updateOrderIdById(Long id, Long orderId) { + return update(new BargainRecordDO().setOrderId(orderId).setEndTime(LocalDateTime.now()), + new LambdaQueryWrapper<>(BargainRecordDO.class) + .eq(BargainRecordDO::getId, id) + .isNull(BargainRecordDO::getOrderId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java new file mode 100644 index 0000000..55e975c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.combination; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 拼团活动 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CombinationActivityMapper extends BaseMapperX { + + default PageResult selectPage(CombinationActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(CombinationActivityDO::getName, reqVO.getName()) + .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus()) + .orderByDesc(CombinationActivityDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(CombinationActivityDO::getStatus, status); + } + + default PageResult selectPage(PageParam pageParam, Integer status) { + return selectPage(pageParam, new LambdaQueryWrapperX() + .eq(CombinationActivityDO::getStatus, status)); + } + + default List selectListByStatus(Integer status, Integer count) { + return selectList(new LambdaQueryWrapperX() + .eq(CombinationActivityDO::getStatus, status) + .last("LIMIT " + count)); + } + + /** + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + * @param spuIds spu 编号 + * @param status 状态 + * @return 包含 spuId 和 activityId 的 map 对象列表 + */ + default List> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(@Param("spuIds") Collection spuIds, @Param("status") Integer status) { + return selectMaps(new QueryWrapper() + .select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id + .in("spu_id", spuIds) + .eq("status", status) + .groupBy("spu_id")); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(CombinationActivityDO::getId, ids) + .lt(CombinationActivityDO::getStartTime, dateTime) + .gt(CombinationActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(CombinationActivityDO::getCreateTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java new file mode 100644 index 0000000..5d80b6d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.combination; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 拼团商品 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CombinationProductMapper extends BaseMapperX { + + default PageResult selectPage(CombinationProductPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CombinationProductDO::getActivityId, reqVO.getActivityId()) + .eqIfPresent(CombinationProductDO::getSpuId, reqVO.getSpuId()) + .eqIfPresent(CombinationProductDO::getSkuId, reqVO.getSkuId()) + .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus()) + .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime()) + .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime()) + .eqIfPresent(CombinationProductDO::getCombinationPrice, reqVO.getActivePrice()) + .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(CombinationProductDO::getId)); + } + + default List selectListByActivityIds(Collection ids) { + return selectList(CombinationProductDO::getActivityId, ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java new file mode 100644 index 0000000..04c1c61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.combination; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 拼团记录 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface CombinationRecordMapper extends BaseMapperX { + + default CombinationRecordDO selectByUserIdAndOrderId(Long userId, Long orderId) { + return selectOne(CombinationRecordDO::getUserId, userId, + CombinationRecordDO::getOrderId, orderId); + } + + /** + * 查询拼团记录 + * + * @param headId 团长编号 + * @return 拼团记录 + */ + default CombinationRecordDO selectByHeadId(Long headId, Integer status) { + return selectOne(new LambdaQueryWrapperX() + .eq(CombinationRecordDO::getId, headId) + .eq(CombinationRecordDO::getStatus, status)); + } + + /** + * 查询拼团记录 + * + * @param userId 用户 id + * @param activityId 活动 id + * @return 拼团记录 + */ + default List selectListByUserIdAndActivityId(Long userId, Long activityId) { + return selectList(new LambdaQueryWrapperX() + .eq(CombinationRecordDO::getUserId, userId) + .eq(CombinationRecordDO::getActivityId, activityId)); + } + + /** + * 获取最近的 count 条数据 + * + * @param count 数量 + * @return 拼团记录列表 + */ + default List selectLatestList(int count) { + return selectList(new LambdaQueryWrapperX() + .orderByDesc(CombinationRecordDO::getId) + .last("LIMIT " + count)); + } + + default List selectListByActivityIdAndStatusAndHeadId(Long activityId, Integer status, + Long headId, Integer count) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CombinationRecordDO::getActivityId, activityId) + .eqIfPresent(CombinationRecordDO::getStatus, status) + .eq(CombinationRecordDO::getHeadId, headId) + .orderByDesc(CombinationRecordDO::getId) + .last("LIMIT " + count)); + } + + default Map selectCombinationRecordCountMapByActivityIdAndStatusAndHeadId(Collection activityIds, + Integer status, Long headId) { + // SQL count 查询 + List> result = selectMaps(new QueryWrapper() + .select("COUNT(DISTINCT(user_id)) AS recordCount, activity_id AS activityId") + .in("activity_id", activityIds) + .eq(status != null, "status", status) + .eq(headId != null, "head_id", headId) + .groupBy("activity_id")); + if (CollUtil.isEmpty(result)) { + return Collections.emptyMap(); + } + // 转换数据 + return CollectionUtils.convertMap(result, + record -> MapUtil.getLong(record, "activityId"), + record -> MapUtil.getInt(record, "recordCount")); + } + + default PageResult selectPage(CombinationRecordReqPageVO pageVO) { + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + .eqIfPresent(CombinationRecordDO::getStatus, pageVO.getStatus()) + .betweenIfPresent(CombinationRecordDO::getCreateTime, pageVO.getCreateTime()); + // 如果 headId 非空,说明查询指定团的团长 + 团员的拼团记录 + if (pageVO.getHeadId() != null) { + queryWrapper.eq(CombinationRecordDO::getId, pageVO.getHeadId()) // 团长 + .or().eq(CombinationRecordDO::getHeadId, pageVO.getHeadId()); // 团员 + } + return selectPage(pageVO, queryWrapper); + } + + /** + * 查询指定条件的记录数 + * + * @param status 状态,可为 null + * @param virtualGroup 是否虚拟成团,可为 null + * @param headId 团长编号,可为 null + * @return 记录数 + */ + default Long selectCountByHeadAndStatusAndVirtualGroup(Integer status, Boolean virtualGroup, Long headId) { + return selectCount(new LambdaQueryWrapperX() + .eqIfPresent(CombinationRecordDO::getStatus, status) + .eqIfPresent(CombinationRecordDO::getVirtualGroup, virtualGroup) + .eqIfPresent(CombinationRecordDO::getHeadId, headId)); + } + + /** + * 查询用户拼团记录(DISTINCT 去重),也就是说查询会员表中的用户有多少人参与过拼团活动每个人只统计一次 + * + * @return 参加过拼团的用户数 + */ + default Long selectUserCount() { + return selectCount(new QueryWrapper() + .select("DISTINCT (user_id)")); + } + + default List selectListByHeadIdAndStatusAndExpireTimeLt(Long headId, Integer status, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .eq(CombinationRecordDO::getHeadId, headId) + .eq(CombinationRecordDO::getStatus, status) + .lt(CombinationRecordDO::getExpireTime, dateTime)); + } + + default List selectListByHeadId(Long headId) { + return selectList(CombinationRecordDO::getHeadId, headId); + } + + default PageResult selectPage(Long userId, AppCombinationRecordPageReqVO pageReqVO) { + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + .eq(CombinationRecordDO::getUserId, userId) + .eqIfPresent(CombinationRecordDO::getStatus, pageReqVO.getStatus()); + return selectPage(pageReqVO, queryWrapper); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java new file mode 100644 index 0000000..e5f1daf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yulichang.toolkit.MPJWrappers; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 优惠劵 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CouponMapper extends BaseMapperX { + + default PageResult selectPage(CouponPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CouponDO::getTemplateId, reqVO.getTemplateId()) + .eqIfPresent(CouponDO::getStatus, reqVO.getStatus()) + .inIfPresent(CouponDO::getUserId, reqVO.getUserIds()) + .betweenIfPresent(CouponDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(CouponDO::getId)); + } + + default List selectListByUserIdAndStatus(Long userId, Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getUserId, userId).eq(CouponDO::getStatus, status)); + } + + default CouponDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(new LambdaQueryWrapperX() + .eq(CouponDO::getId, id).eq(CouponDO::getUserId, userId)); + } + + default int delete(Long id, Collection whereStatuses) { + return update(null, new LambdaUpdateWrapper() + .eq(CouponDO::getId, id).in(CouponDO::getStatus, whereStatuses) + .set(CouponDO::getDeleted, 1)); + } + + default int updateByIdAndStatus(Long id, Integer status, CouponDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(CouponDO::getId, id).eq(CouponDO::getStatus, status)); + } + + default Long selectCountByUserIdAndStatus(Long userId, Integer status) { + return selectCount(new LambdaQueryWrapperX() + .eq(CouponDO::getUserId, userId) + .eq(CouponDO::getStatus, status)); + } + + default List selectListByTemplateIdAndUserId(Long templateId, Collection userIds) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getTemplateId, templateId) + .in(CouponDO::getUserId, userIds) + ); + } + + default Map selectCountByUserIdAndTemplateIdIn(Long userId, Collection templateIds) { + String templateIdAlias = "templateId"; + String countAlias = "count"; + List> list = selectMaps(MPJWrappers.lambdaJoin(CouponDO.class) + .selectAs(CouponDO::getTemplateId, templateIdAlias) + .selectCount(CouponDO::getId, countAlias) + .eq(CouponDO::getUserId, userId) + .in(CouponDO::getTemplateId, templateIds) + .groupBy(CouponDO::getTemplateId)); + return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias)); + } + + default List selectListByUserIdAndStatusAndUsePriceLeAndProductScope( + Long userId, Integer status, Integer usePrice, List spuIds, List categoryIds) { + Function, String> productScopeValuesFindInSetFunc = ids -> ids.stream() + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) + .collect(Collectors.joining(" OR ")); + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getUserId, userId) + .eq(CouponDO::getStatus, status) + .le(CouponDO::getUsePrice, usePrice) // 价格小于等于,满足价格使用条件 + .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) // 商品范围一:全部 + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) // 商品范围二:满足指定商品 + .apply(productScopeValuesFindInSetFunc.apply(spuIds))) + .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) // 商品范围三:满足指定分类 + .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); + } + + default List selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getStatus, status) + .le(CouponDO::getValidEndTime, validEndTime) + ); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java new file mode 100644 index 0000000..50e3c03 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.function.Consumer; + +/** + * 优惠劵模板 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CouponTemplateMapper extends BaseMapperX { + + default PageResult selectPage(CouponTemplatePageReqVO reqVO) { + // 构建可领取的查询条件 + Consumer> canTakeConsumer = buildCanTakeQueryConsumer(reqVO.getCanTakeTypes()); + // 执行分页查询 + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) + .eqIfPresent(CouponTemplateDO::getStatus, reqVO.getStatus()) + .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) + .betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(CouponTemplateDO::getProductScope, reqVO.getProductScope()) + .and(reqVO.getProductScopeValue() != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)", + reqVO.getProductScopeValue())) + .and(canTakeConsumer != null, canTakeConsumer) + .orderByDesc(CouponTemplateDO::getId)); + } + + default void updateTakeCount(Long id, Integer incrCount) { + update(null, new LambdaUpdateWrapper() + .eq(CouponTemplateDO::getId, id) + .setSql("take_count = take_count + " + incrCount)); + } + + default List selectListByTakeType(Integer takeType) { + return selectList(CouponTemplateDO::getTakeType, takeType); + } + + default List selectList(List canTakeTypes, Integer productScope, Long productScopeValue, Integer count) { + // 构建可领取的查询条件 + Consumer> canTakeConsumer = buildCanTakeQueryConsumer(canTakeTypes); + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CouponTemplateDO::getProductScope, productScope) + .and(productScopeValue != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)", + productScopeValue)) + .and(canTakeConsumer != null, canTakeConsumer) + .last(" LIMIT " + count) + .orderByDesc(CouponTemplateDO::getId)); + } + + static Consumer> buildCanTakeQueryConsumer(List canTakeTypes) { + Consumer> canTakeConsumer = null; + if (CollUtil.isNotEmpty(canTakeTypes)) { + canTakeConsumer = w -> + w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的 + .in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致 + .and(ww -> ww.gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()) // 3.1 未过期 + .or().eq(CouponTemplateDO::getValidityType, CouponTemplateValidityTypeEnum.TERM.getType())) // 3.2 领取之后 + .apply(" (take_count < total_count OR total_count = -1 )"); // 4. 剩余数量大于 0,或者无限领取 + } + return canTakeConsumer; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java new file mode 100644 index 0000000..efd4e4d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 限时折扣活动 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountActivityMapper extends BaseMapperX { + + default PageResult selectPage(DiscountActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DiscountActivityDO::getName, reqVO.getName()) + .eqIfPresent(DiscountActivityDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DiscountActivityDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DiscountActivityDO::getId)); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(DiscountActivityDO::getId, ids) + .lt(DiscountActivityDO::getStartTime, dateTime) + .gt(DiscountActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(DiscountActivityDO::getCreateTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java new file mode 100644 index 0000000..5257b83 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.discount; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 限时折扣商城 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountProductMapper extends BaseMapperX { + + default List selectListBySkuId(Collection skuIds) { + return selectList(DiscountProductDO::getSkuId, skuIds); + } + + default List selectListByActivityId(Long activityId) { + return selectList(DiscountProductDO::getActivityId, activityId); + } + + default List selectListByActivityId(Collection activityIds) { + return selectList(DiscountProductDO::getActivityId, activityIds); + } + + // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的 + List getMatchDiscountProductList(@Param("skuIds") Collection skuIds); + + /** + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + * + * @param spuIds spu 编号 + * @param status 状态 + * @return 包含 spuId 和 activityId 的 map 对象列表 + */ + default List> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection spuIds, Integer status) { + return selectMaps(new QueryWrapper() + .select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId") + .in("spu_id", spuIds) + .eq("activity_status", status) + .groupBy("spu_id")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyPageMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyPageMapper.java new file mode 100644 index 0000000..979b93f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyPageMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 装修页面 Mapper + * + * @author owen + */ +@Mapper +public interface DiyPageMapper extends BaseMapperX { + + default PageResult selectPage(DiyPagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DiyPageDO::getName, reqVO.getName()) + .betweenIfPresent(DiyPageDO::getCreateTime, reqVO.getCreateTime()) + // 模板下面的页面,在模板中管理 + .isNull(DiyPageDO::getTemplateId) + .orderByDesc(DiyPageDO::getId)); + } + + default List selectListByTemplateId(Long templateId) { + return selectList(DiyPageDO::getTemplateId, templateId); + } + + default DiyPageDO selectByNameAndTemplateIdIsNull(String name) { + return selectOne(new LambdaQueryWrapperX() + .eq(DiyPageDO::getName, name) + .isNull(DiyPageDO::getTemplateId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyTemplateMapper.java new file mode 100644 index 0000000..ca3c628 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/diy/DiyTemplateMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 装修模板 Mapper + * + * @author owen + */ +@Mapper +public interface DiyTemplateMapper extends BaseMapperX { + + default PageResult selectPage(DiyTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DiyTemplateDO::getName, reqVO.getName()) + .eqIfPresent(DiyTemplateDO::getUsed, reqVO.getUsed()) + .betweenIfPresent(DiyTemplateDO::getUsedTime, reqVO.getUsedTime()) + .betweenIfPresent(DiyTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DiyTemplateDO::getUsed) // 排序规则1:已使用的排到最前面 + .orderByDesc(DiyTemplateDO::getId)); // 排序规则2:新创建的排到前面 + } + + default DiyTemplateDO selectByUsed(boolean used) { + return selectOne(DiyTemplateDO::getUsed, used); + } + + default DiyTemplateDO selectByName(String name) { + return selectOne(DiyTemplateDO::getName, name); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java new file mode 100644 index 0000000..ca9e966 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.reward; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 满减送活动 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface RewardActivityMapper extends BaseMapperX { + + default PageResult selectPage(RewardActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RewardActivityDO::getName, reqVO.getName()) + .eqIfPresent(RewardActivityDO::getStatus, reqVO.getStatus()) + .orderByDesc(RewardActivityDO::getId)); + } + + default List selectListByStatus(Collection statuses) { + return selectList(RewardActivityDO::getStatus, statuses); + } + + default List selectListByProductScopeAndStatus(Integer productScope, Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(RewardActivityDO::getProductScope, productScope) + .eq(RewardActivityDO::getStatus, status)); + } + + default List selectListBySpuIdsAndStatus(Collection spuIds, Integer status) { + Function, String> productScopeValuesFindInSetFunc = ids -> ids.stream() + .map(id -> StrUtil.format("FIND_IN_SET({}, product_spu_ids) ", id)) + .collect(Collectors.joining(" OR ")); + return selectList(new QueryWrapper() + .eq("status", status) + .apply(productScopeValuesFindInSetFunc.apply(spuIds))); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(RewardActivityDO::getId, ids) + .lt(RewardActivityDO::getStartTime, dateTime) + .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(RewardActivityDO::getCreateTime) + ); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java new file mode 100644 index 0000000..ca40e76 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 秒杀活动 Mapper + * + * @author halfninety + */ +@Mapper +public interface SeckillActivityMapper extends BaseMapperX { + + default PageResult selectPage(SeckillActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SeckillActivityDO::getName, reqVO.getName()) + .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime()) + .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0") + .orderByDesc(SeckillActivityDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(SeckillActivityDO::getStatus, status)); + } + + /** + * 更新活动库存(减少) + * + * @param id 活动编号 + * @param count 扣减的库存数量(正数) + * @return 影响的行数 + */ + default int updateStockDecr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(SeckillActivityDO::getId, id) + .gt(SeckillActivityDO::getStock, count) + .setSql("stock = stock - " + count)); + } + + /** + * 更新活动库存(增加) + * + * @param id 活动编号 + * @param count 增加的库存数量(正数) + * @return 影响的行数 + */ + default int updateStockIncr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(SeckillActivityDO::getId, id) + .setSql("stock = stock + " + count)); + } + + default PageResult selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(SeckillActivityDO::getStatus, status) + // TODO 芋艿:对 find in set 的想法; + .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0")); + } + + /** + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + * + * @param spuIds spu 编号 + * @param status 状态 + * @return 包含 spuId 和 activityId 的 map 对象列表 + */ + default List> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(@Param("spuIds") Collection spuIds, @Param("status") Integer status) { + return selectMaps(new QueryWrapper() + .select("spu_id AS spuId, MAX(DISTINCT(id)) AS activityId") // 时间越大 id 也越大 直接用 id + .in("spu_id", spuIds) + .eq("status", status) + .groupBy("spu_id")); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(SeckillActivityDO::getId, ids) + .lt(SeckillActivityDO::getStartTime, dateTime) + .gt(SeckillActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(SeckillActivityDO::getCreateTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java new file mode 100644 index 0000000..8fb1401 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 秒杀活动商品 Mapper + * + * @author halfninety + */ +@Mapper +public interface SeckillProductMapper extends BaseMapperX { + + default List selectListByActivityId(Long activityId) { + return selectList(SeckillProductDO::getActivityId, activityId); + } + + default SeckillProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId) { + return selectOne(SeckillProductDO::getActivityId, activityId, + SeckillProductDO::getSkuId, skuId); + } + + default List selectListByActivityId(Collection ids) { + return selectList(SeckillProductDO::getActivityId, ids); + } + + /** + * 更新活动库存(减少) + * + * @param id 活动编号 + * @param count 扣减的库存数量(减少库存) + * @return 影响的行数 + */ + default int updateStockDecr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(SeckillProductDO::getId, id) + .ge(SeckillProductDO::getStock, count) + .setSql("stock = stock - " + count)); + } + + /** + * 更新活动库存(增加) + * + * @param id 活动编号 + * @param count 需要增加的库存(增加库存) + * @return 影响的行数 + */ + default int updateStockIncr(Long id, int count) { + Assert.isTrue(count > 0); + return update(null, new LambdaUpdateWrapper() + .eq(SeckillProductDO::getId, id) + .setSql("stock = stock + " + count)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java new file mode 100644 index 0000000..f1dcaca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SeckillConfigMapper extends BaseMapperX { + + default PageResult selectPage(SeckillConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SeckillConfigDO::getName, reqVO.getName()) + .eqIfPresent(SeckillConfigDO::getStatus, reqVO.getStatus()) + .orderByAsc(SeckillConfigDO::getStartTime)); + } + + default List selectListByStatus(Integer status) { + return selectList(SeckillConfigDO::getStatus, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/package-info.java new file mode 100644 index 0000000..b213191 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 promotion 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.promotion.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/config/PromotionWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/config/PromotionWebConfiguration.java new file mode 100644 index 0000000..3794547 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/config/PromotionWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * promotion 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class PromotionWebConfiguration { + + /** + * promotion 模块的 API 分组 + */ + @Bean + public GroupedOpenApi promotionGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("promotion"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/package-info.java new file mode 100644 index 0000000..8359130 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * promotion 模块的 web 配置 + */ +package cn.iocoder.yudao.module.promotion.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/combination/CombinationRecordExpireJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/combination/CombinationRecordExpireJob.java new file mode 100644 index 0000000..fc0e4c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/combination/CombinationRecordExpireJob.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.job.combination; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 拼团过期 Job + * + * @author HUIHUI + */ +@Component +public class CombinationRecordExpireJob implements JobHandler { + + @Resource + private CombinationRecordService combinationRecordService; + + @Override + @TenantJob + public String execute(String param) { + KeyValue keyValue = combinationRecordService.expireCombinationRecord(); + return StrUtil.format("过期拼团 {} 个, 虚拟成团 {} 个", keyValue.getKey(), keyValue.getValue()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/coupon/CouponExpireJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/coupon/CouponExpireJob.java new file mode 100644 index 0000000..e680628 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/coupon/CouponExpireJob.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.job.coupon; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +// TODO 芋艿:配置一个 Job +/** + * 优惠券过期 Job + * + * @author owen + */ +@Component +public class CouponExpireJob implements JobHandler { + + @Resource + private CouponService couponService; + + @Override + @TenantJob + public String execute(String param) { + int count = couponService.expireCoupon(); + return StrUtil.format("过期优惠券 {} 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/package-info.java new file mode 100644 index 0000000..320b98a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 占位,无具体含义 + */ +package cn.iocoder.yudao.module.promotion.job; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/CouponTakeByRegisterConsumer.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/CouponTakeByRegisterConsumer.java new file mode 100644 index 0000000..4d7a092 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/CouponTakeByRegisterConsumer.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.promotion.mq.consumer.coupon; + +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 用户注册时,发送优惠劵的消费者,基 {@link MemberUserCreateMessage} 消息 + * + * @author owen + */ +@Component +@Slf4j +public class CouponTakeByRegisterConsumer { + + @Resource + private CouponService couponService; + + @EventListener + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + public void onMessage(MemberUserCreateMessage message) { + log.info("[onMessage][消息内容({})]", message); + couponService.takeCouponByRegister(message.getUserId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/package-info.java new file mode 100644 index 0000000..95c23df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消费者 + */ +package cn.iocoder.yudao.module.promotion.mq.consumer; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/package-info.java new file mode 100644 index 0000000..912504e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package cn.iocoder.yudao.module.promotion.mq.message; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/producer/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/producer/package-info.java new file mode 100644 index 0000000..e7b8d1b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/producer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的生产者 + */ +package cn.iocoder.yudao.module.promotion.mq.producer; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/package-info.java new file mode 100644 index 0000000..c022c62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/package-info.java @@ -0,0 +1,8 @@ +/** + * promotion 模块,我们放营销业务。 + * 例如说:营销活动、banner、优惠券等等 + * + * 1. Controller URL:以 /promotion/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 promotion_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.promotion; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryService.java new file mode 100644 index 0000000..7ce7c0a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryService.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 文章分类 Service 接口 + * + * @author HUIHUI + */ +public interface ArticleCategoryService { + + /** + * 创建文章分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createArticleCategory(@Valid ArticleCategoryCreateReqVO createReqVO); + + /** + * 更新文章分类 + * + * @param updateReqVO 更新信息 + */ + void updateArticleCategory(@Valid ArticleCategoryUpdateReqVO updateReqVO); + + /** + * 删除文章分类 + * + * @param id 编号 + */ + void deleteArticleCategory(Long id); + + /** + * 获得文章分类 + * + * @param id 编号 + * @return 文章分类 + */ + ArticleCategoryDO getArticleCategory(Long id); + + /** + * 获得文章分类分页 + * + * @param pageReqVO 分页查询 + * @return 文章分类分页 + */ + PageResult getArticleCategoryPage(ArticleCategoryPageReqVO pageReqVO); + + /** + * 获得指定状态的文章分类列表 + * + * @param status 状态 + * @return 文章分类列表 + */ + List getArticleCategoryListByStatus(Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImpl.java new file mode 100644 index 0000000..9375f49 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImpl.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleCategoryConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleCategoryMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_NOT_EXISTS; + +/** + * 文章分类 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class ArticleCategoryServiceImpl implements ArticleCategoryService { + + @Resource + private ArticleCategoryMapper articleCategoryMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖问题 + private ArticleService articleService; + + @Override + public Long createArticleCategory(ArticleCategoryCreateReqVO createReqVO) { + // 插入 + ArticleCategoryDO category = ArticleCategoryConvert.INSTANCE.convert(createReqVO); + articleCategoryMapper.insert(category); + // 返回 + return category.getId(); + } + + @Override + public void updateArticleCategory(ArticleCategoryUpdateReqVO updateReqVO) { + // 校验存在 + validateArticleCategoryExists(updateReqVO.getId()); + // 更新 + ArticleCategoryDO updateObj = ArticleCategoryConvert.INSTANCE.convert(updateReqVO); + articleCategoryMapper.updateById(updateObj); + } + + @Override + public void deleteArticleCategory(Long id) { + // 校验存在 + validateArticleCategoryExists(id); + // 校验是不是存在关联文章 + Long count = articleService.getArticleCountByCategoryId(id); + if (count > 0) { + throw exception(ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES); + } + + // 删除 + articleCategoryMapper.deleteById(id); + } + + private void validateArticleCategoryExists(Long id) { + if (articleCategoryMapper.selectById(id) == null) { + throw exception(ARTICLE_CATEGORY_NOT_EXISTS); + } + } + + @Override + public ArticleCategoryDO getArticleCategory(Long id) { + return articleCategoryMapper.selectById(id); + } + + @Override + public PageResult getArticleCategoryPage(ArticleCategoryPageReqVO pageReqVO) { + return articleCategoryMapper.selectPage(pageReqVO); + } + + @Override + public List getArticleCategoryListByStatus(Integer status) { + return articleCategoryMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java new file mode 100644 index 0000000..24b0fc9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 文章 Service 接口 + * + * @author HUIHUI + */ +public interface ArticleService { + + /** + * 创建文章 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createArticle(@Valid ArticleCreateReqVO createReqVO); + + /** + * 更新文章 + * + * @param updateReqVO 更新信息 + */ + void updateArticle(@Valid ArticleUpdateReqVO updateReqVO); + + /** + * 删除文章 + * + * @param id 编号 + */ + void deleteArticle(Long id); + + /** + * 获得文章 + * + * @param id 编号 + * @return 文章 + */ + ArticleDO getArticle(Long id); + + /** + * 基于标题,获得文章 + * + * 如果有重名的文章,获取最后发布的 + * + * @param title 标题 + * @return 文章 + */ + ArticleDO getLastArticleByTitle(String title); + + /** + * 获得文章分页 + * + * @param pageReqVO 分页查询 + * @return 文章分页 + */ + PageResult getArticlePage(ArticlePageReqVO pageReqVO); + + /** + * 获得文章列表 + * + * @param recommendHot 是否热门 + * @param recommendBanner 是否轮播图 + * @return 文章列表 + */ + List getArticleCategoryListByRecommend(Boolean recommendHot, Boolean recommendBanner); + + /** + * 获得文章分页 + * + * @param pageReqVO 分页查询 + * @return 文章分页 + */ + PageResult getArticlePage(AppArticlePageReqVO pageReqVO); + + /** + * 获得指定分类的文章数量 + * + * @param categoryId 文章分类编号 + * @return 文章数量 + */ + Long getArticleCountByCategoryId(Long categoryId); + + /** + * 增加文章浏览量 + * + * @param id 文章编号 + */ + void addArticleBrowseCount(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java new file mode 100644 index 0000000..2488365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java @@ -0,0 +1,123 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.convert.article.ArticleConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_NOT_EXISTS; + +/** + * 文章管理 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class ArticleServiceImpl implements ArticleService { + + @Resource + private ArticleMapper articleMapper; + + @Resource + private ArticleCategoryService articleCategoryService; + + @Override + public Long createArticle(ArticleCreateReqVO createReqVO) { + // 校验分类存在 + validateArticleCategoryExists(createReqVO.getCategoryId()); + + // 插入 + ArticleDO article = ArticleConvert.INSTANCE.convert(createReqVO); + article.setBrowseCount(0); // 初始浏览量 + articleMapper.insert(article); + // 返回 + return article.getId(); + } + + @Override + public void updateArticle(ArticleUpdateReqVO updateReqVO) { + // 校验存在 + validateArticleExists(updateReqVO.getId()); + // 校验分类存在 + validateArticleCategoryExists(updateReqVO.getCategoryId()); + + // 更新 + ArticleDO updateObj = ArticleConvert.INSTANCE.convert(updateReqVO); + articleMapper.updateById(updateObj); + } + + @Override + public void deleteArticle(Long id) { + // 校验存在 + validateArticleExists(id); + // 删除 + articleMapper.deleteById(id); + } + + private void validateArticleExists(Long id) { + if (articleMapper.selectById(id) == null) { + throw exception(ARTICLE_NOT_EXISTS); + } + } + + private void validateArticleCategoryExists(Long categoryId) { + ArticleCategoryDO articleCategory = articleCategoryService.getArticleCategory(categoryId); + if (articleCategory == null) { + throw exception(ARTICLE_CATEGORY_NOT_EXISTS); + } + } + + @Override + public ArticleDO getArticle(Long id) { + return articleMapper.selectById(id); + } + + @Override + public ArticleDO getLastArticleByTitle(String title) { + List articles = articleMapper.selectListByTitle(title); + return CollUtil.getLast(articles); + } + + @Override + public PageResult getArticlePage(ArticlePageReqVO pageReqVO) { + return articleMapper.selectPage(pageReqVO); + } + + @Override + public List getArticleCategoryListByRecommend(Boolean recommendHot, Boolean recommendBanner) { + return articleMapper.selectList(recommendHot, recommendBanner); + } + + @Override + public PageResult getArticlePage(AppArticlePageReqVO pageReqVO) { + return articleMapper.selectPage(pageReqVO); + } + + @Override + public Long getArticleCountByCategoryId(Long categoryId) { + return articleMapper.selectCount(ArticleDO::getCategoryId, categoryId); + } + + @Override + public void addArticleBrowseCount(Long id) { + // 校验文章是否存在 + validateArticleExists(id); + // 增加浏览次数 + articleMapper.updateBrowseCount(id); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java new file mode 100644 index 0000000..404f7f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.promotion.service.banner; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 首页 Banner Service 接口 + * + * @author xia + */ +public interface BannerService { + + /** + * 创建 Banner + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBanner(@Valid BannerCreateReqVO createReqVO); + + /** + * 更新 Banner + * + * @param updateReqVO 更新信息 + */ + void updateBanner(@Valid BannerUpdateReqVO updateReqVO); + + /** + * 删除 Banner + * + * @param id 编号 + */ + void deleteBanner(Long id); + + /** + * 获得 Banner + * + * @param id 编号 + * @return Banner + */ + BannerDO getBanner(Long id); + + /** + * 获得 Banner 分页 + * + * @param pageReqVO 分页查询 + * @return Banner分页 + */ + PageResult getBannerPage(BannerPageReqVO pageReqVO); + + /** + * 增加 Banner 点击量 + * + * @param id Banner编号 + */ + void addBannerBrowseCount(Long id); + + /** + * 获得 Banner 列表 + * + * @param position 定位 + * @return Banner 列表 + */ + List getBannerListByPosition(Integer position); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java new file mode 100644 index 0000000..46c22f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.promotion.service.banner; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.banner.BannerConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.banner.BannerMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BANNER_NOT_EXISTS; + +/** + * 首页 banner 实现类 + * + * @author xia + */ +@Service +@Validated +public class BannerServiceImpl implements BannerService { + + @Resource + private BannerMapper bannerMapper; + + @Override + public Long createBanner(BannerCreateReqVO createReqVO) { + // 插入 + BannerDO banner = BannerConvert.INSTANCE.convert(createReqVO); + bannerMapper.insert(banner); + // 返回 + return banner.getId(); + } + + @Override + public void updateBanner(BannerUpdateReqVO updateReqVO) { + // 校验存在 + this.validateBannerExists(updateReqVO.getId()); + // 更新 + BannerDO updateObj = BannerConvert.INSTANCE.convert(updateReqVO); + bannerMapper.updateById(updateObj); + } + + @Override + public void deleteBanner(Long id) { + // 校验存在 + this.validateBannerExists(id); + // 删除 + bannerMapper.deleteById(id); + } + + private void validateBannerExists(Long id) { + if (bannerMapper.selectById(id) == null) { + throw exception(BANNER_NOT_EXISTS); + } + } + + @Override + public BannerDO getBanner(Long id) { + return bannerMapper.selectById(id); + } + + @Override + public PageResult getBannerPage(BannerPageReqVO pageReqVO) { + return bannerMapper.selectPage(pageReqVO); + } + + @Override + public void addBannerBrowseCount(Long id) { + // 校验 Banner 是否存在 + validateBannerExists(id); + // 增加点击次数 + bannerMapper.updateBrowseCount(id); + } + + @Override + public List getBannerListByPosition(Integer position) { + return bannerMapper.selectBannerListByPosition(position); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java new file mode 100644 index 0000000..e1d2702 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java @@ -0,0 +1,120 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 砍价活动 Service 接口 + * + * @author HUIHUI + */ +public interface BargainActivityService { + + /** + * 创建砍价活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBargainActivity(@Valid BargainActivityCreateReqVO createReqVO); + + /** + * 更新砍价活动 + * + * @param updateReqVO 更新信息 + */ + void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO); + + /** + * 更新砍价活动库存 + * + * 如果更新失败(库存不足),则抛出业务异常 + * + * @param id 砍价活动编号 + * @param count 购买数量 + */ + void updateBargainActivityStock(Long id, Integer count); + + /** + * 关闭砍价活动 + * + * @param id 砍价活动编号 + */ + void closeBargainActivityById(Long id); + + /** + * 删除砍价活动 + * + * @param id 编号 + */ + void deleteBargainActivity(Long id); + + /** + * 获得砍价活动 + * + * @param id 编号 + * @return 砍价活动 + */ + BargainActivityDO getBargainActivity(Long id); + + /** + * 获得砍价活动列表 + * + * @param ids 编号数组 + * @return 砍价活动列表 + */ + List getBargainActivityList(Set ids); + + /** + * 校验砍价活动,是否可以参与(发起砍价、下单、帮好友砍价) + * + * @param id 编号 + * @return 砍价活动 + */ + BargainActivityDO validateBargainActivityCanJoin(Long id); + + /** + * 获得砍价活动分页 + * + * @param pageReqVO 分页查询 + * @return 砍价活动分页 + */ + PageResult getBargainActivityPage(BargainActivityPageReqVO pageReqVO); + + /** + * 获取正在进行的活动分页数据 + * + * @param pageReqVO 分页请求 + * @return 砍价活动分页 + */ + PageResult getBargainActivityPage(PageParam pageReqVO); + + /** + * 获取正在进行的活动分页数据 + * + * @param count 需要的数量 + * @return 砍价活动分页 + */ + List getBargainActivityListByCount(Integer count); + + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 日期时间 + * @return 砍价活动列表 + */ + List getBargainActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java new file mode 100644 index 0000000..4ee6220 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java @@ -0,0 +1,208 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainActivityMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 砍价活动 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class BargainActivityServiceImpl implements BargainActivityService { + + @Resource + private BargainActivityMapper bargainActivityMapper; + + @Resource + private ProductSkuApi productSkuApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) { + // 校验商品 SPU 是否存在是否参加的别的活动 + validateBargainConflict(createReqVO.getSpuId(), null); + // 校验商品 sku 是否存在 + validateSku(createReqVO.getSkuId()); + + // 插入砍价活动 + BargainActivityDO activityDO = BargainActivityConvert.INSTANCE.convert(createReqVO) + .setTotalStock(createReqVO.getStock()) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + bargainActivityMapper.insert(activityDO); + return activityDO.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) { + // 校验存在 + BargainActivityDO activity = validateBargainActivityExists(updateReqVO.getId()); + // 校验状态 + if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + throw exception(BARGAIN_ACTIVITY_STATUS_DISABLE); + } + // 校验商品冲突 + validateBargainConflict(updateReqVO.getSpuId(), updateReqVO.getId()); + // 校验商品 sku 是否存在 + validateSku(updateReqVO.getSkuId()); + + // 更新 + BargainActivityDO updateObj = BargainActivityConvert.INSTANCE.convert(updateReqVO); + if (updateObj.getStock() > activity.getTotalStock()) { // 如果更新的库存大于原来的库存,则更新总库存 + updateObj.setTotalStock(updateObj.getStock()); + } + bargainActivityMapper.updateById(updateObj); + } + + @Override + public void updateBargainActivityStock(Long id, Integer count) { + if (count < 0) { + // 更新库存。如果更新失败,则抛出异常 + int updateCount = bargainActivityMapper.updateStock(id, count); + if (updateCount == 0) { + throw exception(BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH); + } + } else if (count > 0) { + bargainActivityMapper.updateStock(id, count); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void closeBargainActivityById(Long id) { + // 校验砍价活动是否存在 + BargainActivityDO activity = validateBargainActivityExists(id); + if (CommonStatusEnum.isDisable(activity.getStatus())) { + throw exception(BARGAIN_ACTIVITY_STATUS_DISABLE); + } + + bargainActivityMapper.updateById(new BargainActivityDO().setId(id) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + } + + private void validateBargainConflict(Long spuId, Long activityId) { + // 查询所有开启的砍价活动 + List activityList = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + if (activityId != null) { // 更新时排除自己 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); + } + // 校验商品 spu 是否参加了其它活动 + if (anyMatch(activityList, activity -> ObjectUtil.equal(activity.getSpuId(), spuId))) { + throw exception(BARGAIN_ACTIVITY_SPU_CONFLICTS); + } + } + + private void validateSku(Long skuId) { + ProductSkuRespDTO sku = productSkuApi.getSku(skuId); + if (sku == null) { + throw exception(SKU_NOT_EXISTS); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBargainActivity(Long id) { + // 校验存在 + BargainActivityDO activityDO = validateBargainActivityExists(id); + // 校验状态 + if (CommonStatusEnum.isEnable(activityDO.getStatus())) { + throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); + } + + // 删除 + bargainActivityMapper.deleteById(id); + } + + private BargainActivityDO validateBargainActivityExists(Long id) { + BargainActivityDO activityDO = bargainActivityMapper.selectById(id); + if (activityDO == null) { + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS); + } + return activityDO; + } + + @Override + public BargainActivityDO getBargainActivity(Long id) { + return bargainActivityMapper.selectById(id); + } + + @Override + public List getBargainActivityList(Set ids) { + return bargainActivityMapper.selectBatchIds(ids); + } + + @Override + public BargainActivityDO validateBargainActivityCanJoin(Long id) { + BargainActivityDO activity = bargainActivityMapper.selectById(id); + if (activity == null) { + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(activity.getStatus())) { + throw exception(BARGAIN_ACTIVITY_STATUS_CLOSED); + } + if (activity.getStock() <= 0) { + throw exception(BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH); + } + if (!LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) { + throw exception(BARGAIN_ACTIVITY_TIME_END); + } + return activity; + } + + @Override + public PageResult getBargainActivityPage(BargainActivityPageReqVO pageReqVO) { + return bargainActivityMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getBargainActivityPage(PageParam pageReqVO) { + // 只查询进行中,且在时间范围内的 + return bargainActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); + } + + @Override + public List getBargainActivityListByCount(Integer count) { + return bargainActivityMapper.selectList(count, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); + } + + @Override + public List getBargainActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + List> spuIdAndActivityIdMaps = bargainActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) { + return Collections.emptyList(); + } + // 2. 查询活动详情 + return bargainActivityMapper.selectListByIdsAndDateTimeLt( + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpService.java new file mode 100644 index 0000000..8aec485 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpService.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpCreateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 砍价助力 Service 接口 + * + * @author 芋道源码 + */ +public interface BargainHelpService { + + /** + * 创建砍价助力(帮人砍价) + * + * @param userId 用户编号 + * @param reqVO 请求信息 + * @return 砍价助力记录 + */ + BargainHelpDO createBargainHelp(Long userId, AppBargainHelpCreateReqVO reqVO); + + /** + * 【砍价活动】获得助力人数 Map + * + * @param activityIds 活动编号 + * @return 助力人数 Map + */ + Map getBargainHelpUserCountMapByActivity(Collection activityIds); + + /** + * 【砍价记录】获得助力人数 Map + * + * @param recordIds 记录编号 + * @return 助力人数 Map + */ + Map getBargainHelpUserCountMapByRecord(Collection recordIds); + + /** + * 【砍价活动】获得用户的助力次数 + * + * @param activityId 活动编号 + * @param userId 用户编号 + * @return 助力次数 + */ + Long getBargainHelpCountByActivity(Long activityId, Long userId); + + /** + * 获得砍价助力分页 + * + * @param pageReqVO 分页查询 + * @return 砍价助力分页 + */ + PageResult getBargainHelpPage(BargainHelpPageReqVO pageReqVO); + + /** + * 获得指定砍价记录编号,对应的砍价助力列表 + * + * @param recordId 砍价记录编号 + * @return 砍价助力列表 + */ + List getBargainHelpListByRecordId(Long recordId); + + /** + * 获得助力记录 + * + * @param recordId 砍价记录编号 + * @param userId 用户编号 + * @return 助力记录 + */ + BargainHelpDO getBargainHelp(Long recordId, Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpServiceImpl.java new file mode 100644 index 0000000..1106ce4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainHelpServiceImpl.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpCreateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainHelpMapper; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import jodd.util.MathUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 砍价助力 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BargainHelpServiceImpl implements BargainHelpService { + + @Resource + private BargainHelpMapper bargainHelpMapper; + + @Resource + private BargainRecordService bargainRecordService; + @Resource + private BargainActivityService bargainActivityService; + + @Override + @Transactional(rollbackFor = Exception.class) + public BargainHelpDO createBargainHelp(Long userId, AppBargainHelpCreateReqVO reqVO) { + // 1.1 校验砍价记录存在,并且处于进行中 + BargainRecordDO record = bargainRecordService.getBargainRecord(reqVO.getRecordId()); + if (record == null) { + throw exception(BARGAIN_RECORD_NOT_EXISTS); + } + if (ObjUtil.notEqual(record.getStatus(), BargainRecordStatusEnum.IN_PROGRESS.getStatus())) { + throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_NOT_IN_PROCESS); + } + // 1.2 不能自己给自己砍价 + if (ObjUtil.equal(record.getUserId(), userId)) { + throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_SELF); + } + + // 2.1 校验砍价活动 + BargainActivityDO activity = bargainActivityService.getBargainActivity(record.getActivityId()); + // 2.2 校验自己是否助力次数上限 + if (bargainHelpMapper.selectCountByUserIdAndActivityId(userId, activity.getId()) + >= activity.getBargainCount()) { + throw exception(BARGAIN_HELP_CREATE_FAIL_LIMIT); + } + // 2.3 特殊情况:砍价已经砍到最低价,不能再砍了 + if (record.getBargainPrice() <= activity.getBargainMinPrice()) { + throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_NOT_IN_PROCESS); + } + + // 3. 已经助力 + if (bargainHelpMapper.selectByUserIdAndRecordId(userId, record.getId()) != null) { + throw exception(BARGAIN_HELP_CREATE_FAIL_HELP_EXISTS); + } + + // 4.1 计算砍价金额 + Integer reducePrice = calculateReducePrice(activity, record); + Assert.isTrue(reducePrice > 0, "砍价金额必须大于 0 元"); + // 4.2 创建助力记录 + BargainHelpDO help = BargainHelpDO.builder().userId(userId).activityId(activity.getId()) + .recordId(record.getId()).reducePrice(reducePrice).build(); + bargainHelpMapper.insert(help); + + // 5. 判断砍价记录是否完成 + Boolean success = record.getBargainPrice() - reducePrice <= activity.getBargainMinPrice() // 情况一:砍价已经砍到最低价 + || bargainHelpMapper.selectUserCountMapByRecordId(reqVO.getRecordId()) >= activity.getHelpMaxCount(); // 情况二:砍价助力已经达到上限 + if (!bargainRecordService.updateBargainRecordBargainPrice( + record.getId(), record.getBargainPrice(), reducePrice, success)) { + // 多人一起砍价,需要重试 + throw exception(BARGAIN_HELP_CREATE_FAIL_CONFLICT); + } + return help; + } + + // TODO 芋艿:优化点:实现一个更随机的逻辑,可以按照你自己的业务; + private Integer calculateReducePrice(BargainActivityDO activity, BargainRecordDO record) { + // 1. 随机金额 + Integer reducePrice = MathUtil.randomInt(activity.getBargainMinPrice(), + activity.getRandomMaxPrice() + 1); // + 1 的原因是,randomInt 默认不包含第二个参数 + // 2. 校验是否超过砍价上限 + if (record.getBargainPrice() - reducePrice < activity.getBargainMinPrice()) { + reducePrice = record.getBargainPrice() - activity.getBargainMinPrice(); + } + return reducePrice; + } + + @Override + public Map getBargainHelpUserCountMapByActivity(Collection activityIds) { + return bargainHelpMapper.selectUserCountMapByActivityId(activityIds); + } + + @Override + public Map getBargainHelpUserCountMapByRecord(Collection recordIds) { + return bargainHelpMapper.selectUserCountMapByRecordId(recordIds); + } + + @Override + public Long getBargainHelpCountByActivity(Long activityId, Long userId) { + return bargainHelpMapper.selectCountByUserIdAndActivityId(userId, activityId); + } + + @Override + public PageResult getBargainHelpPage(BargainHelpPageReqVO pageReqVO) { + return bargainHelpMapper.selectPage(pageReqVO); + } + + @Override + public List getBargainHelpListByRecordId(Long recordId) { + return bargainHelpMapper.selectListByRecordId(recordId); + } + + @Override + public BargainHelpDO getBargainHelp(Long recordId, Long userId) { + return bargainHelpMapper.selectByUserIdAndRecordId(userId, recordId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordService.java new file mode 100644 index 0000000..e3ba206 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordService.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 砍价记录 service 接口 + * + * @author HUIHUI + */ +public interface BargainRecordService { + + /** + * 【会员】创建砍价记录(参与参加活动) + * + * @param userId 用户编号 + * @param reqVO 创建信息 + * @return 砍价记录编号 + */ + Long createBargainRecord(Long userId, AppBargainRecordCreateReqVO reqVO); + + /** + * 更新砍价记录的砍价金额 + * + * 如果满足砍价成功的条件,则更新砍价记录的状态为成功 + * + * @param id 砍价记录编号 + * @param whereBargainPrice 当前的砍价金额 + * @param reducePrice 减少的砍价金额 + * @param success 是否砍价成功 + * @return 是否更新成功。注意,如果并发更新时,会更新失败 + */ + Boolean updateBargainRecordBargainPrice(Long id, Integer whereBargainPrice, + Integer reducePrice, Boolean success); + + /** + * 【下单前】校验是否参与砍价活动 + *

+ * 如果校验失败,则抛出业务异常 + * + * @param userId 用户编号 + * @param bargainRecordId 砍价活动编号 + * @param skuId SKU 编号 + * @return 砍价信息 + */ + BargainValidateJoinRespDTO validateJoinBargain(Long userId, Long bargainRecordId, Long skuId); + + /** + * 更新砍价记录的订单编号 + * + * 在砍价成功后,用户发起订单后,会记录该订单编号 + * + * @param id 砍价记录编号 + * @param orderId 订单编号 + */ + void updateBargainRecordOrderId(Long id, Long orderId); + + /** + * 获得砍价记录 + * + * @param id 砍价记录编号 + * @return 砍价记录 + */ + BargainRecordDO getBargainRecord(Long id); + + /** + * 获得用户在当前砍价活动中的最后一条砍价记录 + * + * @param userId 用户编号 + * @param activityId 砍价记录编号 + * @return 砍价记录 + */ + BargainRecordDO getLastBargainRecord(Long userId, Long activityId); + + /** + * 获得砍价人数 Map + * + * @param activityIds 活动编号 + * @param status 砍价记录状态 + * @return 砍价人数 Map + */ + Map getBargainRecordUserCountMap(Collection activityIds, @Nullable Integer status); + + /** + * 获得砍价人数 + * + * @param status 砍价记录状态 + * @return 砍价人数 + */ + Integer getBargainRecordUserCount(Integer status); + + /** + * 获得砍价人数 + * + * @param activityId 砍价活动编号 + * @param status 砍价记录状态 + * @return 砍价人数 + */ + Integer getBargainRecordUserCount(Long activityId, Integer status); + + /** + * 【管理员】获得砍价记录分页 + * + * @param pageReqVO 分页查询 + * @return 砍价记录分页 + */ + PageResult getBargainRecordPage(BargainRecordPageReqVO pageReqVO); + + /** + * 【会员】获得砍价记录分页 + * + * @param userId 用户编号 + * @param pageParam 分页查询 + * @return 砍价记录分页 + */ + PageResult getBargainRecordPage(Long userId, PageParam pageParam); + + /** + * 获得砍价记录列表 + * + * @param status 砍价记录状态 + * @param count 条数 + * @return 砍价记录列表 + */ + List getBargainRecordList(Integer status, Integer count); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordServiceImpl.java new file mode 100644 index 0000000..aa6db4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordServiceImpl.java @@ -0,0 +1,152 @@ +package cn.iocoder.yudao.module.promotion.service.bargain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.recrod.BargainRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainRecordMapper; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Nullable; +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 砍价记录 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class BargainRecordServiceImpl implements BargainRecordService { + + @Resource + private BargainActivityService bargainActivityService; + + @Resource + private BargainRecordMapper bargainRecordMapper; + + @Override + public Long createBargainRecord(Long userId, AppBargainRecordCreateReqVO reqVO) { + // 1. 校验砍价活动(包括库存) + BargainActivityDO activity = bargainActivityService.validateBargainActivityCanJoin(reqVO.getActivityId()); + + // 2.1 校验当前是否已经有参与中的砍价活动 + if (CollUtil.isNotEmpty(bargainRecordMapper.selectListByUserIdAndActivityIdAndStatus( + userId, reqVO.getActivityId(), BargainRecordStatusEnum.IN_PROGRESS.getStatus()))) { + throw exception(BARGAIN_RECORD_CREATE_FAIL_EXISTS); + } + // 2.2 是否超过参与的上限 + if (bargainRecordMapper.selectCountByUserIdAndActivityIdAndStatus( + userId, reqVO.getActivityId(), BargainRecordStatusEnum.SUCCESS.getStatus()) >= activity.getTotalLimitCount()) { + throw exception(BARGAIN_RECORD_CREATE_FAIL_LIMIT); + } + + // 3. 创建砍价记录 + BargainRecordDO record = BargainRecordDO.builder().userId(userId) + .activityId(reqVO.getActivityId()).spuId(activity.getSpuId()).skuId(activity.getSkuId()) + .bargainFirstPrice(activity.getBargainFirstPrice()).bargainPrice(activity.getBargainFirstPrice()) + .status(BargainRecordStatusEnum.IN_PROGRESS.getStatus()).build(); + bargainRecordMapper.insert(record); + return record.getId(); + } + + @Override + public Boolean updateBargainRecordBargainPrice(Long id, Integer whereBargainPrice, + Integer reducePrice, Boolean success) { + BargainRecordDO updateObj = new BargainRecordDO().setBargainPrice(whereBargainPrice - reducePrice); + if (success) { + updateObj.setStatus(BargainRecordStatusEnum.SUCCESS.getStatus()); + } + return bargainRecordMapper.updateByIdAndBargainPrice(id, whereBargainPrice, updateObj) > 0; + } + + @Override + public BargainValidateJoinRespDTO validateJoinBargain(Long userId, Long bargainRecordId, Long skuId) { + // 1.1 砍价记录不存在 + BargainRecordDO record = bargainRecordMapper.selectByIdAndUserId(bargainRecordId, userId); + if (record == null) { + throw exception(BARGAIN_RECORD_NOT_EXISTS); + } + // 1.2 砍价记录未在进行中 + if (ObjUtil.notEqual(record.getStatus(), BargainRecordStatusEnum.SUCCESS.getStatus())) { + throw exception(BARGAIN_JOIN_RECORD_NOT_SUCCESS); + } + // 1.3 砍价记录已经下单 + if (record.getOrderId() != null) { + throw exception(BARGAIN_JOIN_RECORD_ALREADY_ORDER); + } + + // 2.1 校验砍价活动(包括库存) + BargainActivityDO activity = bargainActivityService.validateBargainActivityCanJoin(record.getActivityId()); + Assert.isTrue(Objects.equals(skuId, activity.getSkuId()), "砍价商品不匹配"); // 防御性校验 + return new BargainValidateJoinRespDTO().setActivityId(activity.getId()).setName(activity.getName()) + .setBargainPrice(record.getBargainPrice()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateBargainRecordOrderId(Long id, Long orderId) { + // 更新失败,说明已经下单 + int updateCount = bargainRecordMapper.updateOrderIdById(id, orderId); + if (updateCount == 0) { + throw exception(BARGAIN_JOIN_RECORD_ALREADY_ORDER); + } + } + + @Override + public BargainRecordDO getBargainRecord(Long id) { + return bargainRecordMapper.selectById(id); + } + + @Override + public BargainRecordDO getLastBargainRecord(Long userId, Long activityId) { + return bargainRecordMapper.selectLastByUserIdAndActivityId(userId, activityId); + } + + @Override + public Map getBargainRecordUserCountMap(Collection activityIds, @Nullable Integer status) { + return bargainRecordMapper.selectUserCountByActivityIdsAndStatus(activityIds, status); + } + + @Override + public Integer getBargainRecordUserCount(Integer status) { + return bargainRecordMapper.selectUserCountByStatus(status); + } + + @Override + public Integer getBargainRecordUserCount(Long activityId, Integer status) { + return bargainRecordMapper.selectUserCountByActivityIdAndStatus(activityId, status); + } + + @Override + public PageResult getBargainRecordPage(BargainRecordPageReqVO pageReqVO) { + return bargainRecordMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getBargainRecordPage(Long userId, PageParam pageParam) { + return bargainRecordMapper.selectBargainRecordPage(userId, pageParam); + } + + @Override + public List getBargainRecordList(Integer status, Integer count) { + return bargainRecordMapper.selectListByStatusAndCount(status, count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java new file mode 100644 index 0000000..23adc73 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.promotion.service.combination; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * 拼团活动 Service 接口 + * + * @author HUIHUI + */ +public interface CombinationActivityService { + + /** + * 创建拼团活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCombinationActivity(@Valid CombinationActivityCreateReqVO createReqVO); + + /** + * 更新拼团活动 + * + * @param updateReqVO 更新信息 + */ + void updateCombinationActivity(@Valid CombinationActivityUpdateReqVO updateReqVO); + + /** + * 关闭拼团活动 + * + * @param id 拼团活动编号 + */ + void closeCombinationActivityById(Long id); + + /** + * 删除拼团活动 + * + * @param id 编号 + */ + void deleteCombinationActivity(Long id); + + /** + * 校验拼团活动是否存在 + * + * @param id 编号 + * @return 拼团活动 + */ + CombinationActivityDO validateCombinationActivityExists(Long id); + + /** + * 获得拼团活动 + * + * @param id 编号 + * @return 拼团活动 + */ + CombinationActivityDO getCombinationActivity(Long id); + + /** + * 获得拼团活动分页 + * + * @param pageReqVO 分页查询 + * @return 拼团活动分页 + */ + PageResult getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO); + + /** + * 获得拼团活动商品列表 + * + * @param activityId 拼团活动 id + * @return 拼团活动的商品列表 + */ + default List getCombinationProductsByActivityId(Long activityId) { + return getCombinationProductListByActivityIds(Collections.singletonList(activityId)); + } + + /** + * 获得拼团活动商品列表 + * + * @param activityIds 拼团活动 ids + * @return 拼团活动的商品列表 + */ + List getCombinationProductListByActivityIds(Collection activityIds); + + /** + * 获得拼团活动列表 + * + * @param ids 拼团活动 ids + * @return 拼团活动的列表 + */ + List getCombinationActivityListByIds(Collection ids); + + /** + * 获取正在进行的活动分页数据 + * + * @param count 需要的数量 + * @return 拼团活动分页 + */ + List getCombinationActivityListByCount(Integer count); + + /** + * 获取正在进行的活动分页数据 + * + * @param pageParam 分页请求 + * @return 拼团活动分页 + */ + PageResult getCombinationActivityPage(PageParam pageParam); + + /** + * 获取指定活动、指定 sku 编号的商品 + * + * @param activityId 活动编号 + * @param skuId sku 编号 + * @return 活动商品信息 + */ + CombinationProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId); + + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 日期时间 + * @return 拼团活动列表 + */ + List getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java new file mode 100644 index 0000000..929076c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java @@ -0,0 +1,257 @@ +package cn.iocoder.yudao.module.promotion.service.combination; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Collections.singletonList; + +/** + * 拼团活动 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class CombinationActivityServiceImpl implements CombinationActivityService { + + @Resource + private CombinationActivityMapper combinationActivityMapper; + @Resource + private CombinationProductMapper combinationProductMapper; + + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) { + // 校验商品 SPU 是否存在是否参加的别的活动 + validateProductConflict(createReqVO.getSpuId(), null); + // 校验商品是否存在 + validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts()); + + // 插入拼团活动 + CombinationActivityDO activity = CombinationActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + combinationActivityMapper.insert(activity); + // 插入商品 + List products = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity); + combinationProductMapper.insertBatch(products); + return activity.getId(); + } + + /** + * 校验拼团商品参与的活动是否存在冲突 + * + * @param spuId 商品 SPU 编号 + * @param activityId 拼团活动编号 + */ + private void validateProductConflict(Long spuId, Long activityId) { + // 查询所有开启的拼团活动 + List activityList = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + if (activityId != null) { // 时排除自己 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); + } + // 查找是否有其它活动,选择了该产品 + List matchActivityList = filterList(activityList, activity -> ObjectUtil.equal(activity.getId(), spuId)); + if (CollUtil.isNotEmpty(matchActivityList)) { + throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS); + } + } + + /** + * 校验拼团商品是否都存在 + * + * @param spuId 商品 SPU 编号 + * @param products 拼团商品 + */ + private void validateProductExists(Long spuId, List products) { + // 1. 校验商品 spu 是否存在 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + + // 2. 校验商品 sku 都存在 + List skus = productSkuApi.getSkuListBySpuId(singletonList(spuId)); + Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); + products.forEach(product -> { + if (!skuMap.containsKey(product.getSkuId())) { + throw exception(SKU_NOT_EXISTS); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) { + // 校验存在 + CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId()); + // 校验状态 + if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE); + } + // 校验商品冲突 + validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId()); + // 校验商品是否存在 + validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts()); + + // 更新活动 + CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO); + combinationActivityMapper.updateById(updateObj); + // 更新商品 + updateCombinationProduct(updateObj, updateReqVO.getProducts()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void closeCombinationActivityById(Long id) { + // 校验活动是否存在 + CombinationActivityDO activity = validateCombinationActivityExists(id); + if (CommonStatusEnum.isDisable(activity.getStatus())) { + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE); + } + + // 关闭活动 + combinationActivityMapper.updateById(new CombinationActivityDO().setId(id) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + } + + /** + * 更新拼团商品 + * + * @param activity 拼团活动 + * @param products 该活动的最新商品配置 + */ + private void updateCombinationProduct(CombinationActivityDO activity, List products) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List newList = CombinationActivityConvert.INSTANCE.convertList(products, activity); + List oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(activity.getId())); + List> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> { + boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId()); + if (same) { + newVal.setId(oldVal.getId()); + } + return same; + }); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + combinationProductMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + combinationProductMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteCombinationActivity(Long id) { + // 校验存在 + CombinationActivityDO activity = validateCombinationActivityExists(id); + // 校验状态 + if (CommonStatusEnum.isEnable(activity.getStatus())) { + throw exception(COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); + } + + // 删除 + combinationActivityMapper.deleteById(id); + } + + @Override + public CombinationActivityDO validateCombinationActivityExists(Long id) { + CombinationActivityDO activityDO = combinationActivityMapper.selectById(id); + if (activityDO == null) { + throw exception(COMBINATION_ACTIVITY_NOT_EXISTS); + } + return activityDO; + } + + @Override + public CombinationActivityDO getCombinationActivity(Long id) { + return validateCombinationActivityExists(id); + } + + @Override + public PageResult getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) { + return combinationActivityMapper.selectPage(pageReqVO); + } + + @Override + public List getCombinationProductListByActivityIds(Collection activityIds) { + return combinationProductMapper.selectListByActivityIds(activityIds); + } + + @Override + public List getCombinationActivityListByIds(Collection ids) { + return combinationActivityMapper.selectList(CombinationActivityDO::getId, ids); + } + + @Override + public List getCombinationActivityListByCount(Integer count) { + return combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus(), count); + } + + @Override + public PageResult getCombinationActivityPage(PageParam pageParam) { + return combinationActivityMapper.selectPage(pageParam, CommonStatusEnum.ENABLE.getStatus()); + } + + @Override + public CombinationProductDO selectByActivityIdAndSkuId(Long activityId, Long skuId) { + return combinationProductMapper.selectOne( + CombinationProductDO::getActivityId, activityId, + CombinationProductDO::getSkuId, skuId); + } + + @Override + public List getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1.查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + List> spuIdAndActivityIdMaps = combinationActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) { + return Collections.emptyList(); + } + // 2.查询活动详情 + return combinationActivityMapper.selectListByIdsAndDateTimeLt( + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java new file mode 100644 index 0000000..55f5b2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java @@ -0,0 +1,176 @@ +package cn.iocoder.yudao.module.promotion.service.combination; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 拼团记录 Service 接口 + * + * @author HUIHUI + */ +public interface CombinationRecordService { + + /** + * 【下单前】校验是否满足拼团活动条件 + * + * 如果校验失败,则抛出业务异常 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @param headId 团长编号 + * @param skuId sku 编号 + * @param count 数量 + * @return 拼团信息 + */ + KeyValue validateCombinationRecord(Long userId, Long activityId, Long headId, + Long skuId, Integer count); + + /** + * 创建拼团记录 + * + * @param reqDTO 创建信息 + * @return 团信息 + */ + CombinationRecordDO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO); + + /** + * 获得拼团记录 + * + * @param userId 用户编号 + * @param orderId 订单编号 + * @return 拼团记录 + */ + CombinationRecordDO getCombinationRecord(Long userId, Long orderId); + + /** + * 【下单前】校验是否满足拼团活动条件 + * + * 如果校验失败,则抛出业务异常 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @param headId 团长编号 + * @param skuId sku 编号 + * @param count 数量 + * @return 拼团信息 + */ + CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count); + + /** + * 获取拼团记录数 + * + * @param status 状态-允许为空 + * @param virtualGroup 是否虚拟成团-允许为空 + * @param headId 团长编号,允许空。目的 headId 设置为 {@link CombinationRecordDO#HEAD_ID_GROUP} 时,可以设置 + * @return 记录数 + */ + Long getCombinationRecordCount(@Nullable Integer status, @Nullable Boolean virtualGroup, Long headId); + + /** + * 查询用户拼团记录(DISTINCT 去重),也就是说查询会员表中的用户有多少人参与过拼团活动每个人只统计一次 + * + * @return 参加过拼团的用户数 + */ + Long getCombinationUserCount(); + + /** + * 获取最近的 count 条拼团记录 + * + * @param count 限制数量 + * @return 拼团记录列表 + */ + List getLatestCombinationRecordList(int count); + + /** + * 获得最近 n 条拼团记录(团长发起的) + * + * @param activityId 拼团活动编号 + * @param status 状态 + * @param count 数量 + * @return 拼团记录列表 + */ + List getHeadCombinationRecordList(Long activityId, Integer status, Integer count); + + /** + * 获取指定编号的拼团记录 + * + * @param id 拼团记录编号 + * @return 拼团记录 + */ + CombinationRecordDO getCombinationRecordById(Long id); + + /** + * 获取指定团长编号的拼团记录 + * + * @param headId 团长编号 + * @return 拼团记录列表 + */ + List getCombinationRecordListByHeadId(Long headId); + + /** + * 获取拼团记录分页数据 + * + * @param pageVO 分页请求 + * @return 拼团记录分页数据 + */ + PageResult getCombinationRecordPage(CombinationRecordReqPageVO pageVO); + + /** + * 【拼团活动】获得拼团记录数量 Map + * + * @param activityIds 活动记录编号数组 + * @param status 拼团状态,允许空 + * @param headId 团长编号,允许空。目的 headId 设置为 {@link CombinationRecordDO#HEAD_ID_GROUP} 时,可以设置 + * @return 拼团记录数量 Map + */ + Map getCombinationRecordCountMapByActivity(Collection activityIds, + @Nullable Integer status, + @Nullable Long headId); + + /** + * 获取拼团记录 + * + * @param userId 用户编号 + * @param id 拼团记录编号 + * @return 拼团记录 + */ + CombinationRecordDO getCombinationRecordByIdAndUser(Long userId, Long id); + + /** + * 取消拼团 + * + * @param userId 用户编号 + * @param id 拼团记录编号 + * @param headId 团长编号 + */ + void cancelCombinationRecord(Long userId, Long id, Long headId); + + /** + * 处理过期拼团 + * + * @return key 过期拼团数量, value 虚拟成团数量 + */ + KeyValue expireCombinationRecord(); + + /** + * 获得拼团记录分页数据 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 拼团记录分页数据 + */ + PageResult getCombinationRecordPage(Long userId, AppCombinationRecordPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java new file mode 100644 index 0000000..809003a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java @@ -0,0 +1,426 @@ +package cn.iocoder.yudao.module.promotion.service.combination; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO; +import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.record.AppCombinationRecordPageReqVO; +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper; +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Nullable; +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.afterNow; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.beforeNow; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +// TODO 芋艿:等拼团记录做完,完整 review 下 + +/** + * 拼团记录 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Slf4j +@Validated +public class CombinationRecordServiceImpl implements CombinationRecordService { + + @Resource + private CombinationActivityService combinationActivityService; + @Resource + private CombinationRecordMapper combinationRecordMapper; + + @Resource + private MemberUserApi memberUserApi; + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Resource + @Lazy + private TradeOrderApi tradeOrderApi; + + // TODO @芋艿:在详细预览下; + @Override + public KeyValue validateCombinationRecord( + Long userId, Long activityId, Long headId, Long skuId, Integer count) { + // 1. 校验拼团活动是否存在 + CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId); + // 1.1 校验活动是否开启 + if (ObjUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); + } + // 1.2. 校验活动开始时间 + if (afterNow(activity.getStartTime())) { + throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START); + } + // 1.3 校验是否超出单次限购数量 + if (count > activity.getSingleLimitCount()) { + throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); + } + + // 2. 父拼团是否存在,是否已经满了 + if (headId != null) { + // 2.1. 查询进行中的父拼团 + CombinationRecordDO record = combinationRecordMapper.selectByHeadId(headId, CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); + if (record == null) { + throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS); + } + // 2.2. 校验拼团是否已满 + if (ObjUtil.equal(record.getUserCount(), record.getUserSize())) { + throw exception(COMBINATION_RECORD_USER_FULL); + } + // 2.3 校验拼团是否过期(有父拼团的时候只校验父拼团的过期时间) + if (beforeNow(record.getExpireTime())) { + throw exception(COMBINATION_RECORD_FAILED_TIME_END); + } + } else { + // 3. 校验当前活动是否结束(自己是父拼团的时候才校验活动是否结束) + if (beforeNow(activity.getEndTime())) { + throw exception(COMBINATION_RECORD_FAILED_TIME_END); + } + } + + // 4.1 校验活动商品是否存在 + CombinationProductDO product = combinationActivityService.selectByActivityIdAndSkuId(activityId, skuId); + if (product == null) { + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); + } + // 4.2 校验 sku 是否存在 + ProductSkuRespDTO sku = productSkuApi.getSku(skuId); + if (sku == null) { + throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); + } + // 4.3 校验库存是否充足 + if (count > sku.getStock()) { + throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL); + } + + // 6.1 校验是否有拼团记录 + List recordList = combinationRecordMapper.selectListByUserIdAndActivityId(userId, activityId); + recordList.removeIf(record -> CombinationRecordStatusEnum.isFailed(record.getStatus())); // 取消的订单,不算数 + if (CollUtil.isEmpty(recordList)) { // 如果为空,说明可以参与,直接返回 + return new KeyValue<>(activity, product); + } + // 6.2 校验用户是否有该活动正在进行的拼团 + CombinationRecordDO inProgressRecord = findFirst(recordList, + record -> CombinationRecordStatusEnum.isInProgress(record.getStatus())); + if (inProgressRecord != null) { + throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED); + } + // 6.3 校验是否超出总限购数量 + Integer sumValue = getSumValue(recordList, CombinationRecordDO::getCount, Integer::sum); + if (sumValue != null && sumValue + count > activity.getTotalLimitCount()) { + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED); + } + return new KeyValue<>(activity, product); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public CombinationRecordDO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { + // 1. 校验拼团活动 + KeyValue keyValue = validateCombinationRecord(reqDTO.getUserId(), + reqDTO.getActivityId(), reqDTO.getHeadId(), reqDTO.getSkuId(), reqDTO.getCount()); + + // 2. 组合数据创建拼团记录 + MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId()); + ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId()); + ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId()); + CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO, keyValue.getKey(), user, spu, sku); + // 2.1. 如果是团长需要设置 headId 为 CombinationRecordDO#HEAD_ID_GROUP + if (record.getHeadId() == null) { + record.setStartTime(LocalDateTime.now()) + .setExpireTime(LocalDateTime.now().plusHours(keyValue.getKey().getLimitDuration())) + .setHeadId(CombinationRecordDO.HEAD_ID_GROUP); + } else { + // 2.2.有团长的情况下需要设置开始时间和过期时间为团长的 + CombinationRecordDO headRecord = combinationRecordMapper.selectByHeadId(record.getHeadId(), + CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); // 查询进行中的父拼团 + record.setStartTime(headRecord.getStartTime()).setExpireTime(headRecord.getExpireTime()); + } + combinationRecordMapper.insert(record); + + // 3. 更新拼团记录 + if (ObjUtil.notEqual(CombinationRecordDO.HEAD_ID_GROUP, record.getHeadId())) { + updateCombinationRecordWhenCreate(reqDTO.getHeadId(), keyValue.getKey()); + } + return record; + } + + /** + * 当新增拼团时,更新拼团记录的进展 + * + * @param headId 团长编号 + * @param activity 活动 + */ + private void updateCombinationRecordWhenCreate(Long headId, CombinationActivityDO activity) { + // 1. 团长 + 团员 + List records = getCombinationRecordListByHeadId(headId); + if (CollUtil.isEmpty(records)) { + return; + } + CombinationRecordDO headRecord = combinationRecordMapper.selectById(headId); + + // 2. 批量更新记录 + List updateRecords = new ArrayList<>(); + records.add(headRecord); // 加入团长,团长也需要更新 + boolean isFull = records.size() >= activity.getUserSize(); + LocalDateTime now = LocalDateTime.now(); + records.forEach(item -> { + CombinationRecordDO updateRecord = new CombinationRecordDO(); + updateRecord.setId(item.getId()).setUserCount(records.size()); + if (isFull) { + updateRecord.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus()); + updateRecord.setEndTime(now); + } + updateRecords.add(updateRecord); + }); + combinationRecordMapper.updateBatch(updateRecords); + } + + @Override + public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) { + return combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId); + } + + @Override + public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, + Long skuId, Integer count) { + KeyValue keyValue = validateCombinationRecord(userId, activityId, + headId, skuId, count); + return new CombinationValidateJoinRespDTO().setActivityId(keyValue.getKey().getId()) + .setName(keyValue.getKey().getName()).setCombinationPrice(keyValue.getValue().getCombinationPrice()); + } + + @Override + public Long getCombinationRecordCount(@Nullable Integer status, @Nullable Boolean virtualGroup, @Nullable Long headId) { + return combinationRecordMapper.selectCountByHeadAndStatusAndVirtualGroup(status, virtualGroup, headId); + } + + @Override + public Long getCombinationUserCount() { + return combinationRecordMapper.selectUserCount(); + } + + @Override + public List getLatestCombinationRecordList(int count) { + return combinationRecordMapper.selectLatestList(count); + } + + @Override + public List getHeadCombinationRecordList(Long activityId, Integer status, Integer count) { + return combinationRecordMapper.selectListByActivityIdAndStatusAndHeadId(activityId, status, + CombinationRecordDO.HEAD_ID_GROUP, count); + } + + @Override + public CombinationRecordDO getCombinationRecordById(Long id) { + return combinationRecordMapper.selectById(id); + } + + @Override + public List getCombinationRecordListByHeadId(Long headId) { + return combinationRecordMapper.selectList(CombinationRecordDO::getHeadId, headId); + } + + @Override + public PageResult getCombinationRecordPage(CombinationRecordReqPageVO pageVO) { + return combinationRecordMapper.selectPage(pageVO); + } + + @Override + public Map getCombinationRecordCountMapByActivity(Collection activityIds, + @Nullable Integer status, @Nullable Long headId) { + return combinationRecordMapper.selectCombinationRecordCountMapByActivityIdAndStatusAndHeadId(activityIds, status, headId); + } + + @Override + public CombinationRecordDO getCombinationRecordByIdAndUser(Long userId, Long id) { + return combinationRecordMapper.selectOne(CombinationRecordDO::getUserId, userId, CombinationRecordDO::getId, id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelCombinationRecord(Long userId, Long id, Long headId) { + // 删除记录 + combinationRecordMapper.deleteById(id); + + // 需要更新的记录 + List updateRecords = new ArrayList<>(); + // 如果它是团长,则顺序(下单时间)继承 + if (Objects.equals(headId, CombinationRecordDO.HEAD_ID_GROUP)) { // 情况一:团长 + // 团员 + List list = getCombinationRecordListByHeadId(id); + if (CollUtil.isEmpty(list)) { + return; + } + // 按照创建时间升序排序 + list.sort(Comparator.comparing(CombinationRecordDO::getCreateTime)); // 影响原 list + CombinationRecordDO newHead = list.get(0); // 新团长继位 + list.forEach(item -> { + CombinationRecordDO recordDO = new CombinationRecordDO(); + recordDO.setId(item.getId()); + if (ObjUtil.equal(item.getId(), newHead.getId())) { // 新团长 + recordDO.setHeadId(CombinationRecordDO.HEAD_ID_GROUP); + } else { + recordDO.setHeadId(newHead.getId()); + } + recordDO.setUserCount(list.size()); + updateRecords.add(recordDO); + }); + } else { // 情况二:团员 + // 团长 + CombinationRecordDO recordHead = combinationRecordMapper.selectById(headId); + // 团员 + List records = getCombinationRecordListByHeadId(headId); + if (CollUtil.isEmpty(records)) { + return; + } + records.add(recordHead); // 加入团长,团长数据也需要更新 + records.forEach(item -> { + CombinationRecordDO recordDO = new CombinationRecordDO(); + recordDO.setId(item.getId()); + recordDO.setUserCount(records.size()); + updateRecords.add(recordDO); + }); + } + + // 更新拼团记录 + combinationRecordMapper.updateBatch(updateRecords); + } + + @Override + public KeyValue expireCombinationRecord() { + // 1. 获取所有正在进行中的过期的父拼团 + List headExpireRecords = combinationRecordMapper.selectListByHeadIdAndStatusAndExpireTimeLt( + CombinationRecordDO.HEAD_ID_GROUP, CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(headExpireRecords)) { + return new KeyValue<>(0, 0); + } + + // 2. 获取拼团活动 + List activities = combinationActivityService.getCombinationActivityListByIds( + convertSet(headExpireRecords, CombinationRecordDO::getActivityId)); + Map activityMap = convertMap(activities, CombinationActivityDO::getId); + + // 3. 逐个处理拼团,过期 or 虚拟成团 + KeyValue keyValue = new KeyValue<>(0, 0); // 统计过期拼团和虚拟成团 + for (CombinationRecordDO record : headExpireRecords) { + try { + CombinationActivityDO activity = activityMap.get(record.getActivityId()); + if (activity == null || !activity.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的 + // 3.1. 处理过期的拼团 + getSelf().handleExpireRecord(record); + keyValue.setKey(keyValue.getKey() + 1); + } else { + // 3.2. 处理虚拟成团 + getSelf().handleVirtualGroupRecord(record); + keyValue.setValue(keyValue.getValue() + 1); + } + } catch (Exception ignored) { // 处理异常继续循环 + log.error("[expireCombinationRecord][record({}) 处理异常,请进行处理!record 数据是:{}]", + record.getId(), JsonUtils.toJsonString(record)); + } + } + return keyValue; + } + + /** + * 处理过期拼团 + * + * @param headRecord 过期拼团团长记录 + */ + @Transactional(rollbackFor = Exception.class) + public void handleExpireRecord(CombinationRecordDO headRecord) { + // 1. 更新拼团记录 + List headAndRecords = updateBatchCombinationRecords(headRecord, + CombinationRecordStatusEnum.FAILED); + // 2. 订单取消 + headAndRecords.forEach(item -> tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId())); + } + + /** + * 处理虚拟拼团 + * + * @param headRecord 虚拟成团团长记录 + */ + @Transactional(rollbackFor = Exception.class) + public void handleVirtualGroupRecord(CombinationRecordDO headRecord) { + // 1. 团员补齐 + combinationRecordMapper.insertBatch(CombinationActivityConvert.INSTANCE.convertVirtualRecordList(headRecord)); + // 2. 更新拼团记录 + updateBatchCombinationRecords(headRecord, CombinationRecordStatusEnum.SUCCESS); + } + + /** + * 更新拼团记录 + * + * @param headRecord 团长记录 + * @param status 状态-拼团失败 FAILED 成功 SUCCESS + * @return 整团记录(包含团长和团成员) + */ + private List updateBatchCombinationRecords(CombinationRecordDO headRecord, CombinationRecordStatusEnum status) { + // 1. 查询团成员(包含团长) + List records = combinationRecordMapper.selectListByHeadId(headRecord.getId()); + records.add(headRecord);// 把团长加进去 + + // 2. 批量更新拼团记录 status 和 endTime + List updateRecords = new ArrayList<>(records.size()); + LocalDateTime now = LocalDateTime.now(); + records.forEach(item -> { + CombinationRecordDO updateRecord = new CombinationRecordDO().setId(item.getId()) + .setStatus(status.getStatus()).setEndTime(now); + if (CombinationRecordStatusEnum.isSuccess(status.getStatus())) { // 虚拟成团完事更改状态成功后还需要把参与人数修改为成团需要人数 + updateRecord.setUserCount(updateRecord.getUserSize()); + } + updateRecords.add(updateRecord); + }); + combinationRecordMapper.updateBatch(updateRecords); + return records; + } + + @Override + public PageResult getCombinationRecordPage(Long userId, AppCombinationRecordPageReqVO pageReqVO) { + return combinationRecordMapper.selectPage(userId, pageReqVO); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private CombinationRecordServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java new file mode 100644 index 0000000..edd6542 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.promotion.service.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; + +import java.util.*; + +/** + * 优惠劵 Service 接口 + * + * @author 芋道源码 + */ +public interface CouponService { + + /** + * 校验优惠劵,包括状态、有限期 + *

+ * 1. 如果校验通过,则返回优惠劵信息 + * 2. 如果校验不通过,则直接抛出业务异常 + * + * @param id 优惠劵编号 + * @param userId 用户编号 + * @return 优惠劵信息 + */ + CouponDO validCoupon(Long id, Long userId); + + /** + * 校验优惠劵,包括状态、有限期 + * + * @param coupon 优惠劵 + * @see #validCoupon(Long, Long) 逻辑相同,只是入参不同 + */ + void validCoupon(CouponDO coupon); + + /** + * 获得优惠劵分页 + * + * @param pageReqVO 分页查询 + * @return 优惠劵分页 + */ + PageResult getCouponPage(CouponPageReqVO pageReqVO); + + /** + * 使用优惠劵 + * + * @param id 优惠劵编号 + * @param userId 用户编号 + * @param orderId 订单编号 + */ + void useCoupon(Long id, Long userId, Long orderId); + + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); + + /** + * 回收优惠劵 + * + * @param id 优惠劵编号 + */ + void deleteCoupon(Long id); + + /** + * 获得用户的优惠劵列表 + * + * @param userId 用户编号 + * @param status 优惠劵状态 + * @return 优惠劵列表 + */ + List getCouponList(Long userId, Integer status); + + /** + * 获得未使用的优惠劵数量 + * + * @param userId 用户编号 + * @return 未使用的优惠劵数量 + */ + Long getUnusedCouponCount(Long userId); + + /** + * 领取优惠券 + * + * @param templateId 优惠券模板编号 + * @param userIds 用户编号列表 + * @param takeType 领取方式 + */ + void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType); + + /** + * 【管理员】给用户发送优惠券 + * + * @param templateId 优惠券模板编号 + * @param userIds 用户编号列表 + */ + default void takeCouponByAdmin(Long templateId, Set userIds) { + takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN); + } + + /** + * 【会员】领取优惠券 + * + * @param templateId 优惠券模板编号 + * @param userId 用户编号 + */ + default void takeCouponByUser(Long templateId, Long userId) { + takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); + } + + /** + * 【系统】给用户发送新人券 + * + * @param userId 用户编号 + */ + void takeCouponByRegister(Long userId); + + /** + * 获取会员领取指定优惠券的数量 + * + * @param templateId 优惠券模板编号 + * @param userId 用户编号 + * @return 领取优惠券的数量 + */ + default Integer getTakeCount(Long templateId, Long userId) { + Map map = getTakeCountMapByTemplateIds(Collections.singleton(templateId), userId); + return MapUtil.getInt(map, templateId, 0); + } + + /** + * 统计会员领取优惠券的数量 + * + * @param templateIds 优惠券模板编号列表 + * @param userId 用户编号 + * @return 领取优惠券的数量 + */ + Map getTakeCountMapByTemplateIds(Collection templateIds, Long userId); + + /** + * 获取用户匹配的优惠券列表 + * + * @param userId 用户编号 + * @param matchReqVO 匹配参数 + * @return 优惠券列表 + */ + List getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO); + + /** + * 过期优惠券 + * + * @return 过期数量 + */ + int expireCoupon(); + + /** + * 获取用户是否可以领取优惠券 + * + * @param userId 用户编号 + * @param templates 优惠券列表 + * @return 是否可以领取 + */ + Map getUserCanCanTakeMap(Long userId, List templates); + + /** + * 获得优惠劵 + * + * @param userId 用户编号 + * @param id 编号 + * @return 优惠劵 + */ + CouponDO getCoupon(Long userId, Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java new file mode 100644 index 0000000..38b56a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -0,0 +1,334 @@ +package cn.iocoder.yudao.module.promotion.service.coupon; + +import cn.hutool.core.collection.CollStreamUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; + +/** + * 优惠劵 Service 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@Service +@Validated +public class CouponServiceImpl implements CouponService { + + @Resource + private CouponTemplateService couponTemplateService; + + @Resource + private CouponMapper couponMapper; + + @Resource + private MemberUserApi memberUserApi; + + @Override + public CouponDO validCoupon(Long id, Long userId) { + CouponDO coupon = couponMapper.selectByIdAndUserId(id, userId); + if (coupon == null) { + throw exception(COUPON_NOT_EXISTS); + } + validCoupon(coupon); + return coupon; + } + + @Override + public void validCoupon(CouponDO coupon) { + // 校验状态 + if (ObjectUtil.notEqual(coupon.getStatus(), CouponStatusEnum.UNUSED.getStatus())) { + throw exception(COUPON_STATUS_NOT_UNUSED); + } + // 校验有效期;为避免定时器没跑,实际优惠劵已经过期 + if (!LocalDateTimeUtils.isBetween(coupon.getValidStartTime(), coupon.getValidEndTime())) { + throw exception(COUPON_VALID_TIME_NOT_NOW); + } + } + + @Override + public PageResult getCouponPage(CouponPageReqVO pageReqVO) { + // 获得用户编号 + if (StrUtil.isNotEmpty(pageReqVO.getNickname())) { + List users = memberUserApi.getUserListByNickname(pageReqVO.getNickname()); + if (CollUtil.isEmpty(users)) { + return PageResult.empty(); + } + pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId)); + } + // 分页查询 + return couponMapper.selectPage(pageReqVO); + } + + @Override + public void useCoupon(Long id, Long userId, Long orderId) { + // 校验优惠劵 + validCoupon(id, userId); + + // 更新状态 + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), + new CouponDO().setStatus(CouponStatusEnum.USED.getStatus()) + .setUseOrderId(orderId).setUseTime(LocalDateTime.now())); + if (updateCount == 0) { + throw exception(COUPON_STATUS_NOT_UNUSED); + } + } + + @Override + public void returnUsedCoupon(Long id) { + // 校验存在 + CouponDO coupon = couponMapper.selectById(id); + if (coupon == null) { + throw exception(COUPON_NOT_EXISTS); + } + // 校验状态 + if (ObjectUtil.notEqual(coupon.getStatus(), CouponStatusEnum.USED.getStatus())) { + throw exception(COUPON_STATUS_NOT_USED); + } + + // 退还 + Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) + ? CouponStatusEnum.EXPIRE.getStatus() // 退还时可能已经过期了 + : CouponStatusEnum.UNUSED.getStatus(); + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.USED.getStatus(), + new CouponDO().setStatus(status)); + if (updateCount == 0) { + throw exception(COUPON_STATUS_NOT_USED); + } + + // TODO 增加优惠券变动记录? + } + + @Override + @Transactional + public void deleteCoupon(Long id) { + // 校验存在 + validateCouponExists(id); + + // 更新优惠劵 + int deleteCount = couponMapper.delete(id, + asList(CouponStatusEnum.UNUSED.getStatus(), CouponStatusEnum.EXPIRE.getStatus())); + if (deleteCount == 0) { + throw exception(COUPON_DELETE_FAIL_USED); + } + // 减少优惠劵模板的领取数量 -1 + couponTemplateService.updateCouponTemplateTakeCount(id, -1); + } + + @Override + public List getCouponList(Long userId, Integer status) { + return couponMapper.selectListByUserIdAndStatus(userId, status); + } + + private void validateCouponExists(Long id) { + if (couponMapper.selectById(id) == null) { + throw exception(COUPON_NOT_EXISTS); + } + } + + @Override + public Long getUnusedCouponCount(Long userId) { + return couponMapper.selectCountByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getStatus()); + } + + @Override + public void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { + CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); + // 1. 过滤掉达到领取限制的用户 + removeTakeLimitUser(userIds, template); + // 2. 校验优惠劵是否可以领取 + validateCouponTemplateCanTake(template, userIds, takeType); + + // 3. 批量保存优惠劵 + couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId))); + + // 3. 增加优惠劵模板的领取数量 + couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void takeCouponByRegister(Long userId) { + List templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER); + for (CouponTemplateDO template : templates) { + takeCoupon(template.getId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER); + } + } + + @Override + public Map getTakeCountMapByTemplateIds(Collection templateIds, Long userId) { + if (CollUtil.isEmpty(templateIds)) { + return Collections.emptyMap(); + } + return couponMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds); + } + + @Override + public List getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) { + List list = couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId, + CouponStatusEnum.UNUSED.getStatus(), + matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds()); + // 兜底逻辑:如果 CouponExpireJob 未执行,status 未变成 EXPIRE ,但是 validEndTime 已经过期了,需要进行过滤 + list.removeIf(coupon -> !LocalDateTimeUtils.isBetween(coupon.getValidStartTime(), coupon.getValidEndTime())); + return list; + } + + @Override + public int expireCoupon() { + // 1. 查询待过期的优惠券 + List list = couponMapper.selectListByStatusAndValidEndTimeLe( + CouponStatusEnum.UNUSED.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(list)) { + return 0; + } + + // 2. 遍历执行 + int count = 0; + for (CouponDO coupon : list) { + try { + boolean success = getSelf().expireCoupon(coupon); + if (success) { + count++; + } + } catch (Exception e) { + log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId(), e); + } + } + return count; + } + + @Override + public Map getUserCanCanTakeMap(Long userId, List templates) { + // 1. 未登录时,都显示可以领取 + Map userCanTakeMap = convertMap(templates, CouponTemplateDO::getId, templateId -> true); + if (userId == null) { + return userCanTakeMap; + } + + // 2.1 过滤领取数量无限制的 + Set templateIds = convertSet(templates, CouponTemplateDO::getId, template -> template.getTakeLimitCount() != -1); + // 2.2 检查用户领取的数量是否超过限制 + if (CollUtil.isNotEmpty(templateIds)) { + Map couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId); + for (CouponTemplateDO template : templates) { + Integer takeCount = couponTakeCountMap.get(template.getId()); + userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount()); + } + } + return userCanTakeMap; + } + + /** + * 过期单个优惠劵 + * + * @param coupon 优惠劵 + * @return 是否过期成功 + */ + private boolean expireCoupon(CouponDO coupon) { + // 更新记录状态 + int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), + new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus())); + if (updateRows == 0) { + log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId()); + return false; + } + log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId()); + return true; + } + + /** + * 校验优惠券是否可以领取 + * + * @param couponTemplate 优惠券模板 + * @param userIds 领取人列表 + * @param takeType 领取方式 + */ + private void validateCouponTemplateCanTake(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { + // 如果所有用户都领取过,则抛出异常 + if (CollUtil.isEmpty(userIds)) { + throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); + } + + // 校验模板 + if (couponTemplate == null) { + throw exception(COUPON_TEMPLATE_NOT_EXISTS); + } + // 校验剩余数量 + if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { + throw exception(COUPON_TEMPLATE_NOT_ENOUGH); + } + // 校验"固定日期"的有效期类型是否过期 + if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) { + if (LocalDateTimeUtils.beforeNow(couponTemplate.getValidEndTime())) { + throw exception(COUPON_TEMPLATE_EXPIRED); + } + } + // 校验领取方式 + if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { + throw exception(COUPON_TEMPLATE_CANNOT_TAKE); + } + } + + /** + * 过滤掉达到领取上线的用户 + * + * @param userIds 用户编号数组 + * @param couponTemplate 优惠劵模版 + */ + private void removeTakeLimitUser(Set userIds, CouponTemplateDO couponTemplate) { + if (couponTemplate.getTakeLimitCount() <= 0) { + return; + } + // 查询已领过券的用户 + List alreadyTakeCoupons = couponMapper.selectListByTemplateIdAndUserId(couponTemplate.getId(), userIds); + if (CollUtil.isEmpty(alreadyTakeCoupons)) { + return; + } + // 移除达到领取限制的用户 + Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, CouponDO::getUserId, Collectors.summingInt(c -> 1)); + userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); + } + + @Override + public CouponDO getCoupon(Long userId, Long id) { + return couponMapper.selectByIdAndUserId(id, userId); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private CouponServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java new file mode 100644 index 0000000..02ed758 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.promotion.service.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 优惠劵模板 Service 接口 + * + * @author 芋道源码 + */ +public interface CouponTemplateService { + + /** + * 创建优惠劵模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCouponTemplate(@Valid CouponTemplateCreateReqVO createReqVO); + + /** + * 更新优惠劵模板 + * + * @param updateReqVO 更新信息 + */ + void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO); + + /** + * 更新优惠劵模板的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateCouponTemplateStatus(Long id, Integer status); + + /** + * 删除优惠劵模板 + * + * @param id 编号 + */ + void deleteCouponTemplate(Long id); + + /** + * 获得优惠劵模板 + * + * @param id 编号 + * @return 优惠劵模板 + */ + CouponTemplateDO getCouponTemplate(Long id); + + /** + * 获得优惠劵模板分页 + * + * @param pageReqVO 分页查询 + * @return 优惠劵模板分页 + */ + PageResult getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); + + /** + * 更新优惠劵模板的领取数量 + * + * @param id 优惠劵模板编号 + * @param incrCount 增加数量 + */ + void updateCouponTemplateTakeCount(Long id, int incrCount); + + /** + * 获得指定领取方式的优惠券模板 + * + * @param takeType 领取方式 + * @return 优惠券模板列表 + */ + List getCouponTemplateListByTakeType(CouponTakeTypeEnum takeType); + + /** + * 获得优惠券模板列表 + * + * @param canTakeTypes 可领取的类型列表 + * @param productScope 商品使用范围类型 + * @param productScopeValue 商品使用范围编号 + * @param count 查询数量 + * @return 优惠券模板列表 + */ + List getCouponTemplateList(List canTakeTypes, Integer productScope, + Long productScopeValue, Integer count); + + /** + * 获得优惠券模版列表 + * + * @param ids 优惠券模版编号 + * @return 优惠券模版列表 + */ + List getCouponTemplateList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java new file mode 100644 index 0000000..deaa426 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.promotion.service.coupon; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL; + +/** + * 优惠劵模板 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CouponTemplateServiceImpl implements CouponTemplateService { + + @Resource + private CouponTemplateMapper couponTemplateMapper; + + @Resource + private ProductCategoryApi productCategoryApi; + @Resource + private ProductSpuApi productSpuApi; + + @Override + public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { + // 校验商品范围 + validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues()); + // 插入 + CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + couponTemplateMapper.insert(couponTemplate); + // 返回 + return couponTemplate.getId(); + } + + @Override + public void updateCouponTemplate(CouponTemplateUpdateReqVO updateReqVO) { + // 校验存在 + CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId()); + // 校验发放数量不能过小 + if (updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) { + throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount()); + } + // 校验商品范围 + validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues()); + + // 更新 + CouponTemplateDO updateObj = CouponTemplateConvert.INSTANCE.convert(updateReqVO); + couponTemplateMapper.updateById(updateObj); + } + + @Override + public void updateCouponTemplateStatus(Long id, Integer status) { + // 校验存在 + validateCouponTemplateExists(id); + // 更新 + couponTemplateMapper.updateById(new CouponTemplateDO().setId(id).setStatus(status)); + } + + @Override + public void deleteCouponTemplate(Long id) { + // 校验存在 + validateCouponTemplateExists(id); + // 删除 + couponTemplateMapper.deleteById(id); + } + + private CouponTemplateDO validateCouponTemplateExists(Long id) { + CouponTemplateDO couponTemplate = couponTemplateMapper.selectById(id); + if (couponTemplate == null) { + throw exception(COUPON_TEMPLATE_NOT_EXISTS); + } + return couponTemplate; + } + + private void validateProductScope(Integer productScope, List productScopeValues) { + if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) { + productSpuApi.validateSpuList(productScopeValues); + } else if (Objects.equals(PromotionProductScopeEnum.CATEGORY.getScope(), productScope)) { + productCategoryApi.validateCategoryList(productScopeValues); + } + } + + @Override + public CouponTemplateDO getCouponTemplate(Long id) { + return couponTemplateMapper.selectById(id); + } + + @Override + public PageResult getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO) { + return couponTemplateMapper.selectPage(pageReqVO); + } + + @Override + public void updateCouponTemplateTakeCount(Long id, int incrCount) { + couponTemplateMapper.updateTakeCount(id, incrCount); + } + + @Override + public List getCouponTemplateListByTakeType(CouponTakeTypeEnum takeType) { + return couponTemplateMapper.selectListByTakeType(takeType.getValue()); + } + + @Override + public List getCouponTemplateList(List canTakeTypes, Integer productScope, + Long productScopeValue, Integer count) { + return couponTemplateMapper.selectList(canTakeTypes, productScope, productScopeValue, count); + } + + @Override + public List getCouponTemplateList(Collection ids) { + return couponTemplateMapper.selectBatchIds(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java new file mode 100644 index 0000000..af8b757 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 限时折扣 Service 接口 + * + * @author 芋道源码 + */ +public interface DiscountActivityService { + + /** + * 基于指定 SKU 编号数组,获得匹配的限时折扣商品 + * + * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态 + * + * @param skuIds SKU 编号数组 + * @return 匹配的限时折扣商品 + */ + List getMatchDiscountProductList(Collection skuIds); + + /** + * 创建限时折扣活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDiscountActivity(@Valid DiscountActivityCreateReqVO createReqVO); + + /** + * 更新限时折扣活动 + * + * @param updateReqVO 更新信息 + */ + void updateDiscountActivity(@Valid DiscountActivityUpdateReqVO updateReqVO); + + /** + * 关闭限时折扣活动 + * + * @param id 编号 + */ + void closeDiscountActivity(Long id); + + /** + * 删除限时折扣活动 + * + * @param id 编号 + */ + void deleteDiscountActivity(Long id); + + /** + * 获得限时折扣活动 + * + * @param id 编号 + * @return 限时折扣活动 + */ + DiscountActivityDO getDiscountActivity(Long id); + + /** + * 获得限时折扣活动分页 + * + * @param pageReqVO 分页查询 + * @return 限时折扣活动分页 + */ + PageResult getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO); + + /** + * 获得活动编号,对应对应的商品列表 + * + * @param activityId 活动编号 + * @return 活动的商品列表 + */ + List getDiscountProductsByActivityId(Long activityId); + + /** + * 获得活动编号,对应对应的商品列表 + * + * @param activityIds 活动编号 + * @return 活动的商品列表 + */ + List getDiscountProductsByActivityId(Collection activityIds); + + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 当前日期时间 + * @return 折扣活动列表 + */ + List getDiscountActivityBySpuIdsAndStatusAndDateTimeLt( + Collection spuIds, Integer status, LocalDateTime dateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java new file mode 100644 index 0000000..507d0e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java @@ -0,0 +1,206 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 限时折扣 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DiscountActivityServiceImpl implements DiscountActivityService { + + @Resource + private DiscountActivityMapper discountActivityMapper; + @Resource + private DiscountProductMapper discountProductMapper; + + @Override + public List getMatchDiscountProductList(Collection skuIds) { + return discountProductMapper.getMatchDiscountProductList(skuIds); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { + // 校验商品是否冲突 + validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); + + // 插入活动 + DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + discountActivityMapper.insert(discountActivity); + // 插入商品 + List discountProducts = BeanUtils.toBean(createReqVO.getProducts(), DiscountProductDO.class, + product -> product.setActivityId(discountActivity.getId()).setActivityStatus(discountActivity.getStatus()) + .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime())); + discountProductMapper.insertBatch(discountProducts); + // 返回 + return discountActivity.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) { + // 校验存在 + DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId()); + if (discountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能修改噢 + throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); + } + // 校验商品是否冲突 + validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); + + // 更新活动 + DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); + discountActivityMapper.updateById(updateObj); + // 更新商品 + updateDiscountProduct(updateReqVO); + } + + private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) { + // TODO @zhangshuai:这里的逻辑,可以优化下哈;参考 CombinationActivityServiceImpl 的 updateCombinationProduct,主要是 CollectionUtils.diffList 的使用哈; + // 然后原先是使用 DiscountActivityConvert.INSTANCE.isEquals 对比,现在看看是不是简化就基于 skuId 对比就完事了;之前写的太精细,意义不大; + List dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId()); + // 计算要删除的记录 + List deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId, + discountProductDO -> updateReqVO.getProducts().stream() + .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product))); + if (CollUtil.isNotEmpty(deleteIds)) { + discountProductMapper.deleteBatchIds(deleteIds); + } + // 计算新增的记录 + List newDiscountProducts = convertList(updateReqVO.getProducts(), + product -> DiscountActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId())); + newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch( + dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的 + if (CollectionUtil.isNotEmpty(newDiscountProducts)) { + discountProductMapper.insertBatch(newDiscountProducts); + } + } + + /** + * 校验商品是否冲突 + * + * @param id 编号 + * @param products 商品列表 + */ + private void validateDiscountActivityProductConflicts(Long id, List products) { + if (CollUtil.isEmpty(products)) { + return; + } + // 查询商品参加的活动 + // TODO @zhangshuai:下面 121 这个查询,是不是不用做呀;直接 convert 出 skuId 集合就 ok 啦; + List list = discountProductMapper.selectListByActivityId(id); + // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。 + List skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList()); + List matchDiscountProductList = getMatchDiscountProductList(skuIds); + if (id != null) { // 排除自己这个活动 + matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId())); + } + // 如果非空,则说明冲突 + if (CollUtil.isNotEmpty(matchDiscountProductList)) { + throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS); + } + } + + @Override + public void closeDiscountActivity(Long id) { + // 校验存在 + DiscountActivityDO activity = validateDiscountActivityExists(id); + if (activity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); + } + + // 更新 + DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + discountActivityMapper.updateById(updateObj); + } + + @Override + public void deleteDiscountActivity(Long id) { + // 校验存在 + DiscountActivityDO activity = validateDiscountActivityExists(id); + if (CommonStatusEnum.isEnable(activity.getStatus())) { // 未关闭的活动,不能删除噢 + throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); + } + + // 删除 + discountActivityMapper.deleteById(id); + } + + private DiscountActivityDO validateDiscountActivityExists(Long id) { + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id); + if (discountActivity == null) { + throw exception(DISCOUNT_ACTIVITY_NOT_EXISTS); + } + return discountActivity; + } + + @Override + public DiscountActivityDO getDiscountActivity(Long id) { + return discountActivityMapper.selectById(id); + } + + @Override + public PageResult getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO) { + return discountActivityMapper.selectPage(pageReqVO); + } + + @Override + public List getDiscountProductsByActivityId(Long activityId) { + return discountProductMapper.selectListByActivityId(activityId); + } + + @Override + public List getDiscountProductsByActivityId(Collection activityIds) { + return discountProductMapper.selectList("activity_id", activityIds); + } + + @Override + public List getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + List> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) { + return Collections.emptyList(); + } + + // 2. 查询活动详情 + return discountActivityMapper.selectListByIdsAndDateTimeLt( + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageService.java new file mode 100644 index 0000000..31900e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 装修页面 Service 接口 + * + * @author owen + */ +public interface DiyPageService { + + /** + * 创建装修页面 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDiyPage(@Valid DiyPageCreateReqVO createReqVO); + + /** + * 更新装修页面 + * + * @param updateReqVO 更新信息 + */ + void updateDiyPage(@Valid DiyPageUpdateReqVO updateReqVO); + + /** + * 删除装修页面 + * + * @param id 编号 + */ + void deleteDiyPage(Long id); + + /** + * 获得装修页面 + * + * @param id 编号 + * @return 装修页面 + */ + DiyPageDO getDiyPage(Long id); + + /** + * 获得装修页面列表 + * + * @param ids 编号 + * @return 装修页面列表 + */ + List getDiyPageList(Collection ids); + + /** + * 获得装修页面分页 + * + * @param pageReqVO 分页查询 + * @return 装修页面分页 + */ + PageResult getDiyPagePage(DiyPagePageReqVO pageReqVO); + + /** + * 更新装修页面属性 + * + * @param updateReqVO 更新信息 + */ + void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO); + + /** + * 获得模板所属的页面列表 + * + * @param templateId 模板编号 + * @return 装修页面列表 + */ + List getDiyPageByTemplateId(Long templateId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java new file mode 100644 index 0000000..69f96ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyPageMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NAME_USED; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NOT_EXISTS; + +/** + * 装修页面 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class DiyPageServiceImpl implements DiyPageService { + + @Resource + private DiyPageMapper diyPageMapper; + + @Override + public Long createDiyPage(DiyPageCreateReqVO createReqVO) { + // 校验名称唯一 + validateNameUnique(null, createReqVO.getTemplateId(), createReqVO.getName()); + // 插入 + DiyPageDO diyPage = DiyPageConvert.INSTANCE.convert(createReqVO); + diyPage.setProperty("{}"); + diyPageMapper.insert(diyPage); + return diyPage.getId(); + } + + @Override + public void updateDiyPage(DiyPageUpdateReqVO updateReqVO) { + // 校验存在 + validateDiyPageExists(updateReqVO.getId()); + // 校验名称唯一 + validateNameUnique(updateReqVO.getId(), updateReqVO.getTemplateId(), updateReqVO.getName()); + // 更新 + DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO); + diyPageMapper.updateById(updateObj); + } + + /** + * 校验 Page 页面,在一个 template 模版下的名字是唯一的 + * + * @param id Page 编号 + * @param templateId 模版编号 + * @param name Page 名字 + */ + void validateNameUnique(Long id, Long templateId, String name) { + if (templateId != null || StrUtil.isBlank(name)) { + return; + } + DiyPageDO page = diyPageMapper.selectByNameAndTemplateIdIsNull(name); + if (page == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的页面 + if (id == null) { + throw exception(DIY_PAGE_NAME_USED, name); + } + if (!page.getId().equals(id)) { + throw exception(DIY_PAGE_NAME_USED, name); + } + } + + @Override + public void deleteDiyPage(Long id) { + // 校验存在 + validateDiyPageExists(id); + // 删除 + diyPageMapper.deleteById(id); + } + + private void validateDiyPageExists(Long id) { + if (diyPageMapper.selectById(id) == null) { + throw exception(DIY_PAGE_NOT_EXISTS); + } + } + + @Override + public DiyPageDO getDiyPage(Long id) { + return diyPageMapper.selectById(id); + } + + @Override + public List getDiyPageList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return diyPageMapper.selectBatchIds(ids); + } + + @Override + public PageResult getDiyPagePage(DiyPagePageReqVO pageReqVO) { + return diyPageMapper.selectPage(pageReqVO); + } + + @Override + public List getDiyPageByTemplateId(Long templateId) { + return diyPageMapper.selectListByTemplateId(templateId); + } + + @Override + public void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO) { + // 校验存在 + validateDiyPageExists(updateReqVO.getId()); + // 更新 + DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO); + diyPageMapper.updateById(updateObj); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateService.java new file mode 100644 index 0000000..4f0c0c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateService.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; + +import javax.validation.Valid; + +/** + * 装修模板 Service 接口 + * + * @author owen + */ +public interface DiyTemplateService { + + /** + * 创建装修模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDiyTemplate(@Valid DiyTemplateCreateReqVO createReqVO); + + /** + * 更新装修模板 + * + * @param updateReqVO 更新信息 + */ + void updateDiyTemplate(@Valid DiyTemplateUpdateReqVO updateReqVO); + + /** + * 删除装修模板 + * + * @param id 编号 + */ + void deleteDiyTemplate(Long id); + + /** + * 获得装修模板 + * + * @param id 编号 + * @return 装修模板 + */ + DiyTemplateDO getDiyTemplate(Long id); + + /** + * 获得装修模板分页 + * + * @param pageReqVO 分页查询 + * @return 装修模板分页 + */ + PageResult getDiyTemplatePage(DiyTemplatePageReqVO pageReqVO); + + /** + * 使用装修模板 + * + * @param id 编号 + */ + void useDiyTemplate(Long id); + + /** + * 更新装修模板属性 + * + * @param updateReqVO 更新信息 + */ + void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO); + + /** + * 获取使用中的装修模板 + * + * @return 装修模板 + */ + DiyTemplateDO getUsedDiyTemplate(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java new file mode 100644 index 0000000..f6d5e72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyPageConvert; +import cn.iocoder.yudao.module.promotion.convert.diy.DiyTemplateConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyTemplateMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 装修模板 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class DiyTemplateServiceImpl implements DiyTemplateService { + + @Resource + private DiyTemplateMapper diyTemplateMapper; + + @Resource + private DiyPageService diyPageService; + + @Transactional(rollbackFor = Exception.class) + @Override + public Long createDiyTemplate(DiyTemplateCreateReqVO createReqVO) { + // 校验名称唯一 + validateNameUnique(null, createReqVO.getName()); + // 插入 + DiyTemplateDO diyTemplate = DiyTemplateConvert.INSTANCE.convert(createReqVO); + diyTemplate.setProperty("{}"); + diyTemplateMapper.insert(diyTemplate); + // 创建默认页面 + createDefaultPage(diyTemplate); + // 返回 + return diyTemplate.getId(); + } + + /** + * 创建模板下面的默认页面 + * 默认创建两个页面:首页、我的 + * + * @param diyTemplate 模板对象 + */ + private void createDefaultPage(DiyTemplateDO diyTemplate) { + String remark = String.format("模板【%s】自动创建", diyTemplate.getName()); + diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "首页", remark)); + diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "我的", remark)); + } + + @Override + public void updateDiyTemplate(DiyTemplateUpdateReqVO updateReqVO) { + // 校验存在 + validateDiyTemplateExists(updateReqVO.getId()); + // 校验名称唯一 + validateNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 更新 + DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO); + diyTemplateMapper.updateById(updateObj); + } + + void validateNameUnique(Long id, String name) { + if (StrUtil.isBlank(name)) { + return; + } + DiyTemplateDO template = diyTemplateMapper.selectByName(name); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的模板 + if (id == null) { + throw exception(DIY_TEMPLATE_NAME_USED, name); + } + if (!template.getId().equals(id)) { + throw exception(DIY_TEMPLATE_NAME_USED, name); + } + } + + @Override + public void deleteDiyTemplate(Long id) { + // 校验存在 + DiyTemplateDO diyTemplateDO = validateDiyTemplateExists(id); + // 校验使用中 + if (BooleanUtil.isTrue(diyTemplateDO.getUsed())) { + throw exception(DIY_TEMPLATE_USED_CANNOT_DELETE); + } + // 删除 + diyTemplateMapper.deleteById(id); + } + + private DiyTemplateDO validateDiyTemplateExists(Long id) { + DiyTemplateDO diyTemplateDO = diyTemplateMapper.selectById(id); + if (diyTemplateDO == null) { + throw exception(DIY_TEMPLATE_NOT_EXISTS); + } + return diyTemplateDO; + } + + @Override + public DiyTemplateDO getDiyTemplate(Long id) { + return diyTemplateMapper.selectById(id); + } + + @Override + public PageResult getDiyTemplatePage(DiyTemplatePageReqVO pageReqVO) { + return diyTemplateMapper.selectPage(pageReqVO); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void useDiyTemplate(Long id) { + // 校验存在 + validateDiyTemplateExists(id); + // TODO @疯狂:要不已使用的情况,抛个业务异常? + // 已使用的更新为未使用 + DiyTemplateDO used = diyTemplateMapper.selectByUsed(true); + if (used != null) { + // 如果 id 相同,说明未发生变化 + if (used.getId().equals(id)) { + return; + } + this.updateTemplateUsed(used.getId(), false, null); + } + // 更新为已使用 + this.updateTemplateUsed(id, true, LocalDateTime.now()); + } + + /** + * 更新模板是否使用 + * + * @param id 模板编号 + * @param used 是否使用 + * @param usedTime 使用时间 + */ + private void updateTemplateUsed(Long id, Boolean used, LocalDateTime usedTime) { + DiyTemplateDO updateObj = new DiyTemplateDO().setId(id) + .setUsed(used).setUsedTime(usedTime); + diyTemplateMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO) { + // 校验存在 + validateDiyTemplateExists(updateReqVO.getId()); + // 更新模板属性 + DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO); + diyTemplateMapper.updateById(updateObj); + } + + @Override + public DiyTemplateDO getUsedDiyTemplate() { + return diyTemplateMapper.selectByUsed(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java new file mode 100644 index 0000000..f08e740 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 满减送活动 Service 接口 + * + * @author 芋道源码 + */ +public interface RewardActivityService { + + /** + * 创建满减送活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRewardActivity(@Valid RewardActivityCreateReqVO createReqVO); + + /** + * 更新满减送活动 + * + * @param updateReqVO 更新信息 + */ + void updateRewardActivity(@Valid RewardActivityUpdateReqVO updateReqVO); + + /** + * 关闭满减送活动 + * + * @param id 活动编号 + */ + void closeRewardActivity(Long id); + + /** + * 删除满减送活动 + * + * @param id 编号 + */ + void deleteRewardActivity(Long id); + + /** + * 获得满减送活动 + * + * @param id 编号 + * @return 满减送活动 + */ + RewardActivityDO getRewardActivity(Long id); + + /** + * 获得满减送活动分页 + * + * @param pageReqVO 分页查询 + * @return 满减送活动分页 + */ + PageResult getRewardActivityPage(RewardActivityPageReqVO pageReqVO); + + /** + * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 + * + * @param spuIds SPU 编号数组 + * @return 满减送活动列表 + */ + List getMatchRewardActivityList(Collection spuIds); + + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 当前日期时间 + * @return 满减送活动列表 + */ + List getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java new file mode 100644 index 0000000..b7884c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java @@ -0,0 +1,182 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; + +/** + * 满减送活动 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class RewardActivityServiceImpl implements RewardActivityService { + + @Resource + private RewardActivityMapper rewardActivityMapper; + + @Override + public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) { + // 校验商品是否冲突 + validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds()); + + // 插入 + RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); + rewardActivityMapper.insert(rewardActivity); + // 返回 + return rewardActivity.getId(); + } + + @Override + public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId()); + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢 + throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); + } + // 校验商品是否冲突 + validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds()); + + // 更新 + RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); + rewardActivityMapper.updateById(updateObj); + } + + @Override + public void closeRewardActivity(Long id) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); + } + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END); + } + + // 更新 + RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + rewardActivityMapper.updateById(updateObj); + } + + @Override + public void deleteRewardActivity(Long id) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); + if (!dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢 + throw exception(REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); + } + + // 删除 + rewardActivityMapper.deleteById(id); + } + + private RewardActivityDO validateRewardActivityExists(Long id) { + RewardActivityDO activity = rewardActivityMapper.selectById(id); + if (activity == null) { + throw exception(REWARD_ACTIVITY_NOT_EXISTS); + } + return activity; + } + + // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验; + + /** + * 校验商品参加的活动是否冲突 + * + * @param id 活动编号 + * @param spuIds 商品 SPU 编号数组 + */ + private void validateRewardActivitySpuConflicts(Long id, Collection spuIds) { + if (CollUtil.isEmpty(spuIds)) { + return; + } + // 查询商品参加的活动 + List rewardActivityList = getRewardActivityListBySpuIds(spuIds, + asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); + if (id != null) { // 排除自己这个活动 + rewardActivityList.removeIf(activity -> id.equals(activity.getId())); + } + // 如果非空,则说明冲突 + if (CollUtil.isNotEmpty(rewardActivityList)) { + throw exception(REWARD_ACTIVITY_SPU_CONFLICTS); + } + } + + /** + * 获得商品参加的满减送活动的数组 + * + * @param spuIds 商品 SPU 编号数组 + * @param statuses 活动状态数组 + * @return 商品参加的满减送活动的数组 + */ + private List getRewardActivityListBySpuIds(Collection spuIds, + Collection statuses) { + List list = rewardActivityMapper.selectListByStatus(statuses); + return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds)); + } + + @Override + public RewardActivityDO getRewardActivity(Long id) { + return rewardActivityMapper.selectById(id); + } + + @Override + public PageResult getRewardActivityPage(RewardActivityPageReqVO pageReqVO) { + return rewardActivityMapper.selectPage(pageReqVO); + } + + @Override + public List getMatchRewardActivityList(Collection spuIds) { + // TODO 芋艿:待实现;先指定,然后再全局的; +// // 如果有全局活动,则直接选择它 +// List allActivities = rewardActivityMapper.selectListByProductScopeAndStatus( +// PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus()); +// if (CollUtil.isNotEmpty(allActivities)) { +// return MapUtil.builder(allActivities.get(0), spuIds).build(); +// } +// +// // 查询某个活动参加的活动 +// List productActivityList = getRewardActivityListBySpuIds(spuIds, +// singleton(PromotionActivityStatusEnum.RUN.getStatus())); +// return convertMap(productActivityList, activity -> activity, +// rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回 + return null; + } + + @Override + public List getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1. 查询出指定 spuId 的 spu 参加的活动 + List rewardActivityList = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(rewardActivityList)) { + return Collections.emptyList(); + } + + // 2. 查询活动详情 + return rewardActivityMapper.selectListByIdsAndDateTimeLt(convertSet(rewardActivityList, RewardActivityDO::getId), dateTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java new file mode 100644 index 0000000..0ed6a4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java @@ -0,0 +1,142 @@ +package cn.iocoder.yudao.module.promotion.service.seckill; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 秒杀活动 Service 接口 + * + * @author halfninety + */ +public interface SeckillActivityService { + + /** + * 创建秒杀活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSeckillActivity(@Valid SeckillActivityCreateReqVO createReqVO); + + /** + * 更新秒杀活动 + * + * @param updateReqVO 更新信息 + */ + void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); + + /** + * 更新秒杀库存(减少) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updateSeckillStockDecr(Long id, Long skuId, Integer count); + + /** + * 更新秒杀库存(增加) + * + * @param id 活动编号 + * @param skuId sku 编号 + * @param count 数量(正数) + */ + void updateSeckillStockIncr(Long id, Long skuId, Integer count); + + /** + * 关闭秒杀活动 + * + * @param id 编号 + */ + void closeSeckillActivity(Long id); + + /** + * 删除秒杀活动 + * + * @param id 编号 + */ + void deleteSeckillActivity(Long id); + + /** + * 获得秒杀活动 + * + * @param id 编号 + * @return 秒杀活动 + */ + SeckillActivityDO getSeckillActivity(Long id); + + /** + * 获得秒杀活动分页 + * + * @param pageReqVO 分页查询 + * @return 秒杀活动分页 + */ + PageResult getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO); + + /** + * 通过活动编号获取活动商品 + * + * @param activityId 活动编号 + * @return 活动商品列表 + */ + List getSeckillProductListByActivityId(Long activityId); + + /** + * 通过活动编号获取活动商品 + * + * @param activityIds 活动编号 + * @return 活动商品列表 + */ + List getSeckillProductListByActivityId(Collection activityIds); + + /** + * 通过活动时段编号获取指定 status 的秒杀活动 + * + * @param configId 时段配置编号 + * @param status 状态 + * @return 秒杀活动列表 + */ + List getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status); + + /** + * 通过活动时段获取秒杀活动 + * + * @param pageReqVO 请求 + * @return 秒杀活动列表 + */ + PageResult getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO); + + /** + * 校验是否参与秒杀商品 + * + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 + * @return 秒杀信息 + */ + SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count); + + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 日期时间 + * @return 秒杀活动列表 + */ + List getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java new file mode 100644 index 0000000..8ccfb30 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -0,0 +1,339 @@ +package cn.iocoder.yudao.module.promotion.service.seckill; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.hutool.core.collection.CollUtil.isNotEmpty; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Collections.singletonList; + +/** + * 秒杀活动 Service 实现类 + * + * @author halfninety + */ +@Service +@Validated +public class SeckillActivityServiceImpl implements SeckillActivityService { + + @Resource + private SeckillActivityMapper seckillActivityMapper; + @Resource + private SeckillProductMapper seckillProductMapper; + @Resource + private SeckillConfigService seckillConfigService; + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { + // 1.1 校验商品秒杀时段是否冲突 + validateProductConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null); + // 1.2 校验商品是否存在 + validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts()); + + // 2.1 插入秒杀活动 + SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + activity.setTotalStock(activity.getStock()); + seckillActivityMapper.insert(activity); + // 2.2 插入商品 + List products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity); + seckillProductMapper.insertBatch(products); + return activity.getId(); + } + + /** + * 校验秒杀商品参与的活动是否存在冲突 + * + * 1. 校验秒杀时段是否存在 + * 2. 秒杀商品是否参加其它活动 + * + * @param configIds 秒杀时段数组 + * @param spuId 商品 SPU 编号 + * @param activityId 秒杀活动编号 + */ + private void validateProductConflict(List configIds, Long spuId, Long activityId) { + // 1. 校验秒杀时段是否存在 + seckillConfigService.validateSeckillConfigExists(configIds); + + // 2.1 查询所有开启的秒杀活动 + List activityList = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + if (activityId != null) { // 排除自己 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); + } + // 2.2 过滤出所有 configIds 有交集的活动,判断是否存在重叠 + List conflictActivityList = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds)); + if (isNotEmpty(conflictActivityList)) { + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); + } + } + + /** + * 校验秒杀商品是否都存在 + * + * @param spuId 商品 SPU 编号 + * @param products 秒杀商品 + */ + private void validateProductExists(Long spuId, List products) { + // 1. 校验商品 spu 是否存在 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + + // 2. 校验商品 sku 都存在 + List skus = productSkuApi.getSkuListBySpuId(singletonList(spuId)); + Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); + products.forEach(product -> { + if (!skuMap.containsKey(product.getSkuId())) { + throw exception(SKU_NOT_EXISTS); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { + // 1.1 校验存在 + SeckillActivityDO activity = validateSeckillActivityExists(updateReqVO.getId()); + if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) { + throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); + } + // 1.2 校验商品是否冲突 + validateProductConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId()); + // 1.3 校验商品是否存在 + validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts()); + + // 2.1 更新活动 + SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) + .setStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + if (updateObj.getStock() > activity.getTotalStock()) { // 如果更新的库存大于原来的库存,则更新总库存 + updateObj.setTotalStock(updateObj.getStock()); + } + seckillActivityMapper.updateById(updateObj); + // 2.2 更新商品 + updateSeckillProduct(updateObj, updateReqVO.getProducts()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSeckillStockDecr(Long id, Long skuId, Integer count) { + // 1.1 校验活动库存是否充足 + SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); + if (count > seckillActivity.getTotalStock()) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + // 1.2 校验商品库存是否充足 + SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(id, skuId); + if (product == null || count > product.getStock()) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + + // 2.1 更新活动商品库存 + int updateCount = seckillProductMapper.updateStockDecr(product.getId(), count); + if (updateCount == 0) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + + // 2.2 更新活动库存 + updateCount = seckillActivityMapper.updateStockDecr(seckillActivity.getId(), count); + if (updateCount == 0) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSeckillStockIncr(Long id, Long skuId, Integer count) { + SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(id, skuId); + // 更新活动商品库存 + seckillProductMapper.updateStockIncr(product.getId(), count); + // 更新活动库存 + seckillActivityMapper.updateStockIncr(id, count); + } + + /** + * 更新秒杀商品 + * + * @param activity 秒杀活动 + * @param products 该活动的最新商品配置 + */ + private void updateSeckillProduct(SeckillActivityDO activity, List products) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List newList = SeckillActivityConvert.INSTANCE.convertList(products, activity); + List oldList = seckillProductMapper.selectListByActivityId(activity.getId()); + List> diffList = diffList(oldList, newList, (oldVal, newVal) -> { + boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId()); + if (same) { + newVal.setId(oldVal.getId()); + } + return same; + }); + + // 第二步,批量添加、修改、删除 + if (isNotEmpty(diffList.get(0))) { + seckillProductMapper.insertBatch(diffList.get(0)); + } + if (isNotEmpty(diffList.get(1))) { + seckillProductMapper.updateBatch(diffList.get(1)); + } + if (isNotEmpty(diffList.get(2))) { + seckillProductMapper.deleteBatchIds(convertList(diffList.get(2), SeckillProductDO::getId)); + } + } + + @Override + public void closeSeckillActivity(Long id) { + // 校验存在 + SeckillActivityDO activity = validateSeckillActivityExists(id); + if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) { + throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); + } + + // 更新 + SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()); + seckillActivityMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSeckillActivity(Long id) { + // 校验存在 + SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id); + if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) { + throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END); + } + + // 删除活动 + seckillActivityMapper.deleteById(id); + // 删除活动商品 + List products = seckillProductMapper.selectListByActivityId(id); + seckillProductMapper.deleteBatchIds(convertSet(products, SeckillProductDO::getId)); + } + + private SeckillActivityDO validateSeckillActivityExists(Long id) { + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(id); + if (seckillActivity == null) { + throw exception(SECKILL_ACTIVITY_NOT_EXISTS); + } + return seckillActivity; + } + + @Override + public SeckillActivityDO getSeckillActivity(Long id) { + return seckillActivityMapper.selectById(id); + } + + @Override + public PageResult getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO) { + return seckillActivityMapper.selectPage(pageReqVO); + } + + @Override + public List getSeckillProductListByActivityId(Long activityId) { + return seckillProductMapper.selectListByActivityId(activityId); + } + + @Override + public List getSeckillProductListByActivityId(Collection activityIds) { + return seckillProductMapper.selectListByActivityId(activityIds); + } + + @Override + public List getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status) { + return filterList(seckillActivityMapper.selectList(SeckillActivityDO::getStatus, status), + item -> anyMatch(item.getConfigIds(), id -> ObjectUtil.equal(id, configId)) // 校验时段 + && isBetween(item.getStartTime(), item.getEndTime())); // 追加当前日期是否处在活动日期之间的校验条件 + } + + @Override + public PageResult getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) { + return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus()); + } + + @Override + public SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count) { + // 1.1 校验秒杀活动是否存在 + SeckillActivityDO activity = validateSeckillActivityExists(activityId); + if (CommonStatusEnum.isDisable(activity.getStatus())) { + throw exception(SECKILL_JOIN_ACTIVITY_STATUS_CLOSED); + } + // 1.2 是否在活动时间范围内 + if (!LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) { + throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); + } + SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig(); + if (config == null || !CollectionUtil.contains(activity.getConfigIds(), config.getId())) { + throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); + } + // 1.3 超过单次购买限制 + if (count > activity.getSingleLimitCount()) { + throw exception(SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); + } + + // 2.1 校验秒杀商品是否存在 + SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(activityId, skuId); + if (product == null) { + throw exception(SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); + } + // 2.2 校验库存是否充足 + if (count > product.getStock()) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + return SeckillActivityConvert.INSTANCE.convert02(activity, product); + } + + @Override + public List getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1.查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + List> spuIdAndActivityIdMaps = seckillActivityMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) { + return Collections.emptyList(); + } + // 2.查询活动详情 + return seckillActivityMapper.selectListByIdsAndDateTimeLt( + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java new file mode 100644 index 0000000..13214e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.promotion.service.seckill; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 秒杀时段 Service 接口 + * + * @author halfninety + */ +public interface SeckillConfigService { + + /** + * 创建秒杀时段 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSeckillConfig(@Valid SeckillConfigCreateReqVO createReqVO); + + /** + * 更新秒杀时段 + * + * @param updateReqVO 更新信息 + */ + void updateSeckillConfig(@Valid SeckillConfigUpdateReqVO updateReqVO); + + /** + * 删除秒杀时段 + * + * @param id 编号 + */ + void deleteSeckillConfig(Long id); + + /** + * 获得秒杀时段 + * + * @param id 编号 + * @return 秒杀时段 + */ + SeckillConfigDO getSeckillConfig(Long id); + + /** + * 获得所有秒杀时段列表 + * + * @return 所有秒杀时段列表 + */ + List getSeckillConfigList(); + + /** + * 校验秒杀时段是否存在 + * + * @param ids 秒杀时段 id 集合 + */ + void validateSeckillConfigExists(Collection ids); + + /** + * 获得秒杀时间段配置分页数据 + * + * @param pageVO 分页请求参数 + * @return 秒杀时段分页列表 + */ + PageResult getSeckillConfigPage(SeckillConfigPageReqVO pageVO); + + /** + * 获得所有正常状态的时段配置列表 + * + * @param status 状态 + * @return 秒杀时段列表 + */ + List getSeckillConfigListByStatus(Integer status); + + /** + * 更新秒杀时段配置状态 + * + * @param id id + * @param status 状态 + */ + void updateSeckillConfigStatus(Long id, Integer status); + + /** + * 获得当前的秒杀时段 + * + * 要求必须处于开启状态、且在当前时间段内 + * + * @return 时段 + */ + SeckillConfigDO getCurrentSeckillConfig(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java new file mode 100644 index 0000000..c24493b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.promotion.service.seckill; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalTime; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; + +/** + * 秒杀时段 Service 实现类 + * + * @author halfninety + */ +@Service +@Validated +public class SeckillConfigServiceImpl implements SeckillConfigService { + + @Resource + private SeckillConfigMapper seckillConfigMapper; + + @Override + public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) { + // 校验时间段是否冲突 + validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime(), null); + + // 插入 + SeckillConfigDO seckillConfig = SeckillConfigConvert.INSTANCE.convert(createReqVO); + seckillConfigMapper.insert(seckillConfig); + // 返回 + return seckillConfig.getId(); + } + + @Override + public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) { + // 校验存在 + validateSeckillConfigExists(updateReqVO.getId()); + // 校验时间段是否冲突 + validateSeckillConfigConflict(updateReqVO.getStartTime(), updateReqVO.getEndTime(), updateReqVO.getId()); + + // 更新 + SeckillConfigDO updateObj = SeckillConfigConvert.INSTANCE.convert(updateReqVO); + seckillConfigMapper.updateById(updateObj); + } + + @Override + public void updateSeckillConfigStatus(Long id, Integer status) { + // 校验秒杀时段是否存在 + validateSeckillConfigExists(id); + + // 更新状态 + seckillConfigMapper.updateById(new SeckillConfigDO().setId(id).setStatus(status)); + } + + @Override + public SeckillConfigDO getCurrentSeckillConfig() { + List list = seckillConfigMapper.selectList(SeckillConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); + return findFirst(list, config -> isBetween(config.getStartTime(), config.getEndTime())); + } + + @Override + public void deleteSeckillConfig(Long id) { + // 校验存在 + validateSeckillConfigExists(id); + + // 删除 + seckillConfigMapper.deleteById(id); + } + + private void validateSeckillConfigExists(Long id) { + if (seckillConfigMapper.selectById(id) == null) { + throw exception(SECKILL_CONFIG_NOT_EXISTS); + } + } + + /** + * 校验时间是否存在冲突 + * + * @param startTimeStr 开始时间 + * @param endTimeStr 结束时间 + */ + private void validateSeckillConfigConflict(String startTimeStr, String endTimeStr, Long id) { + // 1. 查询出所有的时段配置 + LocalTime startTime = LocalTime.parse(startTimeStr); + LocalTime endTime = LocalTime.parse(endTimeStr); + List configs = seckillConfigMapper.selectList(); + // 更新时排除自己 + if (id != null) { + configs.removeIf(item -> ObjectUtil.equal(item.getId(), id)); + } + + // 2. 判断是否有重叠的时间 + boolean hasConflict = configs.stream().anyMatch(config -> LocalDateTimeUtils.isOverlap(startTime, endTime, + LocalTime.parse(config.getStartTime()), LocalTime.parse(config.getEndTime()))); + if (hasConflict) { + throw exception(SECKILL_CONFIG_TIME_CONFLICTS); + } + } + + + @Override + public SeckillConfigDO getSeckillConfig(Long id) { + return seckillConfigMapper.selectById(id); + } + + @Override + public List getSeckillConfigList() { + return seckillConfigMapper.selectList(); + } + + @Override + public void validateSeckillConfigExists(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 1. 如果有数量不匹配,说明有不存在的,则抛出 SECKILL_CONFIG_NOT_EXISTS 业务异常 + List configs = seckillConfigMapper.selectBatchIds(ids); + if (configs.size() != ids.size()) { + throw exception(SECKILL_CONFIG_NOT_EXISTS); + } + + // 2. 如果存在关闭,则抛出 SECKILL_CONFIG_DISABLE 业务异常 + configs.forEach(config -> { + if (ObjectUtil.equal(config.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + throw exception(SECKILL_CONFIG_DISABLE); + } + }); + } + + @Override + public PageResult getSeckillConfigPage(SeckillConfigPageReqVO pageVO) { + return seckillConfigMapper.selectPage(pageVO); + } + + @Override + public List getSeckillConfigListByStatus(Integer status) { + List list = seckillConfigMapper.selectListByStatus(status); + list.sort(Comparator.comparing(SeckillConfigDO::getStartTime)); + return list; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java new file mode 100644 index 0000000..2ad362f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.util; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; + +import java.time.LocalDateTime; + +/** + * 活动工具类 + * + * @author 芋道源码 + */ +public class PromotionUtils { + + /** + * 根据时间,计算活动状态 + * + * @param endTime 结束时间 + * @return 活动状态 + */ + public static Integer calculateActivityStatus(LocalDateTime endTime) { + return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml new file mode 100644 index 0000000..76af37d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImplTest.java new file mode 100644 index 0000000..2f4abc7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImplTest.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleCategoryMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +// TODO 芋艿:review 单测 +/** + * {@link ArticleCategoryServiceImpl} 的单元测试类 + * + * @author HUIHUI + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ArticleCategoryServiceImpl.class) +public class ArticleCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private ArticleCategoryServiceImpl articleCategoryService; + + @Resource + private ArticleCategoryMapper articleCategoryMapper; + + @Test + public void testCreateArticleCategory_success() { + // 准备参数 + ArticleCategoryCreateReqVO reqVO = randomPojo(ArticleCategoryCreateReqVO.class); + + // 调用 + Long articleCategoryId = articleCategoryService.createArticleCategory(reqVO); + // 断言 + assertNotNull(articleCategoryId); + // 校验记录的属性是否正确 + ArticleCategoryDO articleCategory = articleCategoryMapper.selectById(articleCategoryId); + assertPojoEquals(reqVO, articleCategory); + } + + @Test + public void testUpdateArticleCategory_success() { + // mock 数据 + ArticleCategoryDO dbArticleCategory = randomPojo(ArticleCategoryDO.class); + articleCategoryMapper.insert(dbArticleCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ArticleCategoryUpdateReqVO reqVO = randomPojo(ArticleCategoryUpdateReqVO.class, o -> { + o.setId(dbArticleCategory.getId()); // 设置更新的 ID + }); + + // 调用 + articleCategoryService.updateArticleCategory(reqVO); + // 校验是否更新正确 + ArticleCategoryDO articleCategory = articleCategoryMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, articleCategory); + } + + @Test + public void testUpdateArticleCategory_notExists() { + // 准备参数 + ArticleCategoryUpdateReqVO reqVO = randomPojo(ArticleCategoryUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> articleCategoryService.updateArticleCategory(reqVO), ARTICLE_CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteArticleCategory_success() { + // mock 数据 + ArticleCategoryDO dbArticleCategory = randomPojo(ArticleCategoryDO.class); + articleCategoryMapper.insert(dbArticleCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbArticleCategory.getId(); + + // 调用 + articleCategoryService.deleteArticleCategory(id); + // 校验数据不存在了 + assertNull(articleCategoryMapper.selectById(id)); + } + + @Test + public void testDeleteArticleCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> articleCategoryService.deleteArticleCategory(id), ARTICLE_CATEGORY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetArticleCategoryPage() { + // mock 数据 + ArticleCategoryDO dbArticleCategory = randomPojo(ArticleCategoryDO.class, o -> { // 等会查询到 + o.setName(null); + o.setPicUrl(null); + o.setStatus(null); + o.setSort(null); + o.setCreateTime(null); + }); + articleCategoryMapper.insert(dbArticleCategory); + // 测试 name 不匹配 + articleCategoryMapper.insert(cloneIgnoreId(dbArticleCategory, o -> o.setName(null))); + // 测试 picUrl 不匹配 + articleCategoryMapper.insert(cloneIgnoreId(dbArticleCategory, o -> o.setPicUrl(null))); + // 测试 status 不匹配 + articleCategoryMapper.insert(cloneIgnoreId(dbArticleCategory, o -> o.setStatus(null))); + // 测试 sort 不匹配 + articleCategoryMapper.insert(cloneIgnoreId(dbArticleCategory, o -> o.setSort(null))); + // 测试 createTime 不匹配 + articleCategoryMapper.insert(cloneIgnoreId(dbArticleCategory, o -> o.setCreateTime(null))); + // 准备参数 + ArticleCategoryPageReqVO reqVO = new ArticleCategoryPageReqVO(); + reqVO.setName(null); + reqVO.setStatus(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = articleCategoryService.getArticleCategoryPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbArticleCategory, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImplTest.java new file mode 100644 index 0000000..0b0507d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImplTest.java @@ -0,0 +1,168 @@ +package cn.iocoder.yudao.module.promotion.service.article; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link ArticleServiceImpl} 的单元测试类 + * + * @author HUIHUI + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(ArticleServiceImpl.class) +public class ArticleServiceImplTest extends BaseDbUnitTest { + + @Resource + private ArticleServiceImpl articleService; + + @Resource + private ArticleMapper articleMapper; + + @Test + public void testCreateArticle_success() { + // 准备参数 + ArticleCreateReqVO reqVO = randomPojo(ArticleCreateReqVO.class); + + // 调用 + Long articleId = articleService.createArticle(reqVO); + // 断言 + assertNotNull(articleId); + // 校验记录的属性是否正确 + ArticleDO article = articleMapper.selectById(articleId); + assertPojoEquals(reqVO, article); + } + + @Test + public void testUpdateArticle_success() { + // mock 数据 + ArticleDO dbArticle = randomPojo(ArticleDO.class); + articleMapper.insert(dbArticle);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ArticleUpdateReqVO reqVO = randomPojo(ArticleUpdateReqVO.class, o -> { + o.setId(dbArticle.getId()); // 设置更新的 ID + }); + + // 调用 + articleService.updateArticle(reqVO); + // 校验是否更新正确 + ArticleDO article = articleMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, article); + } + + @Test + public void testUpdateArticle_notExists() { + // 准备参数 + ArticleUpdateReqVO reqVO = randomPojo(ArticleUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> articleService.updateArticle(reqVO), ARTICLE_NOT_EXISTS); + } + + @Test + public void testDeleteArticle_success() { + // mock 数据 + ArticleDO dbArticle = randomPojo(ArticleDO.class); + articleMapper.insert(dbArticle);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbArticle.getId(); + + // 调用 + articleService.deleteArticle(id); + // 校验数据不存在了 + assertNull(articleMapper.selectById(id)); + } + + @Test + public void testDeleteArticle_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> articleService.deleteArticle(id), ARTICLE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetArticlePage() { + // mock 数据 + ArticleDO dbArticle = randomPojo(ArticleDO.class, o -> { // 等会查询到 + o.setCategoryId(null); + o.setTitle(null); + o.setAuthor(null); + o.setPicUrl(null); + o.setIntroduction(null); + o.setBrowseCount(null); + o.setSort(null); + o.setStatus(null); + o.setSpuId(null); + o.setRecommendHot(null); + o.setRecommendBanner(null); + o.setContent(null); + o.setCreateTime(null); + }); + articleMapper.insert(dbArticle); + // 测试 categoryId 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setCategoryId(null))); + // 测试 title 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setTitle(null))); + // 测试 author 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setAuthor(null))); + // 测试 picUrl 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setPicUrl(null))); + // 测试 introduction 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setIntroduction(null))); + // 测试 browseCount 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setBrowseCount(null))); + // 测试 sort 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setSort(null))); + // 测试 status 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setStatus(null))); + // 测试 spuId 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setSpuId(null))); + // 测试 recommendHot 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setRecommendHot(null))); + // 测试 recommendBanner 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setRecommendBanner(null))); + // 测试 content 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setContent(null))); + // 测试 createTime 不匹配 + articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setCreateTime(null))); + // 准备参数 + ArticlePageReqVO reqVO = new ArticlePageReqVO(); + reqVO.setCategoryId(null); + reqVO.setTitle(null); + reqVO.setAuthor(null); + reqVO.setStatus(null); + reqVO.setSpuId(null); + reqVO.setRecommendHot(null); + reqVO.setRecommendBanner(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = articleService.getArticlePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbArticle, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java new file mode 100644 index 0000000..4ae4f1d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java @@ -0,0 +1,199 @@ +package cn.iocoder.yudao.module.promotion.service.combination; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_ACTIVITY_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +// TODO 芋艿:等完成后,在补全单测 +/** + * {@link CombinationActivityServiceImpl} 的单元测试类 + * + * @author HUIHUI + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(CombinationActivityServiceImpl.class) +public class CombinationActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private CombinationActivityServiceImpl combinationActivityService; + + @Resource + private CombinationActivityMapper combinationActivityMapper; + + @Test + public void testCreateCombinationActivity_success() { + // 准备参数 + CombinationActivityCreateReqVO reqVO = randomPojo(CombinationActivityCreateReqVO.class); + + // 调用 + Long combinationActivityId = combinationActivityService.createCombinationActivity(reqVO); + // 断言 + assertNotNull(combinationActivityId); + // 校验记录的属性是否正确 + CombinationActivityDO combinationActivity = combinationActivityMapper.selectById(combinationActivityId); + assertPojoEquals(reqVO, combinationActivity); + } + + @Test + public void testUpdateCombinationActivity_success() { + // mock 数据 + CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class); + combinationActivityMapper.insert(dbCombinationActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + CombinationActivityUpdateReqVO reqVO = randomPojo(CombinationActivityUpdateReqVO.class, o -> { + o.setId(dbCombinationActivity.getId()); // 设置更新的 ID + }); + + // 调用 + combinationActivityService.updateCombinationActivity(reqVO); + // 校验是否更新正确 + CombinationActivityDO combinationActivity = combinationActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, combinationActivity); + } + + @Test + public void testUpdateCombinationActivity_notExists() { + // 准备参数 + CombinationActivityUpdateReqVO reqVO = randomPojo(CombinationActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> combinationActivityService.updateCombinationActivity(reqVO), COMBINATION_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteCombinationActivity_success() { + // mock 数据 + CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class); + combinationActivityMapper.insert(dbCombinationActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCombinationActivity.getId(); + + // 调用 + combinationActivityService.deleteCombinationActivity(id); + // 校验数据不存在了 + assertNull(combinationActivityMapper.selectById(id)); + } + + @Test + public void testDeleteCombinationActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> combinationActivityService.deleteCombinationActivity(id), COMBINATION_ACTIVITY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCombinationActivityPage() { + // mock 数据 + CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class, o -> { // 等会查询到 + o.setName(null); + //o.setSpuId(null); + o.setTotalLimitCount(null); + o.setSingleLimitCount(null); + o.setStartTime(null); + o.setEndTime(null); + o.setUserSize(null); + o.setVirtualGroup(null); + o.setStatus(null); + o.setLimitDuration(null); + o.setCreateTime(null); + }); + combinationActivityMapper.insert(dbCombinationActivity); + // 测试 name 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setName(null))); + // 测试 spuId 不匹配 + //combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null))); + // 测试 totalLimitCount 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalLimitCount(null))); + // 测试 singleLimitCount 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSingleLimitCount(null))); + // 测试 startTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setStartTime(null))); + // 测试 endTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setEndTime(null))); + // 测试 userSize 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null))); + // 测试 virtualGroup 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setVirtualGroup(null))); + // 测试 status 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setStatus(null))); + // 测试 limitDuration 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setLimitDuration(null))); + // 测试 createTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setCreateTime(null))); + // 准备参数 + CombinationActivityPageReqVO reqVO = new CombinationActivityPageReqVO(); + reqVO.setName(null); + reqVO.setStatus(null); + + // 调用 + PageResult pageResult = combinationActivityService.getCombinationActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbCombinationActivity, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCombinationActivityList() { + // mock 数据 + CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class, o -> { // 等会查询到 + o.setName(null); + //o.setSpuId(null); + o.setTotalLimitCount(null); + o.setSingleLimitCount(null); + o.setStartTime(null); + o.setEndTime(null); + o.setUserSize(null); + o.setVirtualGroup(null); + o.setStatus(null); + o.setLimitDuration(null); + o.setCreateTime(null); + }); + combinationActivityMapper.insert(dbCombinationActivity); + // 测试 name 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setName(null))); + // 测试 spuId 不匹配 + //combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null))); + // 测试 totalLimitCount 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalLimitCount(null))); + // 测试 singleLimitCount 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSingleLimitCount(null))); + // 测试 startTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setStartTime(null))); + // 测试 endTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setEndTime(null))); + // 测试 userSize 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null))); + // 测试 virtualGroup 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setVirtualGroup(null))); + // 测试 status 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setStatus(null))); + // 测试 limitDuration 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setLimitDuration(null))); + // 测试 createTime 不匹配 + combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setCreateTime(null))); + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java new file mode 100644 index 0000000..990b163 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.promotion.service.coupon; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link CouponTemplateServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(CouponTemplateServiceImpl.class) +public class CouponTemplateServiceImplTest extends BaseDbUnitTest { + + @Resource + private CouponTemplateServiceImpl couponTemplateService; + + @Resource + private CouponTemplateMapper couponTemplateMapper; + + @Test + public void testCreateCouponTemplate_success() { + // 准备参数 + CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class, + o -> o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()) + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType()) + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType())); + + // 调用 + Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO); + // 断言 + assertNotNull(couponTemplateId); + // 校验记录的属性是否正确 + CouponTemplateDO couponTemplate = couponTemplateMapper.selectById(couponTemplateId); + assertPojoEquals(reqVO, couponTemplate); + } + + @Test + public void testUpdateCouponTemplate_success() { + // mock 数据 + CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class); + couponTemplateMapper.insert(dbCouponTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> { + o.setId(dbCouponTemplate.getId()); // 设置更新的 ID + // 其它通用字段 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()) + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType()) + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType()); + }); + + // 调用 + couponTemplateService.updateCouponTemplate(reqVO); + // 校验是否更新正确 + CouponTemplateDO couponTemplate = couponTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, couponTemplate); + } + + @Test + public void testUpdateCouponTemplate_notExists() { + // 准备参数 + CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> couponTemplateService.updateCouponTemplate(reqVO), COUPON_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteCouponTemplate_success() { + // mock 数据 + CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class); + couponTemplateMapper.insert(dbCouponTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCouponTemplate.getId(); + + // 调用 + couponTemplateService.deleteCouponTemplate(id); + // 校验数据不存在了 + assertNull(couponTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteCouponTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> couponTemplateService.deleteCouponTemplate(id), COUPON_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testGetCouponTemplatePage() { + // mock 数据 + CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到 + o.setName("芋艿"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()); + o.setCreateTime(buildTime(2022, 2, 2)); + }); + couponTemplateMapper.insert(dbCouponTemplate); + // 测试 name 不匹配 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName("土豆"))); + // 测试 status 不匹配 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 type 不匹配 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()))); + // 测试 createTime 不匹配 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(buildTime(2022, 1, 1)))); + // 准备参数 + CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO(); + reqVO.setName("芋艿"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2022, 2, 1), buildTime(2022, 2, 3)})); + + // 调用 + PageResult pageResult = couponTemplateService.getCouponTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbCouponTemplate, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java new file mode 100644 index 0000000..1f0c5bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java @@ -0,0 +1,211 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DISCOUNT_ACTIVITY_NOT_EXISTS; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link DiscountActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(DiscountActivityServiceImpl.class) +public class DiscountActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private DiscountActivityServiceImpl discountActivityService; + + @Resource + private DiscountActivityMapper discountActivityMapper; + @Resource + private DiscountProductMapper discountProductMapper; + + @Test + public void testCreateDiscountActivity_success() { + // 准备参数 + DiscountActivityCreateReqVO reqVO = randomPojo(DiscountActivityCreateReqVO.class, o -> { + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + // 设置商品 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3), + new DiscountActivityBaseVO.Product().setSpuId(10L).setSkuId(20L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30))); + }); + + // 调用 + Long discountActivityId = discountActivityService.createDiscountActivity(reqVO); + // 断言 + assertNotNull(discountActivityId); + // 校验活动 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(discountActivityId); + assertPojoEquals(reqVO, discountActivity); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + // 校验商品 + List discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId()); + assertEquals(discountProducts.size(), reqVO.getProducts().size()); + for (int i = 0; i < reqVO.getProducts().size(); i++) { + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i); + DiscountProductDO discountProduct = discountProducts.get(i); + assertEquals(discountProduct.getActivityId(), discountActivity.getId()); + assertEquals(discountProduct.getSpuId(), product.getSpuId()); + assertEquals(discountProduct.getSkuId(), product.getSkuId()); + assertEquals(discountProduct.getDiscountType(), product.getDiscountType()); + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice()); + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent()); + } + } + + @Test + public void testUpdateDiscountActivity_success() { + // mock 数据(商品) + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // mock 数据(活动) + DiscountProductDO dbDiscountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId()) + .setSpuId(1L).setSkuId(2L).setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null)); + DiscountProductDO dbDiscountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId()) + .setSpuId(10L).setSkuId(20L).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null)); + discountProductMapper.insert(dbDiscountProduct01); + discountProductMapper.insert(dbDiscountProduct02); + // 准备参数 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class, o -> { + o.setId(dbDiscountActivity.getId()); // 设置更新的 ID + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + // 设置商品 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null), + new DiscountActivityBaseVO.Product().setSpuId(100L).setSkuId(200L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null))); + }); + + // 调用 + discountActivityService.updateDiscountActivity(reqVO); + // 校验活动 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, discountActivity); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + // 校验商品 + List discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId()); + assertEquals(discountProducts.size(), reqVO.getProducts().size()); + for (int i = 0; i < reqVO.getProducts().size(); i++) { + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i); + DiscountProductDO discountProduct = discountProducts.get(i); + assertEquals(discountProduct.getActivityId(), discountActivity.getId()); + assertEquals(discountProduct.getSpuId(), product.getSpuId()); + assertEquals(discountProduct.getSkuId(), product.getSkuId()); + assertEquals(discountProduct.getDiscountType(), product.getDiscountType()); + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice()); + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent()); + } + } + + @Test + public void testCloseDiscountActivity() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, + o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiscountActivity.getId(); + + // 调用 + discountActivityService.closeDiscountActivity(id); + // 校验状态 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); + } + + @Test + public void testUpdateDiscountActivity_notExists() { + // 准备参数 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> discountActivityService.updateDiscountActivity(reqVO), DISCOUNT_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteDiscountActivity_success() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, + o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus())); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiscountActivity.getId(); + + // 调用 + discountActivityService.deleteDiscountActivity(id); + // 校验数据不存在了 + assertNull(discountActivityMapper.selectById(id)); + } + + @Test + public void testDeleteDiscountActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> discountActivityService.deleteDiscountActivity(id), DISCOUNT_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testGetDiscountActivityPage() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, o -> { // 等会查询到 + o.setName("芋艿"); + o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()); + o.setCreateTime(buildTime(2021, 1, 15)); + }); + discountActivityMapper.insert(dbDiscountActivity); + // 测试 name 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setName("土豆"))); + // 测试 status 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setStatus(PromotionActivityStatusEnum.END.getStatus()))); + // 测试 createTime 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setCreateTime(buildTime(2021, 2, 10)))); + // 准备参数 + DiscountActivityPageReqVO reqVO = new DiscountActivityPageReqVO(); + reqVO.setName("芋艿"); + reqVO.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()); + reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 1, 1), buildTime(2021, 1, 31)})); + + // 调用 + PageResult pageResult = discountActivityService.getDiscountActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDiscountActivity, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImplTest.java new file mode 100644 index 0000000..2c1d189 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImplTest.java @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPagePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.page.DiyPageUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyPageDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyPageMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_PAGE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link DiyPageServiceImpl} 的单元测试类 + * + * @author owen + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(DiyPageServiceImpl.class) +public class DiyPageServiceImplTest extends BaseDbUnitTest { + + @Resource + private DiyPageServiceImpl diyPageService; + + @Resource + private DiyPageMapper diyPageMapper; + + @Test + public void testCreateDiyPage_success() { + // 准备参数 + DiyPageCreateReqVO reqVO = randomPojo(DiyPageCreateReqVO.class); + + // 调用 + Long diyPageId = diyPageService.createDiyPage(reqVO); + // 断言 + assertNotNull(diyPageId); + // 校验记录的属性是否正确 + DiyPageDO diyPage = diyPageMapper.selectById(diyPageId); + assertPojoEquals(reqVO, diyPage); + } + + @Test + public void testUpdateDiyPage_success() { + // mock 数据 + DiyPageDO dbDiyPage = randomPojo(DiyPageDO.class); + diyPageMapper.insert(dbDiyPage);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DiyPageUpdateReqVO reqVO = randomPojo(DiyPageUpdateReqVO.class, o -> { + o.setId(dbDiyPage.getId()); // 设置更新的 ID + }); + + // 调用 + diyPageService.updateDiyPage(reqVO); + // 校验是否更新正确 + DiyPageDO diyPage = diyPageMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, diyPage); + } + + @Test + public void testUpdateDiyPage_notExists() { + // 准备参数 + DiyPageUpdateReqVO reqVO = randomPojo(DiyPageUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> diyPageService.updateDiyPage(reqVO), DIY_PAGE_NOT_EXISTS); + } + + @Test + public void testDeleteDiyPage_success() { + // mock 数据 + DiyPageDO dbDiyPage = randomPojo(DiyPageDO.class); + diyPageMapper.insert(dbDiyPage);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiyPage.getId(); + + // 调用 + diyPageService.deleteDiyPage(id); + // 校验数据不存在了 + assertNull(diyPageMapper.selectById(id)); + } + + @Test + public void testDeleteDiyPage_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> diyPageService.deleteDiyPage(id), DIY_PAGE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetDiyPagePage() { + // mock 数据 + DiyPageDO dbDiyPage = randomPojo(DiyPageDO.class, o -> { // 等会查询到 + o.setName(null); + o.setCreateTime(null); + }); + diyPageMapper.insert(dbDiyPage); + // 测试 name 不匹配 + diyPageMapper.insert(cloneIgnoreId(dbDiyPage, o -> o.setName(null))); + // 测试 createTime 不匹配 + diyPageMapper.insert(cloneIgnoreId(dbDiyPage, o -> o.setCreateTime(null))); + // 准备参数 + DiyPagePageReqVO reqVO = new DiyPagePageReqVO(); + reqVO.setName(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = diyPageService.getDiyPagePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDiyPage, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImplTest.java new file mode 100644 index 0000000..1d7f9ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImplTest.java @@ -0,0 +1,176 @@ +package cn.iocoder.yudao.module.promotion.service.diy; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.diy.DiyTemplateDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.diy.DiyTemplateMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DIY_TEMPLATE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link DiyTemplateServiceImpl} 的单元测试类 + * + * @author owen + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(DiyTemplateServiceImpl.class) +public class DiyTemplateServiceImplTest extends BaseDbUnitTest { + + @Resource + private DiyTemplateServiceImpl diyTemplateService; + + @Resource + private DiyTemplateMapper diyTemplateMapper; + + @Test + public void testCreateDiyTemplate_success() { + // 准备参数 + DiyTemplateCreateReqVO reqVO = randomPojo(DiyTemplateCreateReqVO.class); + + // 调用 + Long diyTemplateId = diyTemplateService.createDiyTemplate(reqVO); + // 断言 + assertNotNull(diyTemplateId); + // 校验记录的属性是否正确 + DiyTemplateDO diyTemplate = diyTemplateMapper.selectById(diyTemplateId); + assertPojoEquals(reqVO, diyTemplate); + } + + @Test + public void testUpdateDiyTemplate_success() { + // mock 数据 + DiyTemplateDO dbDiyTemplate = randomPojo(DiyTemplateDO.class); + diyTemplateMapper.insert(dbDiyTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DiyTemplateUpdateReqVO reqVO = randomPojo(DiyTemplateUpdateReqVO.class, o -> { + o.setId(dbDiyTemplate.getId()); // 设置更新的 ID + }); + + // 调用 + diyTemplateService.updateDiyTemplate(reqVO); + // 校验是否更新正确 + DiyTemplateDO diyTemplate = diyTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, diyTemplate); + } + + @Test + public void testUpdateDiyTemplate_notExists() { + // 准备参数 + DiyTemplateUpdateReqVO reqVO = randomPojo(DiyTemplateUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> diyTemplateService.updateDiyTemplate(reqVO), DIY_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteDiyTemplate_success() { + // mock 数据 + DiyTemplateDO dbDiyTemplate = randomPojo(DiyTemplateDO.class); + diyTemplateMapper.insert(dbDiyTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiyTemplate.getId(); + + // 调用 + diyTemplateService.deleteDiyTemplate(id); + // 校验数据不存在了 + assertNull(diyTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteDiyTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> diyTemplateService.deleteDiyTemplate(id), DIY_TEMPLATE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetDiyTemplatePage() { + // mock 数据 + DiyTemplateDO dbDiyTemplate = randomPojo(DiyTemplateDO.class, o -> { // 等会查询到 + o.setName(null); + o.setUsed(null); + o.setUsedTime(null); + o.setRemark(null); + o.setPreviewPicUrls(null); + o.setProperty(null); + o.setCreateTime(null); + }); + diyTemplateMapper.insert(dbDiyTemplate); + // 测试 name 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setName(null))); + // 测试 used 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setUsed(null))); + // 测试 usedTime 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setUsedTime(null))); + // 测试 remark 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setRemark(null))); + // 测试 previewPicUrls 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setPreviewPicUrls(null))); + // 测试 property 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setProperty(null))); + // 测试 createTime 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setCreateTime(null))); + // 准备参数 + DiyTemplatePageReqVO reqVO = new DiyTemplatePageReqVO(); + reqVO.setName(null); + reqVO.setUsed(null); + reqVO.setUsedTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = diyTemplateService.getDiyTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDiyTemplate, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetDiyTemplateList() { + // mock 数据 + DiyTemplateDO dbDiyTemplate = randomPojo(DiyTemplateDO.class, o -> { // 等会查询到 + o.setName(null); + o.setUsed(null); + o.setUsedTime(null); + o.setRemark(null); + o.setPreviewPicUrls(null); + o.setProperty(null); + o.setCreateTime(null); + }); + diyTemplateMapper.insert(dbDiyTemplate); + // 测试 name 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setName(null))); + // 测试 used 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setUsed(null))); + // 测试 usedTime 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setUsedTime(null))); + // 测试 remark 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setRemark(null))); + // 测试 previewPicUrls 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setPreviewPicUrls(null))); + // 测试 property 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setProperty(null))); + // 测试 createTime 不匹配 + diyTemplateMapper.insert(cloneIgnoreId(dbDiyTemplate, o -> o.setCreateTime(null))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java new file mode 100644 index 0000000..c28287e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java @@ -0,0 +1,219 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Set; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link RewardActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(RewardActivityServiceImpl.class) +public class RewardActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private RewardActivityServiceImpl rewardActivityService; + + @Resource + private RewardActivityMapper rewardActivityMapper; + + @Test + public void testCreateRewardActivity_success() { + // 准备参数 + RewardActivityCreateReqVO reqVO = randomPojo(RewardActivityCreateReqVO.class, o -> { + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType()); + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()); + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + }); + + // 调用 + Long rewardActivityId = rewardActivityService.createRewardActivity(reqVO); + // 断言 + assertNotNull(rewardActivityId); + // 校验记录的属性是否正确 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId); + assertPojoEquals(reqVO, rewardActivity, "rules"); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + for (int i = 0; i < reqVO.getRules().size(); i++) { + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); + } + } + + @Test + public void testUpdateRewardActivity_success() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> { + o.setId(dbRewardActivity.getId()); // 设置更新的 ID + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType()); + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()); + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + }); + + // 调用 + rewardActivityService.updateRewardActivity(reqVO); + // 校验是否更新正确 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, rewardActivity, "rules"); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + for (int i = 0; i < reqVO.getRules().size(); i++) { + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); + } + } + + @Test + public void testCloseRewardActivity() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbRewardActivity.getId(); + + // 调用 + rewardActivityService.closeRewardActivity(id); + // 校验状态 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(id); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); + } + + @Test + public void testUpdateRewardActivity_notExists() { + // 准备参数 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> rewardActivityService.updateRewardActivity(reqVO), REWARD_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteRewardActivity_success() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbRewardActivity.getId(); + + // 调用 + rewardActivityService.deleteRewardActivity(id); + // 校验数据不存在了 + assertNull(rewardActivityMapper.selectById(id)); + } + + @Test + public void testDeleteRewardActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testGetRewardActivityPage() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到 + o.setName("芋艿"); + o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + }); + rewardActivityMapper.insert(dbRewardActivity); + // 测试 name 不匹配 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆"))); + // 测试 status 不匹配 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()))); + // 准备参数 + RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO(); + reqVO.setName("芋艿"); + reqVO.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + + // 调用 + PageResult pageResult = rewardActivityService.getRewardActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules"); + } + + @Test + public void testGetRewardActivities_all() { + // mock 数据 + RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.ALL.getScope())); + rewardActivityMapper.insert(allActivity); + RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); + rewardActivityMapper.insert(productActivity); + // 准备参数 + Set spuIds = asSet(1L, 2L); + + // 调用 TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList + //Map> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); + // 断言 + //assertEquals(matchRewardActivities.size(), 1); + //Map.Entry> next = matchRewardActivities.entrySet().iterator().next(); + //assertPojoEquals(next.getKey(), allActivity); + //assertEquals(next.getValue(), spuIds); + } + + @Test + public void testGetRewardActivities_product() { + // mock 数据 + RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); + rewardActivityMapper.insert(productActivity01); + RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(singletonList(3L))); + rewardActivityMapper.insert(productActivity02); + // 准备参数 + Set spuIds = asSet(1L, 2L, 3L); + + // 调用 TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList + //Map> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); + // 断言 + //assertEquals(matchRewardActivities.size(), 2); + //matchRewardActivities.forEach((activity, activitySpuIds) -> { + // if (activity.getId().equals(productActivity01.getId())) { + // assertPojoEquals(activity, productActivity01); + // assertEquals(activitySpuIds, asSet(1L, 2L)); + // } else if (activity.getId().equals(productActivity02.getId())) { + // assertPojoEquals(activity, productActivity02); + // assertEquals(activitySpuIds, asSet(3L)); + // } else { + // fail(); + // } + //}); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java new file mode 100644 index 0000000..93dbeca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.promotion.service.seckillactivity; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityServiceImpl; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link SeckillActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(SeckillActivityServiceImpl.class) +@Disabled // TODO 芋艿:未来开启 +public class SeckillActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private SeckillActivityServiceImpl seckillActivityService; + + @Resource + private SeckillActivityMapper seckillActivityMapper; + + @Test + public void testCreateSeckillActivity_success() { + // 准备参数 + SeckillActivityCreateReqVO reqVO = randomPojo(SeckillActivityCreateReqVO.class); + + // 调用 + Long seckillActivityId = seckillActivityService.createSeckillActivity(reqVO); + // 断言 + assertNotNull(seckillActivityId); + // 校验记录的属性是否正确 + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(seckillActivityId); + assertPojoEquals(reqVO, seckillActivity); + } + + @Test + public void testUpdateSeckillActivity_success() { + // mock 数据 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class); + seckillActivityMapper.insert(dbSeckillActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SeckillActivityUpdateReqVO reqVO = randomPojo(SeckillActivityUpdateReqVO.class, o -> { + o.setId(dbSeckillActivity.getId()); // 设置更新的 ID + }); + + // 调用 + seckillActivityService.updateSeckillActivity(reqVO); + // 校验是否更新正确 + SeckillActivityDO seckillActivity = seckillActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, seckillActivity); + } + + @Test + public void testUpdateSeckillActivity_notExists() { + // 准备参数 + SeckillActivityUpdateReqVO reqVO = randomPojo(SeckillActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> seckillActivityService.updateSeckillActivity(reqVO), SECKILL_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteSeckillActivity_success() { + // mock 数据 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class); + seckillActivityMapper.insert(dbSeckillActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSeckillActivity.getId(); + + // 调用 + seckillActivityService.deleteSeckillActivity(id); + // 校验数据不存在了 + assertNull(seckillActivityMapper.selectById(id)); + } + + @Test + public void testDeleteSeckillActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> seckillActivityService.deleteSeckillActivity(id), SECKILL_ACTIVITY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetSeckillActivityPage() { + // mock 数据 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStatus(null); + o.setConfigIds(null); + o.setCreateTime(null); + }); + seckillActivityMapper.insert(dbSeckillActivity); + // 测试 name 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setName(null))); + // 测试 status 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setStatus(null))); + // 测试 timeId 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setConfigIds(null))); + // 测试 createTime 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setCreateTime(null))); + // 准备参数 + SeckillActivityPageReqVO reqVO = new SeckillActivityPageReqVO(); + reqVO.setName(null); + reqVO.setStatus(null); + reqVO.setConfigId(null); + reqVO.setCreateTime((new LocalDateTime[]{})); + + // 调用 + PageResult pageResult = seckillActivityService.getSeckillActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSeckillActivity, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetSeckillActivityList() { + // mock 数据 + SeckillActivityDO dbSeckillActivity = randomPojo(SeckillActivityDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStatus(null); + o.setConfigIds(null); + o.setCreateTime(null); + }); + seckillActivityMapper.insert(dbSeckillActivity); + // 测试 name 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setName(null))); + // 测试 status 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setStatus(null))); + // 测试 timeId 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setConfigIds(null))); + // 测试 createTime 不匹配 + seckillActivityMapper.insert(cloneIgnoreId(dbSeckillActivity, o -> o.setCreateTime(null))); + // 准备参数 +// SeckillActivityExportReqVO reqVO = new SeckillActivityExportReqVO(); +// reqVO.setName(null); +// reqVO.setStatus(null); +// reqVO.setTimeId(null); +// reqVO.setCreateTime((new Date[]{})); +// +// // 调用 +// List list = seckillActivityService.getSeckillActivityList(reqVO); +// // 断言 +// assertEquals(1, list.size()); +// assertPojoEquals(dbSeckillActivity, list.get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillconfig/SeckillConfigServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillconfig/SeckillConfigServiceImplTest.java new file mode 100644 index 0000000..28dee33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillconfig/SeckillConfigServiceImplTest.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.promotion.service.seckillconfig; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper; +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigServiceImpl; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_CONFIG_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * {@link SeckillConfigServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(SeckillConfigServiceImpl.class) +@Disabled // TODO 芋艿:未来开启;后续要 review 下 +public class SeckillConfigServiceImplTest extends BaseDbUnitTest { + + @Resource + private SeckillConfigServiceImpl SeckillConfigService; + + @Resource + private SeckillConfigMapper seckillConfigMapper; + + @Resource + private ObjectMapper objectMapper; + + @Test + public void testJacksonSerializ() { + + // 准备参数 + SeckillConfigCreateReqVO reqVO = randomPojo(SeckillConfigCreateReqVO.class); +// ObjectMapper objectMapper = new ObjectMapper(); + try { + String string = objectMapper.writeValueAsString(reqVO); + System.out.println(string); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + + } + + @Test + public void testCreateSeckillConfig_success() { + // 准备参数 + SeckillConfigCreateReqVO reqVO = randomPojo(SeckillConfigCreateReqVO.class); + + // 调用 + Long SeckillConfigId = SeckillConfigService.createSeckillConfig(reqVO); + // 断言 + assertNotNull(SeckillConfigId); + // 校验记录的属性是否正确 + SeckillConfigDO SeckillConfig = seckillConfigMapper.selectById(SeckillConfigId); + assertPojoEquals(reqVO, SeckillConfig); + } + + @Test + public void testUpdateSeckillConfig_success() { + // mock 数据 + SeckillConfigDO dbSeckillConfig = randomPojo(SeckillConfigDO.class); + seckillConfigMapper.insert(dbSeckillConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SeckillConfigUpdateReqVO reqVO = randomPojo(SeckillConfigUpdateReqVO.class, o -> { + o.setId(dbSeckillConfig.getId()); // 设置更新的 ID + }); + + // 调用 + SeckillConfigService.updateSeckillConfig(reqVO); + // 校验是否更新正确 + SeckillConfigDO SeckillConfig = seckillConfigMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, SeckillConfig); + } + + @Test + public void testUpdateSeckillConfig_notExists() { + // 准备参数 + SeckillConfigUpdateReqVO reqVO = randomPojo(SeckillConfigUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> SeckillConfigService.updateSeckillConfig(reqVO), SECKILL_CONFIG_NOT_EXISTS); + } + + @Test + public void testDeleteSeckillConfig_success() { + // mock 数据 + SeckillConfigDO dbSeckillConfig = randomPojo(SeckillConfigDO.class); + seckillConfigMapper.insert(dbSeckillConfig);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSeckillConfig.getId(); + + // 调用 + SeckillConfigService.deleteSeckillConfig(id); + // 校验数据不存在了 + assertNull(seckillConfigMapper.selectById(id)); + } + + @Test + public void testDeleteSeckillConfig_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> SeckillConfigService.deleteSeckillConfig(id), SECKILL_CONFIG_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetSeckillConfigPage() { + // mock 数据 +// SeckillConfigDO dbSeckillConfig = randomPojo(SeckillConfigDO.class, o -> { // 等会查询到 +// o.setName(null); +// o.setStartTime(null); +// o.setEndTime(null); +// o.setCreateTime(null); +// }); +// seckillConfigMapper.insert(dbSeckillConfig); +// // 测试 name 不匹配 +// seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setName(null))); +// // 测试 startTime 不匹配 +// seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setStartTime(null))); +// // 测试 endTime 不匹配 +// seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setEndTime(null))); +// // 测试 createTime 不匹配 +// seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setCreateTime(null))); +// // 准备参数 +// SeckillConfigPageReqVO reqVO = new SeckillConfigPageReqVO(); +// reqVO.setName(null); +//// reqVO.setStartTime((new LocalTime())); +//// reqVO.setEndTime((new LocalTime[]{})); +//// reqVO.setCreateTime((new Date[]{})); +// +// // 调用 +// PageResult pageResult = SeckillConfigService.getSeckillConfigPage(reqVO); +// // 断言 +// assertEquals(1, pageResult.getTotal()); +// assertEquals(1, pageResult.getList().size()); +// assertPojoEquals(dbSeckillConfig, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetSeckillConfigList() { + // mock 数据 + SeckillConfigDO dbSeckillConfig = randomPojo(SeckillConfigDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStartTime(null); + o.setEndTime(null); + o.setCreateTime(null); + }); + seckillConfigMapper.insert(dbSeckillConfig); + // 测试 name 不匹配 + seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setName(null))); + // 测试 startTime 不匹配 + seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setStartTime(null))); + // 测试 endTime 不匹配 + seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setEndTime(null))); + // 测试 createTime 不匹配 + seckillConfigMapper.insert(cloneIgnoreId(dbSeckillConfig, o -> o.setCreateTime(null))); + // 准备参数 +// SeckillConfigExportReqVO reqVO = new SeckillConfigExportReqVO(); +// reqVO.setName(null); +// reqVO.setStartTime((new LocalTime[]{})); +// reqVO.setEndTime((new LocalTime[]{})); +// reqVO.setCreateTime((new Date[]{})); +// +// // 调用 +// List list = SeckillConfigService.getSeckillConfigList(reqVO); +// // 断言 +// assertEquals(1, list.size()); +// assertPojoEquals(dbSeckillConfig, list.get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..c656a9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,47 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..6a1a242 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,12 @@ +DELETE FROM "market_activity"; +DELETE FROM "promotion_coupon_template"; +DELETE FROM "promotion_coupon"; +DELETE FROM "promotion_reward_activity"; +DELETE FROM "promotion_discount_activity"; +DELETE FROM "promotion_discount_product"; +DELETE FROM "promotion_seckill_config"; +DELETE FROM "promotion_combination_activity"; +DELETE FROM "promotion_article_category"; +DELETE FROM "promotion_article"; +DELETE FROM "promotion_diy_template"; +DELETE FROM "promotion_diy_page"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..00ac3f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,256 @@ +CREATE TABLE IF NOT EXISTS "market_activity" +( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "title" varchar(50) NOT NULL, + "activity_type" tinyint(4) NOT NULL, + "status" tinyint(4) NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "invalid_time" datetime, + "delete_time" datetime, + "time_limited_discount" varchar(2000), + "full_privilege" varchar(2000), + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint(20) NOT NULL, + PRIMARY KEY ("id") +) COMMENT '促销活动'; + +CREATE TABLE IF NOT EXISTS "promotion_coupon_template" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "total_count" int NOT NULL, + "take_limit_count" int NOT NULL, + "take_type" int NOT NULL, + "use_price" int NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "validity_type" int NOT NULL, + "valid_start_time" datetime, + "valid_end_time" datetime, + "fixed_start_term" int, + "fixed_end_term" int, + "discount_type" int NOT NULL, + "discount_percent" int, + "discount_price" int, + "discount_limit_price" int, + "take_count" int NOT NULL DEFAULT 0, + "use_count" int NOT NULL DEFAULT 0, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '优惠劵模板'; + +CREATE TABLE IF NOT EXISTS "promotion_coupon" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "template_id" bigint NOT NULL, + "name" varchar NOT NULL, + "status" int NOT NULL, + "user_id" bigint NOT NULL, + "take_type" int NOT NULL, + "useprice" int NOT NULL, + "valid_start_time" datetime NOT NULL, + "valid_end_time" datetime NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "discount_type" int NOT NULL, + "discount_percent" int, + "discount_price" int, + "discount_limit_price" int, + "use_order_id" bigint, + "use_time" datetime, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '优惠劵'; + +CREATE TABLE IF NOT EXISTS "promotion_reward_activity" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "remark" varchar, + "condition_type" int NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "rules" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '满减送活动'; + +CREATE TABLE IF NOT EXISTS "promotion_discount_activity" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '限时折扣活动'; + +CREATE TABLE IF NOT EXISTS "promotion_seckill_activity" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "spu_id" bigint NOT NULL, + "name" varchar NOT NULL, + "status" int NOT NULL, + "remark" varchar, + "start_time" varchar NOT NULL, + "end_time" varchar NOT NULL, + "sort" int NOT NULL, + "config_ids" varchar NOT NULL, + "order_count" int NOT NULL, + "user_count" int NOT NULL, + "total_price" int NOT NULL, + "total_limit_count" int, + "single_limit_count" int, + "stock" int, + "total_stock" int, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '秒杀活动'; + +CREATE TABLE IF NOT EXISTS "promotion_seckill_config" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "start_time" varchar NOT NULL, + "end_time" varchar NOT NULL, + "pic_url" varchar NOT NULL, + "status" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '秒杀时段配置'; + +CREATE TABLE IF NOT EXISTS "promotion_combination_activity" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "spu_id" bigint, + "total_limit_count" int NOT NULL, + "single_limit_count" int NOT NULL, + "start_time" varchar NOT NULL, + "end_time" varchar NOT NULL, + "user_size" int NOT NULL, + "total_num" int NOT NULL, + "success_num" int NOT NULL, + "order_user_count" int NOT NULL, + "virtual_group" int NOT NULL, + "status" int NOT NULL, + "limit_duration" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '拼团活动'; + +CREATE TABLE IF NOT EXISTS "promotion_article_category" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "pic_url" varchar, + "status" int NOT NULL, + "sort" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '文章分类表'; + +CREATE TABLE IF NOT EXISTS "promotion_article" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "category_id" bigint NOT NULL, + "title" varchar NOT NULL, + "author" varchar, + "pic_url" varchar NOT NULL, + "introduction" varchar, + "browse_count" varchar, + "sort" int NOT NULL, + "status" int NOT NULL, + "spu_id" bigint NOT NULL, + "recommend_hot" bit NOT NULL, + "recommend_banner" bit NOT NULL, + "content" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '文章管理表'; + +CREATE TABLE IF NOT EXISTS "promotion_diy_template" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "used" bit NOT NULL, + "used_time" varchar, + "remark" varchar, + "preview_pic_urls" varchar, + "property" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL DEFAULT 0, + PRIMARY KEY ("id") +) COMMENT '装修模板'; +CREATE TABLE IF NOT EXISTS "promotion_diy_page" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "template_id" bigint NOT NULL, + "name" varchar NOT NULL, + "remark" varchar, + "preview_pic_urls" varchar, + "property" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT '装修页面'; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/pom.xml new file mode 100644 index 0000000..7c838fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-statistics-api + jar + + ${project.artifactId} + + statistics 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/api/package-info.java new file mode 100644 index 0000000..2963c12 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/api/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 占位,无特殊含义 + */ +package cn.iocoder.yudao.module.statistics.api; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/TimeRangeTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/TimeRangeTypeEnum.java new file mode 100644 index 0000000..5f3c8fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/TimeRangeTypeEnum.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.statistics.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 时间范围类型的枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum TimeRangeTypeEnum implements IntArrayValuable { + + /** + * 天 + */ + DAY(1), + /** + * 周 + */ + WEEK(7), + /** + * 月 + */ + MONTH(30), + /** + * 年 + */ + YEAR(365), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TimeRangeTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/package-info.java new file mode 100644 index 0000000..f885ae0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-api/src/main/java/cn/iocoder/yudao/module/statistics/enums/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 占位,无特殊含义 + */ +package cn.iocoder.yudao.module.statistics.enums; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/pom.xml new file mode 100644 index 0000000..fc15455 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/pom.xml @@ -0,0 +1,91 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-statistics-biz + jar + + ${project.artifactId} + + statistics 模块,主要实现统计相关功能 + 例如:统计商品、会员、交易等功能。 + + + + + cn.iocoder.boot + yudao-module-statistics-api + ${revision} + + + cn.iocoder.boot + yudao-module-promotion-api + ${revision} + + + cn.iocoder.boot + yudao-module-product-api + ${revision} + + + cn.iocoder.boot + yudao-module-trade-api + ${revision} + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + cn.iocoder.boot + yudao-module-pay-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/common/vo/DataComparisonRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/common/vo/DataComparisonRespVO.java new file mode 100644 index 0000000..efd889a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/common/vo/DataComparisonRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.common.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 数据对照 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DataComparisonRespVO { + + @Schema(description = "当前数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private T value; + + @Schema(description = "参照数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private T reference; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java new file mode 100644 index 0000000..9b0f715 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.NumberUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.*; +import cn.iocoder.yudao.module.statistics.convert.member.MemberStatisticsConvert; +import cn.iocoder.yudao.module.statistics.service.infra.ApiAccessLogStatisticsService; +import cn.iocoder.yudao.module.statistics.service.member.MemberStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.TradeOrderStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员统计") +@RestController +@RequestMapping("/statistics/member") +@Validated +@Slf4j +public class MemberStatisticsController { + + @Resource + private MemberStatisticsService memberStatisticsService; + @Resource + private TradeOrderStatisticsService tradeOrderStatisticsService; + @Resource + private ApiAccessLogStatisticsService apiAccessLogStatisticsService; + + @GetMapping("/summary") + @Operation(summary = "获得会员统计(实时统计)") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult getMemberSummary() { + return success(memberStatisticsService.getMemberSummary()); + } + + @GetMapping("/analyse") + @Operation(summary = "获得会员分析数据") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult getMemberAnalyse(MemberAnalyseReqVO reqVO) { + // 1. 查询数据 + LocalDateTime beginTime = ArrayUtil.get(reqVO.getTimes(), 0); + LocalDateTime endTime = ArrayUtil.get(reqVO.getTimes(), 1); + // 1.1 查询分析对照数据 + DataComparisonRespVO comparisonData = memberStatisticsService.getMemberAnalyseComparisonData(beginTime, endTime); + // TODO @疯狂:这个可能有点特殊,要按照 create_time 来查询;不然它的漏斗就不统一;因为是访问数量 > 今日下单人 > 今日支付人;是一个统一的维度; + // 1.2 查询成交用户数量 + Integer payUserCount = tradeOrderStatisticsService.getPayUserCount(beginTime, endTime); + // 1.3 计算客单价 + int atv = 0; + if (payUserCount != null && payUserCount > 0) { + // TODO @疯狂:类似上面的 payUserCount + Integer payPrice = tradeOrderStatisticsService.getOrderPayPrice(beginTime, endTime); + atv = NumberUtil.div(payPrice, payUserCount).intValue(); + } + // 1.4 查询访客数量 + Integer visitUserCount = apiAccessLogStatisticsService.getIpCount(UserTypeEnum.MEMBER.getValue(), beginTime, endTime); + // 1.5 下单用户数量 + Integer orderUserCount = tradeOrderStatisticsService.getOrderUserCount(beginTime, endTime); + + // 2. 拼接返回 + return success(MemberStatisticsConvert.INSTANCE.convert(visitUserCount, orderUserCount, payUserCount, atv, comparisonData)); + } + + @GetMapping("/area-statistics-list") + @Operation(summary = "按照省份,获得会员统计列表") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult> getMemberAreaStatisticsList() { + return success(memberStatisticsService.getMemberAreaStatisticsList()); + } + + @GetMapping("/sex-statistics-list") + @Operation(summary = "按照性别,获得会员统计列表") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult> getMemberSexStatisticsList() { + return success(memberStatisticsService.getMemberSexStatisticsList()); + } + + @GetMapping("/terminal-statistics-list") + @Operation(summary = "按照终端,获得会员统计列表") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult> getMemberTerminalStatisticsList() { + return success(memberStatisticsService.getMemberTerminalStatisticsList()); + } + + // TODO @疯狂:要注意 date 的排序; + @GetMapping("/user-count-comparison") + @Operation(summary = "获得用户数量对照") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult> getUserCountComparison() { + return success(memberStatisticsService.getUserCountComparison()); + } + + @GetMapping("/register-count-list") + @Operation(summary = "获得会员注册数量列表") + @PreAuthorize("@ss.hasPermission('statistics:member:query')") + public CommonResult> getMemberRegisterCountList(MemberAnalyseReqVO reqVO) { + return success(memberStatisticsService.getMemberRegisterCountList( + ArrayUtil.get(reqVO.getTimes(), 0), ArrayUtil.get(reqVO.getTimes(), 1))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseDataRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseDataRespVO.java new file mode 100644 index 0000000..d2dd3e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseDataRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员分析数据 Response VO") +@Data +public class MemberAnalyseDataRespVO { + + @Schema(description = "会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer registerUserCount; + + @Schema(description = "活跃用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer visitUserCount; + + @Schema(description = "充值会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "221") + private Integer rechargeUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseReqVO.java new file mode 100644 index 0000000..e0106b4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员分析 Request VO") +@Data +public class MemberAnalyseReqVO { + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "时间范围") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseRespVO.java new file mode 100644 index 0000000..e1c4654 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAnalyseRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员分析 Response VO") +@Data +public class MemberAnalyseRespVO { + + @Schema(description = "访客数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer visitUserCount; + + @Schema(description = "下单用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderUserCount; + + @Schema(description = "成交用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer payUserCount; + + @Schema(description = "客单价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer atv; + + @Schema(description = "对照数据", requiredMode = Schema.RequiredMode.REQUIRED) + private DataComparisonRespVO comparison; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAreaStatisticsRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAreaStatisticsRespVO.java new file mode 100644 index 0000000..1024d04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberAreaStatisticsRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员地区统计 Response VO") +@Data +public class MemberAreaStatisticsRespVO { + + @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer areaId; + @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") + private String areaName; + + @Schema(description = "会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer userCount; + + @Schema(description = "下单的会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderCreateUserCount; + @Schema(description = "支付订单的会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") + private Integer orderPayUserCount; + + @Schema(description = "订单支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "622") + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberCountRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberCountRespVO.java new file mode 100644 index 0000000..ce81658 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberCountRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员数量统计 Response VO") +@Data +public class MemberCountRespVO { + + @Schema(description = "用户访问量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer visitUserCount; + + @Schema(description = "注册用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer registerUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberRegisterCountRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberRegisterCountRespVO.java new file mode 100644 index 0000000..fb7fc2a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberRegisterCountRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +@Schema(description = "管理后台 - 会员注册数量 Response VO") +@Data +public class MemberRegisterCountRespVO { + + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private LocalDate date; + + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer count; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSexStatisticsRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSexStatisticsRespVO.java new file mode 100644 index 0000000..eaf7ce5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSexStatisticsRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员性别统计 Response VO") +@Data +public class MemberSexStatisticsRespVO { + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sex; + + // TODO @疯狂:要不还是其它字段,我们也补全,这样方便使用的用户,做定制化;就保持和 MemberAreaStatisticsRespVO 一致; + @Schema(description = "会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer userCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSummaryRespVO.java new file mode 100644 index 0000000..2a55e38 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberSummaryRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员统计 Response VO") +@Data +public class MemberSummaryRespVO { + + @Schema(description = "会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer userCount; + + @Schema(description = "充值会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "221") + private Integer rechargeUserCount; + + @Schema(description = "充值金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer rechargePrice; + + // TODO @疯狂:要不干脆这个字段改成:orderPayPrice?? + @Schema(description = "支出金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer expensePrice; // 只计算 mall 交易订单的支付金额,不考虑退款 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberTerminalStatisticsRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberTerminalStatisticsRespVO.java new file mode 100644 index 0000000..3ecf0f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/vo/MemberTerminalStatisticsRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员终端统计 Response VO") +@Data +public class MemberTerminalStatisticsRespVO { + + @Schema(description = "终端", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer terminal; + + // TODO @疯狂:要不 orderCreateUserCount 和 orderPayUserCount 貌似更统一一些; + @Schema(description = "会员数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer userCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/PayStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/PayStatisticsController.java new file mode 100644 index 0000000..362ec7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/PayStatisticsController.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.pay; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.statistics.controller.admin.pay.vo.PaySummaryRespVO; +import cn.iocoder.yudao.module.statistics.convert.pay.PayStatisticsConvert; +import cn.iocoder.yudao.module.statistics.service.pay.PayWalletStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 支付统计") +@RestController +@RequestMapping("/statistics/pay") +@Validated +@Slf4j +public class PayStatisticsController { + + @Resource + private PayWalletStatisticsService payWalletStatisticsService; + + @GetMapping("/summary") + @Operation(summary = "获取充值金额") + public CommonResult getWalletRechargePrice() { + Integer rechargePrice = payWalletStatisticsService.getRechargePriceSummary(); + return success(PayStatisticsConvert.INSTANCE.convert(rechargePrice)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/vo/PaySummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/vo/PaySummaryRespVO.java new file mode 100644 index 0000000..01edc24 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/pay/vo/PaySummaryRespVO.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.pay.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 支付统计 Response VO") +@Data +public class PaySummaryRespVO { + + @Schema(description = "充值金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer rechargePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/ProductStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/ProductStatisticsController.java new file mode 100644 index 0000000..fd067b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/ProductStatisticsController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.product; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsReqVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.product.ProductStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.product.ProductStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag;import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 商品统计") +@RestController +@RequestMapping("/statistics/product") +@Validated +public class ProductStatisticsController { + + @Resource + private ProductStatisticsService productStatisticsService; + + @Resource + private ProductSpuApi productSpuApi; + + @GetMapping("/analyse") + @Operation(summary = "获得商品统计分析") + @PreAuthorize("@ss.hasPermission('statistics:product:query')") + public CommonResult> getProductStatisticsAnalyse(ProductStatisticsReqVO reqVO) { + return success(productStatisticsService.getProductStatisticsAnalyse(reqVO)); + } + + @GetMapping("/list") + @Operation(summary = "获得商品统计明细(日期维度)") + @PreAuthorize("@ss.hasPermission('statistics:product:query')") + public CommonResult> getProductStatisticsList(ProductStatisticsReqVO reqVO) { + List list = productStatisticsService.getProductStatisticsList(reqVO); + return success(BeanUtils.toBean(list, ProductStatisticsRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出获得商品统计明细 Excel(日期维度)") + @PreAuthorize("@ss.hasPermission('statistics:product:export')") + public void exportProductStatisticsExcel(ProductStatisticsReqVO reqVO, HttpServletResponse response) throws IOException { + List list = productStatisticsService.getProductStatisticsList(reqVO); + // 导出 Excel + List voList = BeanUtils.toBean(list, ProductStatisticsRespVO.class); + ExcelUtils.write(response, "商品状况.xls", "数据", ProductStatisticsRespVO.class, voList); + } + + @GetMapping("/rank-page") + @Operation(summary = "获得商品统计排行榜分页(商品维度)") + @PreAuthorize("@ss.hasPermission('statistics:product:query')") + public CommonResult> getProductStatisticsRankPage(@Valid ProductStatisticsReqVO reqVO, + @Valid SortablePageParam pageParam) { + PageResult pageResult = productStatisticsService.getProductStatisticsRankPage(reqVO, pageParam); + // 处理商品信息 + Set spuIds = convertSet(pageResult.getList(), ProductStatisticsDO::getSpuId); + Map spuMap = convertMap(productSpuApi.getSpuList(spuIds), ProductSpuRespDTO::getId); + return success(BeanUtils.toBean(pageResult, ProductStatisticsRespVO.class, + item -> Optional.ofNullable(spuMap.get(item.getSpuId())) + .ifPresent(spu -> item.setName(spu.getName()).setPicUrl(spu.getPicUrl())))); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsReqVO.java new file mode 100644 index 0000000..02387c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.product.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品统计分析 Request VO") +@Data +@ToString(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class ProductStatisticsReqVO { + + @Schema(description = "统计时间范围", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] times; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsRespVO.java new file mode 100644 index 0000000..9d93142 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/product/vo/ProductStatisticsRespVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.product.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - 商品统计 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ProductStatisticsRespVO { + + @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "12393") + private Long id; + + @Schema(description = "统计日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-12-16") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @ExcelProperty("统计日期") + private LocalDate time; + + @Schema(description = "商品SPU编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15114") + @ExcelProperty("商品SPU编号") + private Long spuId; + + // region 商品信息 + + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "商品名称") + @ExcelProperty("商品名称") + private String name; + + @Schema(description = "商品封面图", requiredMode = Schema.RequiredMode.REQUIRED, example = "15114") + @ExcelProperty("商品封面图") + private String picUrl; + + // endregion + + @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "17505") + @ExcelProperty("浏览量") + private Integer browseCount; + + @Schema(description = "访客量", requiredMode = Schema.RequiredMode.REQUIRED, example = "11814") + @ExcelProperty("访客量") + private Integer browseUserCount; + + @Schema(description = "收藏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20950") + @ExcelProperty("收藏数量") + private Integer favoriteCount; + + @Schema(description = "加购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "28493") + @ExcelProperty("加购数量") + private Integer cartCount; + + @Schema(description = "下单件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "18966") + @ExcelProperty("下单件数") + private Integer orderCount; + + @Schema(description = "支付件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "15142") + @ExcelProperty("支付件数") + private Integer orderPayCount; + + @Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "11595") + @ExcelProperty("支付金额,单位:分") + private Integer orderPayPrice; + + @Schema(description = "退款件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2591") + @ExcelProperty("退款件数") + private Integer afterSaleCount; + + @Schema(description = "退款金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "21709") + @ExcelProperty("退款金额,单位:分") + private Integer afterSaleRefundPrice; + + @Schema(description = "访客支付转化率(百分比)", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") + private Integer browseConvertPercent; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/TradeStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/TradeStatisticsController.java new file mode 100644 index 0000000..5aa88e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/TradeStatisticsController.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.*; +import cn.iocoder.yudao.module.statistics.convert.trade.TradeStatisticsConvert; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.trade.AfterSaleStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.BrokerageStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.TradeOrderStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.TradeStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 交易统计") +@RestController +@RequestMapping("/statistics/trade") +@Validated +@Slf4j +public class TradeStatisticsController { + + @Resource + private TradeStatisticsService tradeStatisticsService; + @Resource + private TradeOrderStatisticsService tradeOrderStatisticsService; + @Resource + private AfterSaleStatisticsService afterSaleStatisticsService; + @Resource + private BrokerageStatisticsService brokerageStatisticsService; + + @GetMapping("/summary") + @Operation(summary = "获得交易统计") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult> getTradeSummaryComparison() { + // 1.1 昨天的数据 + TradeSummaryRespBO yesterdayData = tradeStatisticsService.getTradeSummaryByDays(-1); + // 1.2 前天的数据(用于对照昨天的数据) + TradeSummaryRespBO beforeYesterdayData = tradeStatisticsService.getTradeSummaryByDays(-2); + + // 2.1 本月数据 + TradeSummaryRespBO monthData = tradeStatisticsService.getTradeSummaryByMonths(0); + // 2.2 上月数据(用于对照本月的数据) + TradeSummaryRespBO lastMonthData = tradeStatisticsService.getTradeSummaryByMonths(-1); + // 拼接数据 + return success(TradeStatisticsConvert.INSTANCE.convert(yesterdayData, beforeYesterdayData, monthData, lastMonthData)); + } + + @GetMapping("/analyse") + @Operation(summary = "获得交易状况统计") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult> getTradeStatisticsAnalyse(TradeTrendReqVO reqVO) { + return success(tradeStatisticsService.getTradeStatisticsAnalyse(ArrayUtil.get(reqVO.getTimes(), 0), + ArrayUtil.get(reqVO.getTimes(), 1))); + } + + @GetMapping("/list") + @Operation(summary = "获得交易状况明细") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult> getTradeStatisticsList(TradeTrendReqVO reqVO) { + List list = tradeStatisticsService.getTradeStatisticsList(ArrayUtil.get(reqVO.getTimes(), 0), + ArrayUtil.get(reqVO.getTimes(), 1)); + return success(TradeStatisticsConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出获得交易状况明细 Excel") + @PreAuthorize("@ss.hasPermission('statistics:trade:export')") + public void exportTradeStatisticsExcel(TradeTrendReqVO reqVO, HttpServletResponse response) throws IOException { + List list = tradeStatisticsService.getTradeStatisticsList(ArrayUtil.get(reqVO.getTimes(), 0), + ArrayUtil.get(reqVO.getTimes(), 1)); + // 导出 Excel + List voList = TradeStatisticsConvert.INSTANCE.convertList(list); + List data = TradeStatisticsConvert.INSTANCE.convertList02(voList); + ExcelUtils.write(response, "交易状况.xls", "数据", TradeTrendSummaryExcelVO.class, data); + } + + @GetMapping("/order-count") + @Operation(summary = "获得交易订单数量") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult getOrderCount() { + // 订单统计 + Long undeliveredCount = tradeOrderStatisticsService.getCountByStatusAndDeliveryType( + TradeOrderStatusEnum.UNDELIVERED.getStatus(), DeliveryTypeEnum.EXPRESS.getType()); + // TODO @疯狂:订单支付后,如果是门店自提的,需要 update 成 DELIVERED;;目前还没搞~~突然反应过来 + Long pickUpCount = tradeOrderStatisticsService.getCountByStatusAndDeliveryType( + TradeOrderStatusEnum.DELIVERED.getStatus(), DeliveryTypeEnum.PICK_UP.getType()); + // 售后统计 + Long afterSaleApplyCount = afterSaleStatisticsService.getCountByStatus(AfterSaleStatusEnum.APPLY); + Long auditingWithdrawCount = brokerageStatisticsService.getWithdrawCountByStatus(BrokerageWithdrawStatusEnum.AUDITING); + // 拼接返回 + return success(TradeStatisticsConvert.INSTANCE.convert(undeliveredCount, pickUpCount, afterSaleApplyCount, auditingWithdrawCount)); + } + + @GetMapping("/order-comparison") + @Operation(summary = "获得交易订单数量") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult> getOrderComparison() { + return success(tradeOrderStatisticsService.getOrderComparison()); + } + + @GetMapping("/order-count-trend") + @Operation(summary = "获得订单量趋势统计") + @PreAuthorize("@ss.hasPermission('statistics:trade:query')") + public CommonResult>> getOrderCountTrendComparison(@Valid TradeOrderTrendReqVO reqVO) { + // TODO @疯狂:要注意 date 的排序; + return success(tradeOrderStatisticsService.getOrderCountTrendComparison(reqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderCountRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderCountRespVO.java new file mode 100644 index 0000000..1320a88 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderCountRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 交易订单数量 Response VO") +@Data +public class TradeOrderCountRespVO { + + @Schema(description = "待发货", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long undelivered; + + @Schema(description = "待核销", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long pickUp; + + @Schema(description = "退款中", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long afterSaleApply; + + @Schema(description = "提现待审核", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long auditingWithdraw; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderSummaryRespVO.java new file mode 100644 index 0000000..22d8f4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderSummaryRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 交易订单统计 Response VO") +@Data +public class TradeOrderSummaryRespVO { + + @Schema(description = "支付订单商品数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderPayCount; + + @Schema(description = "总支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendReqVO.java new file mode 100644 index 0000000..57f0546 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.statistics.enums.TimeRangeTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 交易订单量趋势统计 Request VO") +@Data +public class TradeOrderTrendReqVO { + + @Schema(description = "日期范围类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "日期范围类型不能为空") + @InEnum(value = TimeRangeTypeEnum.class, message = "日期范围类型,必须是 {value}") + private Integer type; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "起始时间") + private LocalDateTime beginTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "截止时间") + private LocalDateTime endTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendRespVO.java new file mode 100644 index 0000000..d69c343 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeOrderTrendRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 订单量趋势统计 Response VO") +@Data +public class TradeOrderTrendRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String date; + + @Schema(description = "订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderPayCount; + + @Schema(description = "订单支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeSummaryRespVO.java new file mode 100644 index 0000000..5e0e7c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeSummaryRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 交易统计 Response VO") +@Data +public class TradeSummaryRespVO { + + @Schema(description = "昨日订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer yesterdayOrderCount; + @Schema(description = "昨日支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer yesterdayPayPrice; + + @Schema(description = "本月订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer monthOrderCount; + @Schema(description = "本月支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer monthPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendReqVO.java new file mode 100644 index 0000000..234b7a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 交易状况 Request VO") +@Data +public class TradeTrendReqVO { + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "时间范围") + private LocalDateTime[] times; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryExcelVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryExcelVO.java new file mode 100644 index 0000000..5b14fa1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryExcelVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import lombok.Data; + +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 交易状况统计 Excel VO + * + * @author owen + */ +@Data +public class TradeTrendSummaryExcelVO { + + @ExcelProperty(value = "日期") + @DateTimeFormat(FORMAT_YEAR_MONTH_DAY) + private LocalDate date; + + @ExcelProperty(value = "营业额", converter = MoneyConvert.class) + private Integer turnoverPrice; + + @ExcelProperty(value = "商品支付金额", converter = MoneyConvert.class) + private Integer orderPayPrice; + + @ExcelProperty(value = "充值金额", converter = MoneyConvert.class) + private Integer rechargePrice; + + @ExcelProperty(value = "支出金额", converter = MoneyConvert.class) + private Integer expensePrice; + + @ExcelProperty(value = "余额支付金额", converter = MoneyConvert.class) + private Integer walletPayPrice; + + @ExcelProperty(value = "支付佣金金额", converter = MoneyConvert.class) + private Integer brokerageSettlementPrice; + + @ExcelProperty(value = "商品退款金额", converter = MoneyConvert.class) + private Integer afterSaleRefundPrice; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryRespVO.java new file mode 100644 index 0000000..be5a93a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/trade/vo/TradeTrendSummaryRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.statistics.controller.admin.trade.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - 交易状况统计 Response VO") +@Data +public class TradeTrendSummaryRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-12-16") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate date; + + @Schema(description = "营业额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer turnoverPrice; // 营业额 = 商品支付金额 + 充值金额 + + @Schema(description = "订单支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer orderPayPrice; + + @Schema(description = "余额支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer walletPayPrice; + + @Schema(description = "订单退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer afterSaleRefundPrice; + + @Schema(description = "支付佣金金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer brokerageSettlementPrice; + + @Schema(description = "充值金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer rechargePrice; + + @Schema(description = "支出金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer expensePrice; // 余额支付金额 + 支付佣金金额 + 商品退款金额 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/app/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/app/package-info.java new file mode 100644 index 0000000..1384194 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:占位 + */ +package cn.iocoder.yudao.module.statistics.controller.app; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/member/MemberStatisticsConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/member/MemberStatisticsConvert.java new file mode 100644 index 0000000..2d527b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/member/MemberStatisticsConvert.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.statistics.convert.member; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberAnalyseDataRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberAnalyseRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberAreaStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberSummaryRespVO; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 会员统计 Convert + * + * @author owen + */ +@Mapper +public interface MemberStatisticsConvert { + + MemberStatisticsConvert INSTANCE = Mappers.getMapper(MemberStatisticsConvert.class); + + default List convertList(List areaList, + Map userCountMap, + Map orderMap) { + return CollectionUtils.convertList(areaList, area -> { + MemberAreaStatisticsRespBO orderVo = Optional.ofNullable(orderMap.get(area.getId())) + .orElseGet(MemberAreaStatisticsRespBO::new); + return new MemberAreaStatisticsRespVO() + .setAreaId(area.getId()).setAreaName(area.getName()) + .setUserCount(MapUtil.getInt(userCountMap, area.getId(), 0)) + .setOrderCreateUserCount(ObjUtil.defaultIfNull(orderVo.getOrderCreateUserCount(), 0)) + .setOrderPayUserCount(ObjUtil.defaultIfNull(orderVo.getOrderPayUserCount(), 0)) + .setOrderPayPrice(ObjUtil.defaultIfNull(orderVo.getOrderPayPrice(), 0)); + }); + } + + MemberSummaryRespVO convert(RechargeSummaryRespBO rechargeSummary, Integer expensePrice, Integer userCount); + + MemberAnalyseRespVO convert(Integer visitUserCount, Integer orderUserCount, Integer payUserCount, int atv, + DataComparisonRespVO comparison); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/pay/PayStatisticsConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/pay/PayStatisticsConvert.java new file mode 100644 index 0000000..08f3800 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/pay/PayStatisticsConvert.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.statistics.convert.pay; + +import cn.iocoder.yudao.module.statistics.controller.admin.pay.vo.PaySummaryRespVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 支付统计 Convert + * + * @author owen + */ +@Mapper +public interface PayStatisticsConvert { + + PayStatisticsConvert INSTANCE = Mappers.getMapper(PayStatisticsConvert.class); + + PaySummaryRespVO convert(Integer rechargePrice); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/trade/TradeStatisticsConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/trade/TradeStatisticsConvert.java new file mode 100644 index 0000000..7c14062 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/convert/trade/TradeStatisticsConvert.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.statistics.convert.trade; + +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderCountRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeSummaryRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryExcelVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeOrderSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; +import org.mapstruct.IterableMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 交易统计 Convert + * + * @author owen + */ +@Mapper +public interface TradeStatisticsConvert { + + TradeStatisticsConvert INSTANCE = Mappers.getMapper(TradeStatisticsConvert.class); + + default DataComparisonRespVO convert(TradeSummaryRespBO yesterdayData, + TradeSummaryRespBO beforeYesterdayData, + TradeSummaryRespBO monthData, + TradeSummaryRespBO lastMonthData) { + return convert(convert(yesterdayData, monthData), convert(beforeYesterdayData, lastMonthData)); + } + + + default TradeSummaryRespVO convert(TradeSummaryRespBO yesterdayData, TradeSummaryRespBO monthData) { + return new TradeSummaryRespVO() + .setYesterdayOrderCount(yesterdayData.getCount()).setYesterdayPayPrice(yesterdayData.getSummary()) + .setMonthOrderCount(monthData.getCount()).setMonthPayPrice(monthData.getSummary()); + } + + DataComparisonRespVO convert(TradeSummaryRespVO value, TradeSummaryRespVO reference); + + DataComparisonRespVO convert(TradeTrendSummaryRespVO value, + TradeTrendSummaryRespVO reference); + + List convertList02(List list); + + TradeStatisticsDO convert(LocalDateTime time, TradeOrderSummaryRespBO orderSummary, + AfterSaleSummaryRespBO afterSaleSummary, Integer brokerageSettlementPrice, + WalletSummaryRespBO walletSummary); + + @IterableMapping(qualifiedByName = "convert") + List convertList(List list); + + TradeTrendSummaryRespVO convertA(TradeStatisticsDO tradeStatistics); + + @Named("convert") + default TradeTrendSummaryRespVO convert(TradeStatisticsDO tradeStatistics) { + TradeTrendSummaryRespVO vo = convertA(tradeStatistics); + return vo + .setDate(tradeStatistics.getTime().toLocalDate()) + // 营业额 = 商品支付金额 + 充值金额 + .setTurnoverPrice(tradeStatistics.getOrderPayPrice() + tradeStatistics.getRechargePayPrice()) + // 支出金额 = 余额支付金额 + 支付佣金金额 + 商品退款金额 + .setExpensePrice(tradeStatistics.getWalletPayPrice() + tradeStatistics.getBrokerageSettlementPrice() + tradeStatistics.getAfterSaleRefundPrice()); + } + + TradeOrderCountRespVO convert(Long undelivered, Long pickUp, Long afterSaleApply, Long auditingWithdraw); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/package-info.java new file mode 100644 index 0000000..80eca3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 todo + */ +package cn.iocoder.yudao.module.statistics.dal.dataobject; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/product/ProductStatisticsDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/product/ProductStatisticsDO.java new file mode 100644 index 0000000..426906d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/product/ProductStatisticsDO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.statistics.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDate; + +/** + * 商品统计 DO + * + * @author owen + */ +@TableName("product_statistics") +@KeySequence("product_statistics_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductStatisticsDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + /** + * 统计日期 + */ + private LocalDate time; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 浏览量 + */ + private Integer browseCount; + /** + * 访客量 + */ + private Integer browseUserCount; + /** + * 收藏数量 + */ + private Integer favoriteCount; + /** + * 加购数量 + */ + private Integer cartCount; + /** + * 下单件数 + */ + private Integer orderCount; + /** + * 支付件数 + */ + private Integer orderPayCount; + /** + * 支付金额,单位:分 + */ + private Integer orderPayPrice; + /** + * 退款件数 + */ + private Integer afterSaleCount; + /** + * 退款金额,单位:分 + */ + private Integer afterSaleRefundPrice; + /** + * 访客支付转化率(百分比) + */ + private Integer browseConvertPercent; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/trade/TradeStatisticsDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/trade/TradeStatisticsDO.java new file mode 100644 index 0000000..46e148a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/trade/TradeStatisticsDO.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.statistics.dal.dataobject.trade; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 交易统计 DO + *

+ * 以天为维度,统计全部的数据 + * + * @author 芋道源码 + */ +@TableName("trade_statistics") +@KeySequence("trade_statistics_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TradeStatisticsDO extends BaseDO { + + /** + * 编号,主键自增 + */ + @TableId + private Long id; + + /** + * 统计日期 + */ + private LocalDateTime time; + + /** + * 创建订单数 + */ + private Integer orderCreateCount; + /** + * 支付订单商品数 + */ + private Integer orderPayCount; + /** + * 总支付金额,单位:分 + */ + private Integer orderPayPrice; + + /** + * 退款订单数 + */ + private Integer afterSaleCount; + /** + * 总退款金额,单位:分 + */ + private Integer afterSaleRefundPrice; + + /** + * 佣金金额(已结算),单位:分 + */ + private Integer brokerageSettlementPrice; + + /** + * 总支付金额(余额),单位:分 + */ + private Integer walletPayPrice; + /** + * 充值订单数 + *

+ * 从 PayWalletRechargeDO 计算 + */ + private Integer rechargePayCount; + /** + * 充值金额,单位:分 + */ + private Integer rechargePayPrice; + /** + * 充值退款订单数 + */ + private Integer rechargeRefundCount; + /** + * 充值退款金额,单位:分 + */ + private Integer rechargeRefundPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java new file mode 100644 index 0000000..5f76b58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.infra; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +// TODO @芋艿:api 访问日志,现在会清理,可能要单独有个偏业务的访问表; +/** + * API 访问日志的统计 Mapper + * + * @author owen + */ +@Mapper +@SuppressWarnings("rawtypes") +public interface ApiAccessLogStatisticsMapper extends BaseMapperX { + + Integer selectIpCountByUserTypeAndCreateTimeBetween(@Param("userType") Integer userType, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Integer selectUserCountByUserTypeAndCreateTimeBetween(@Param("userType") Integer userType, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java new file mode 100644 index 0000000..595e93d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.member; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberRegisterCountRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberSexStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberTerminalStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 会员信息的统计 Mapper + * + * @author owen + */ +@Mapper +@SuppressWarnings("rawtypes") +public interface MemberStatisticsMapper extends BaseMapperX { + + List selectSummaryListByAreaId(); + + List selectSummaryListBySex(); + + List selectSummaryListByRegisterTerminal(); + + Integer selectUserCount(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + /** + * 获得用户的每天注册数量列表 + * + * @param beginTime 开始时间 + * @param endTime 结束时间 + * @return 每天注册数量列表 + */ + List selectListByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java new file mode 100644 index 0000000..f2399f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.pay; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * 支付钱包的统计 Mapper + * + * @author owen + */ +@Mapper +@SuppressWarnings("rawtypes") +public interface PayWalletStatisticsMapper extends BaseMapperX { + + WalletSummaryRespBO selectRechargeSummaryByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime, + @Param("payStatus") Boolean payStatus); + + WalletSummaryRespBO selectRechargeSummaryByRefundTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime, + @Param("refundStatus") Integer refundStatus); + + Integer selectPriceSummaryByBizTypeAndCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime, + @Param("bizType") Integer bizType); + + RechargeSummaryRespBO selectRechargeSummaryGroupByWalletId(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime, + @Param("payStatus") Boolean payStatus); + + Integer selectRechargePriceSummary(@Param("payStatus") Boolean payStatus); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/product/ProductStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/product/ProductStatisticsMapper.java new file mode 100644 index 0000000..600296f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/product/ProductStatisticsMapper.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsReqVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.product.ProductStatisticsDO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 商品统计 Mapper + * + * @author owen + */ +@Mapper +public interface ProductStatisticsMapper extends BaseMapperX { + + default PageResult selectPageGroupBySpuId(ProductStatisticsReqVO reqVO, SortablePageParam pageParam) { + return selectPage(pageParam, buildWrapper(reqVO) + .groupBy(ProductStatisticsDO::getSpuId) + .select(ProductStatisticsDO::getSpuId) + ); + } + + default List selectListByTimeBetween(ProductStatisticsReqVO reqVO) { + return selectList(buildWrapper(reqVO) + .groupBy(ProductStatisticsDO::getTime) + .select(ProductStatisticsDO::getTime)); + } + + default ProductStatisticsRespVO selectVoByTimeBetween(ProductStatisticsReqVO reqVO) { + return selectJoinOne(ProductStatisticsRespVO.class, buildWrapper(reqVO)); + } + + /** + * 构建 LambdaWrapper + * + * @param reqVO 查询参数 + * @return LambdaWrapper + */ + static MPJLambdaWrapperX buildWrapper(ProductStatisticsReqVO reqVO) { + return new MPJLambdaWrapperX() + .betweenIfPresent(ProductStatisticsDO::getTime, reqVO.getTimes()) + .selectSum(ProductStatisticsDO::getBrowseCount) + .selectSum(ProductStatisticsDO::getBrowseUserCount) + .selectSum(ProductStatisticsDO::getFavoriteCount) + .selectSum(ProductStatisticsDO::getCartCount) + .selectSum(ProductStatisticsDO::getOrderCount) + .selectSum(ProductStatisticsDO::getOrderPayCount) + .selectSum(ProductStatisticsDO::getOrderPayPrice) + .selectSum(ProductStatisticsDO::getAfterSaleCount) + .selectSum(ProductStatisticsDO::getAfterSaleRefundPrice) + .selectAvg(ProductStatisticsDO::getBrowseConvertPercent); + } + + /** + * 根据时间范围统计商品信息 + * + * @param page 分页参数 + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 统计 + */ + IPage selectStatisticsResultPageByTimeBetween(IPage page, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + default Long selectCountByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) { + return selectCount(new LambdaQueryWrapperX().between(ProductStatisticsDO::getTime, beginTime, endTime)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java new file mode 100644 index 0000000..7de0cb0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.trade; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * 售后订单的统计 Mapper + * + * @author owen + */ +@Mapper +public interface AfterSaleStatisticsMapper extends BaseMapperX { + + AfterSaleSummaryRespBO selectSummaryByRefundTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Long selectCountByStatus(@Param("status") Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java new file mode 100644 index 0000000..94ad068 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.trade; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; + +/** + * 订单分销的统计 Mapper + * + * @author owen + */ +@Mapper +public interface BrokerageStatisticsMapper extends BaseMapperX { + + Integer selectSummaryPriceByStatusAndUnfreezeTimeBetween(@Param("bizType") Integer bizType, + @Param("status") Integer status, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Long selectWithdrawCountByStatus(@Param("status") Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java new file mode 100644 index 0000000..86b32df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.trade; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderSummaryRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderTrendRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 交易订单的统计 Mapper + * + * @author owen + */ +@Mapper +public interface TradeOrderStatisticsMapper extends BaseMapperX { + + List selectSummaryListByAreaId(); + + Integer selectCountByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Integer selectCountByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Integer selectSummaryPriceByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Integer selectUserCountByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Integer selectUserCountByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + /** + * 按照支付时间统计订单(按天分组) + * + * @param beginTime 支付起始时间 + * @param endTime 支付截止时间 + * @return 订单统计列表 + */ + List selectListByPayTimeBetweenAndGroupByDay(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + /** + * 按照支付时间统计订单(按月分组) + * + * @param beginTime 支付起始时间 + * @param endTime 支付截止时间 + * @return 订单统计列表 + */ + List selectListByPayTimeBetweenAndGroupByMonth(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + Long selectCountByStatusAndDeliveryType(@Param("status") Integer status, @Param("deliveryType") Integer deliveryType); + + TradeOrderSummaryRespVO selectPaySummaryByPayStatusAndPayTimeBetween(@Param("payStatus") Boolean payStatus, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java new file mode 100644 index 0000000..67d2d50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.statistics.dal.mysql.trade; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 交易统计 Mapper + * + * @author owen + */ +@Mapper +public interface TradeStatisticsMapper extends BaseMapperX { + + TradeSummaryRespBO selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + TradeTrendSummaryRespVO selectVoByTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + default List selectListByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) { + return selectList(new LambdaQueryWrapperX() + .between(TradeStatisticsDO::getTime, beginTime, endTime)); + } + + Integer selectExpensePriceByTimeBetween(@Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + default TradeStatisticsDO selectByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) { + return selectOne(new LambdaQueryWrapperX() + .between(TradeStatisticsDO::getTime, beginTime, endTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/package-info.java new file mode 100644 index 0000000..e8cf302 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿,占坑,无特殊含义 + */ +package cn.iocoder.yudao.module.statistics.job; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/product/ProductStatisticsJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/product/ProductStatisticsJob.java new file mode 100644 index 0000000..17eca18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/product/ProductStatisticsJob.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.statistics.job.product; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.statistics.service.product.ProductStatisticsService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +// TODO 芋艿:缺个 Job 的配置;等和 Product 一起配置 + +/** + * 商品统计 Job + * + * @author owen + */ +@Component +public class ProductStatisticsJob implements JobHandler { + + @Resource + private ProductStatisticsService productStatisticsService; + + /** + * 执行商品统计任务 + * + * @param param 要统计的天数,只能是正整数,1 代表昨日数据 + * @return 统计结果 + */ + @Override + @TenantJob + public String execute(String param) { + // 默认昨日 + param = ObjUtil.defaultIfBlank(param, "1"); + // 校验参数的合理性 + if (!NumberUtil.isInteger(param)) { + throw new RuntimeException("商品统计任务的参数只能为是正整数"); + } + Integer days = Convert.toInt(param, 0); + if (days < 1) { + throw new RuntimeException("商品统计任务的参数只能为是正整数"); + } + String result = productStatisticsService.statisticsProduct(days); + return StrUtil.format("商品统计:\n{}", result); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/trade/TradeStatisticsJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/trade/TradeStatisticsJob.java new file mode 100644 index 0000000..228f4d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/job/trade/TradeStatisticsJob.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.statistics.job.trade; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.statistics.service.trade.TradeStatisticsService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +// TODO 芋艿:缺个 Job 的配置;等和 Product 一起配置 +/** + * 交易统计 Job + * + * @author owen + */ +@Component +public class TradeStatisticsJob implements JobHandler { + + @Resource + private TradeStatisticsService tradeStatisticsService; + + /** + * 执行交易统计任务 + * + * @param param 要统计的天数,只能是正整数,1 代表昨日数据 + * @return 统计结果 + */ + @Override + @TenantJob + public String execute(String param) { + // 默认昨日 + param = ObjUtil.defaultIfBlank(param, "1"); + // 校验参数的合理性 + if (!NumberUtil.isInteger(param)) { + throw new RuntimeException("交易统计任务的参数只能为是正整数"); + } + Integer days = Convert.toInt(param, 0); + if (days < 1) { + throw new RuntimeException("交易统计任务的参数只能为是正整数"); + } + String result = tradeStatisticsService.statisticsTrade(days); + return StrUtil.format("交易统计:\n{}", result); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/package-info.java new file mode 100644 index 0000000..598e16c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/package-info.java @@ -0,0 +1,8 @@ +/** + * statistics 模块,主要实现统计相关功能。 + * 例如:统计商品、会员、交易等功能。 + * + * 1. Controller URL:以 /statistics/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 statistics_ 为后缀,方便在数据库中区分【特殊】 + */ +package cn.iocoder.yudao.module.statistics; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java new file mode 100644 index 0000000..6c200fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.statistics.service.infra; + +import java.time.LocalDateTime; + +/** + * API 访问日志的统计 Service 接口 + * + * @author owen + */ +public interface ApiAccessLogStatisticsService { + + /** + * 获取活跃用户数量 + * + * @param userType 用户类型 + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 活跃用户数量 + */ + Integer getUserCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取访问用户数量 + * + * @param userType 用户类型 + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 访问用户数量 + */ + Integer getIpCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsServiceImpl.java new file mode 100644 index 0000000..7ad62d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsServiceImpl.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.statistics.service.infra; + +import cn.iocoder.yudao.module.statistics.dal.mysql.infra.ApiAccessLogStatisticsMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +/** + * API 访问日志的统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class ApiAccessLogStatisticsServiceImpl implements ApiAccessLogStatisticsService { + + @Resource + private ApiAccessLogStatisticsMapper apiAccessLogStatisticsMapper; + + @Override + public Integer getUserCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime) { + return apiAccessLogStatisticsMapper.selectUserCountByUserTypeAndCreateTimeBetween(userType, beginTime, endTime); + } + + @Override + public Integer getIpCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime) { + return apiAccessLogStatisticsMapper.selectIpCountByUserTypeAndCreateTimeBetween(userType, beginTime, endTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java new file mode 100644 index 0000000..253cba6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.statistics.service.member; + +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 会员信息的统计 Service 接口 + * + * @author owen + */ +public interface MemberStatisticsService { + + /** + * 获取会员统计(实时统计) + * + * @return 会员统计 + */ + MemberSummaryRespVO getMemberSummary(); + + /** + * 获取会员分析对照数据 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 会员分析对照数据 + */ + DataComparisonRespVO getMemberAnalyseComparisonData(LocalDateTime beginTime, + LocalDateTime endTime); + + /** + * 按照省份,获得会员统计列表 + * + * @return 会员统计列表 + */ + List getMemberAreaStatisticsList(); + + /** + * 按照性别,获得会员统计列表 + * + * @return 会员统计列表 + */ + List getMemberSexStatisticsList(); + + /** + * 按照终端,获得会员统计列表 + * + * @return 会员统计列表 + */ + List getMemberTerminalStatisticsList(); + + /** + * 获取用户注册数量列表 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 注册数量列表 + */ + List getMemberRegisterCountList(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获得用户数量量统计对照 + * + * @return 用户数量量统计对照 + */ + DataComparisonRespVO getUserCountComparison(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsServiceImpl.java new file mode 100644 index 0000000..60e9b3c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsServiceImpl.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.statistics.service.member; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.*; +import cn.iocoder.yudao.module.statistics.convert.member.MemberStatisticsConvert; +import cn.iocoder.yudao.module.statistics.dal.mysql.member.MemberStatisticsMapper; +import cn.iocoder.yudao.module.statistics.service.infra.ApiAccessLogStatisticsService; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import cn.iocoder.yudao.module.statistics.service.pay.PayWalletStatisticsService; +import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.TradeOrderStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.TradeStatisticsService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 会员信息的统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberStatisticsServiceImpl implements MemberStatisticsService { + + @Resource + private MemberStatisticsMapper memberStatisticsMapper; + + @Resource + private PayWalletStatisticsService payWalletStatisticsService; + @Resource + private TradeStatisticsService tradeStatisticsService; + @Resource + private TradeOrderStatisticsService tradeOrderStatisticsService; + @Resource + private ApiAccessLogStatisticsService apiAccessLogStatisticsService; + + @Override + public MemberSummaryRespVO getMemberSummary() { + RechargeSummaryRespBO rechargeSummary = payWalletStatisticsService.getUserRechargeSummary(null, null); + // TODO @疯狂:1)这里是实时统计,不好走走 TradeStatistics 表;2)因为这个放在商城下,所以只考虑订单数据,即按照 trade_order 的 pay_price 并且已支付来计算; + Integer expensePrice = tradeStatisticsService.getExpensePrice(null, null); + Integer userCount = memberStatisticsMapper.selectUserCount(null, null); + return MemberStatisticsConvert.INSTANCE.convert(rechargeSummary, expensePrice, userCount); + } + + @Override + public List getMemberAreaStatisticsList() { + // 统计用户 + // TODO @疯狂:可能得把每个省的用户,都查询出来,然后去 order 那边 in;因为要按照这些人为基础来计算;;用户规模量大可能不太好,但是暂时就先这样搞吧 = = + Map userCountMap = convertMap(memberStatisticsMapper.selectSummaryListByAreaId(), + vo -> AreaUtils.getParentIdByType(vo.getAreaId(), AreaTypeEnum.PROVINCE), + MemberAreaStatisticsRespBO::getUserCount, Integer::sum); + // 统计订单 + Map orderMap = convertMap(tradeOrderStatisticsService.getSummaryListByAreaId(), + bo -> AreaUtils.getParentIdByType(bo.getAreaId(), AreaTypeEnum.PROVINCE), + bo -> bo, + (a, b) -> new MemberAreaStatisticsRespBO() + .setOrderCreateUserCount(a.getOrderCreateUserCount() + b.getOrderCreateUserCount()) + .setOrderPayUserCount(a.getOrderPayUserCount() + b.getOrderPayUserCount()) + .setOrderPayPrice(ObjUtil.defaultIfNull(a.getOrderPayPrice(), 0) + ObjUtil.defaultIfNull(b.getOrderPayPrice(), 0))); + // 拼接数据 + List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); + areaList.add(new Area().setId(null).setName("未知")); + return MemberStatisticsConvert.INSTANCE.convertList(areaList, userCountMap, orderMap); + } + + @Override + public DataComparisonRespVO getMemberAnalyseComparisonData(LocalDateTime beginTime, LocalDateTime endTime) { + // 当前数据 + MemberAnalyseDataRespVO vo = getMemberAnalyseData(beginTime, endTime); + // 对照数据 + LocalDateTime referenceEndDate = beginTime.minusDays(1); // 减少1天,防止出现时间重叠 + LocalDateTime referenceBeginDate = referenceEndDate.minus(Duration.between(beginTime, endTime)); + MemberAnalyseDataRespVO reference = getMemberAnalyseData( + LocalDateTimeUtil.beginOfDay(referenceBeginDate), LocalDateTimeUtil.endOfDay(referenceEndDate)); + return new DataComparisonRespVO<>(vo, reference); + } + + private MemberAnalyseDataRespVO getMemberAnalyseData(LocalDateTime beginTime, LocalDateTime endTime) { + Integer rechargeUserCount = Optional.ofNullable(payWalletStatisticsService.getUserRechargeSummary(beginTime, endTime)) + .map(RechargeSummaryRespBO::getRechargeUserCount).orElse(0); + return new MemberAnalyseDataRespVO() + .setRegisterUserCount(memberStatisticsMapper.selectUserCount(beginTime, endTime)) + .setVisitUserCount(apiAccessLogStatisticsService.getUserCount(UserTypeEnum.MEMBER.getValue(), beginTime, endTime)) + .setRechargeUserCount(rechargeUserCount); + } + + @Override + public List getMemberSexStatisticsList() { + return memberStatisticsMapper.selectSummaryListBySex(); + } + + @Override + public List getMemberTerminalStatisticsList() { + return memberStatisticsMapper.selectSummaryListByRegisterTerminal(); + } + + @Override + public List getMemberRegisterCountList(LocalDateTime beginTime, LocalDateTime endTime) { + return memberStatisticsMapper.selectListByCreateTimeBetween(beginTime, endTime); + } + + @Override + public DataComparisonRespVO getUserCountComparison() { + // 今日时间范围 + LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); + LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(beginOfToday); + // 昨日时间范围 + LocalDateTime beginOfYesterday = LocalDateTimeUtil.beginOfDay(beginOfToday.minusDays(1)); + LocalDateTime endOfYesterday = LocalDateTimeUtil.endOfDay(beginOfYesterday); + return new DataComparisonRespVO() + .setValue(getUserCount(beginOfToday, endOfToday)) + .setReference(getUserCount(beginOfYesterday, endOfYesterday)); + } + + private MemberCountRespVO getUserCount(LocalDateTime beginTime, LocalDateTime endTime) { + return new MemberCountRespVO() + .setRegisterUserCount(memberStatisticsMapper.selectUserCount(beginTime, endTime)) + .setVisitUserCount(apiAccessLogStatisticsService.getIpCount(UserTypeEnum.MEMBER.getValue(), beginTime, endTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/bo/MemberAreaStatisticsRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/bo/MemberAreaStatisticsRespBO.java new file mode 100644 index 0000000..6b2d9ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/bo/MemberAreaStatisticsRespBO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.statistics.service.member.bo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员地区统计 Response BO") +@Data +public class MemberAreaStatisticsRespBO { + + /** + * 省份编号 + */ + private Integer areaId; + /** + * 省份名称 + */ + private String areaName; + + /** + * 会员数量 + */ + private Integer userCount; + + /** + * 下单的会员数量 + */ + private Integer orderCreateUserCount; + /** + * 支付订单的会员数量 + */ + private Integer orderPayUserCount; + + /** + * 订单支付金额,单位:分 + */ + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java new file mode 100644 index 0000000..d43a576 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.statistics.service.pay; + +import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; + +import java.time.LocalDateTime; + +/** + * 钱包的统计 Service 接口 + * + * @author owen + */ +public interface PayWalletStatisticsService { + + /** + * 获取钱包统计 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 钱包统计 + */ + WalletSummaryRespBO getWalletSummary(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取钱包充值统计 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 钱包充值统计 + */ + RechargeSummaryRespBO getUserRechargeSummary(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取充值金额合计 + * + * @return 充值金额合计 + */ + Integer getRechargePriceSummary(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsServiceImpl.java new file mode 100644 index 0000000..994d986 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsServiceImpl.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.statistics.service.pay; + +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import cn.iocoder.yudao.module.statistics.dal.mysql.pay.PayWalletStatisticsMapper; +import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +/** + * 钱包的统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class PayWalletStatisticsServiceImpl implements PayWalletStatisticsService { + + @Resource + private PayWalletStatisticsMapper payWalletStatisticsMapper; + + @Override + public WalletSummaryRespBO getWalletSummary(LocalDateTime beginTime, LocalDateTime endTime) { + WalletSummaryRespBO paySummary = payWalletStatisticsMapper.selectRechargeSummaryByPayTimeBetween( + beginTime, endTime, true); + WalletSummaryRespBO refundSummary = payWalletStatisticsMapper.selectRechargeSummaryByRefundTimeBetween( + beginTime, endTime, PayRefundStatusEnum.SUCCESS.getStatus()); + Integer walletPayPrice = payWalletStatisticsMapper.selectPriceSummaryByBizTypeAndCreateTimeBetween( + beginTime, endTime, PayWalletBizTypeEnum.PAYMENT.getType()); + // 拼接 + paySummary.setWalletPayPrice(walletPayPrice) + .setRechargeRefundCount(refundSummary.getRechargeRefundCount()) + .setRechargeRefundPrice(refundSummary.getRechargeRefundPrice()); + return paySummary; + } + + @Override + public RechargeSummaryRespBO getUserRechargeSummary(LocalDateTime beginTime, LocalDateTime endTime) { + return payWalletStatisticsMapper.selectRechargeSummaryGroupByWalletId(beginTime, endTime, true); + } + + @Override + public Integer getRechargePriceSummary() { + return payWalletStatisticsMapper.selectRechargePriceSummary(Boolean.TRUE); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/bo/RechargeSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/bo/RechargeSummaryRespBO.java new file mode 100644 index 0000000..05cfa11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/bo/RechargeSummaryRespBO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.statistics.service.pay.bo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 充值统计 Response BO + */ +@Data +public class RechargeSummaryRespBO { + + /** + * 充值会员数量 + */ + private Integer rechargeUserCount; + + /** + * 充值金额 + */ + private Integer rechargePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsService.java new file mode 100644 index 0000000..09d84bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsService.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.statistics.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsReqVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.product.ProductStatisticsDO; + +import java.util.List; + +/** + * 商品统计 Service 接口 + * + * @author owen + */ +public interface ProductStatisticsService { + + /** + * 获得商品统计排行榜分页 + * + * @param reqVO 查询条件 + * @param pageParam 分页排序查询 + * @return 商品统计分页 + */ + PageResult getProductStatisticsRankPage(ProductStatisticsReqVO reqVO, SortablePageParam pageParam); + + /** + * 获得商品状况统计分析 + * + * @param reqVO 查询条件 + * @return 统计数据对照 + */ + DataComparisonRespVO getProductStatisticsAnalyse(ProductStatisticsReqVO reqVO); + + /** + * 获得商品状况明细 + * + * @param reqVO 查询条件 + * @return 统计数据对照 + */ + List getProductStatisticsList(ProductStatisticsReqVO reqVO); + + /** + * 统计指定天数的商品数据 + * + * @return 统计结果 + */ + String statisticsProduct(Integer days); + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsServiceImpl.java new file mode 100644 index 0000000..f56fc47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/product/ProductStatisticsServiceImpl.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.statistics.service.product; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsReqVO; +import cn.iocoder.yudao.module.statistics.controller.admin.product.vo.ProductStatisticsRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.product.ProductStatisticsDO; +import cn.iocoder.yudao.module.statistics.dal.mysql.product.ProductStatisticsMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + + +/** + * 商品统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class ProductStatisticsServiceImpl implements ProductStatisticsService { + + @Resource + private ProductStatisticsMapper productStatisticsMapper; + + + @Override + public PageResult getProductStatisticsRankPage(ProductStatisticsReqVO reqVO, SortablePageParam pageParam) { + PageUtils.buildDefaultSortingField(pageParam, ProductStatisticsDO::getBrowseCount); // 默认浏览量倒序 + return productStatisticsMapper.selectPageGroupBySpuId(reqVO, pageParam); + } + + @Override + public DataComparisonRespVO getProductStatisticsAnalyse(ProductStatisticsReqVO reqVO) { + LocalDateTime beginTime = ArrayUtil.get(reqVO.getTimes(), 0); + LocalDateTime endTime = ArrayUtil.get(reqVO.getTimes(), 1); + + // 统计数据 + ProductStatisticsRespVO value = productStatisticsMapper.selectVoByTimeBetween(reqVO); + // 对照数据 + LocalDateTime referenceBeginTime = beginTime.minus(Duration.between(beginTime, endTime)); + ProductStatisticsReqVO referenceReqVO = new ProductStatisticsReqVO(new LocalDateTime[]{referenceBeginTime, beginTime}); + ProductStatisticsRespVO reference = productStatisticsMapper.selectVoByTimeBetween(referenceReqVO); + return new DataComparisonRespVO<>(value, reference); + } + + @Override + public List getProductStatisticsList(ProductStatisticsReqVO reqVO) { + return productStatisticsMapper.selectListByTimeBetween(reqVO); + } + + @Override + public String statisticsProduct(Integer days) { + LocalDateTime today = LocalDateTime.now(); + return IntStream.rangeClosed(1, days) + .mapToObj(day -> statisticsProduct(today.minusDays(day))) + .sorted() + .collect(Collectors.joining("\n")); + } + + /** + * 统计商品数据 + * + * @param date 需要统计的日期 + * @return 统计结果 + */ + private String statisticsProduct(LocalDateTime date) { + // 1. 处理统计时间范围 + LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(date); + LocalDateTime endTime = LocalDateTimeUtil.endOfDay(date); + String dateStr = DatePattern.NORM_DATE_FORMATTER.format(date); + // 2. 检查该日是否已经统计过 + Long count = productStatisticsMapper.selectCountByTimeBetween(beginTime, endTime); + if (count != null && count > 0) { + return dateStr + " 数据已存在,如果需要重新统计,请先删除对应的数据"; + } + + StopWatch stopWatch = new StopWatch(dateStr); + stopWatch.start(); + // 4. 分页统计,避免商品表数据较多时,出现超时问题 + final int pageSize = 100; + for (int pageNo = 1; ; pageNo++) { + IPage page = productStatisticsMapper.selectStatisticsResultPageByTimeBetween( + Page.of(pageNo, pageSize, false), beginTime, endTime); + if (CollUtil.isEmpty(page.getRecords())) { + break; + } + // 4.1 计算访客支付转化率(百分比) + for (ProductStatisticsDO record : page.getRecords()) { + record.setTime(date.toLocalDate()); + if (record.getBrowseUserCount() != null && ObjUtil.notEqual(record.getBrowseUserCount(), 0)) { + record.setBrowseConvertPercent(100 * record.getOrderPayCount() / record.getBrowseUserCount()); + } + } + // 4.2 插入数据 + productStatisticsMapper.insertBatch(page.getRecords()); + } + return stopWatch.prettyPrint(); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java new file mode 100644 index 0000000..f584c3d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; + +import java.time.LocalDateTime; + +/** + * 售后统计 Service 接口 + * + * @author owen + */ +public interface AfterSaleStatisticsService { + + /** + * 获取售后单统计 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 售后统计结果 + */ + AfterSaleSummaryRespBO getAfterSaleSummary(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取指定状态的售后订单数量 + * + * @param status 售后状态 + * @return 售后订单数量 + */ + Long getCountByStatus(AfterSaleStatusEnum status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsServiceImpl.java new file mode 100644 index 0000000..46ab5f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsServiceImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.statistics.dal.mysql.trade.AfterSaleStatisticsMapper; +import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +/** + * 售后统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class AfterSaleStatisticsServiceImpl implements AfterSaleStatisticsService { + + @Resource + private AfterSaleStatisticsMapper afterSaleStatisticsMapper; + + @Override + public AfterSaleSummaryRespBO getAfterSaleSummary(LocalDateTime beginTime, LocalDateTime endTime) { + return afterSaleStatisticsMapper.selectSummaryByRefundTimeBetween(beginTime, endTime); + } + + @Override + public Long getCountByStatus(AfterSaleStatusEnum status) { + return afterSaleStatisticsMapper.selectCountByStatus(status.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java new file mode 100644 index 0000000..6845b60 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; + +import java.time.LocalDateTime; + +/** + * 分销统计 Service 接口 + * + * @author owen + */ +public interface BrokerageStatisticsService { + + /** + * 获取已结算的佣金金额 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 已结算的佣金金额 + */ + Integer getBrokerageSettlementPriceSummary(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取指定状态的提现记录数量 + * + * @param status 提现记录状态 + * @return 提现记录数量 + */ + Long getWithdrawCountByStatus(BrokerageWithdrawStatusEnum status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsServiceImpl.java new file mode 100644 index 0000000..d7af3d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsServiceImpl.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.statistics.dal.mysql.trade.BrokerageStatisticsMapper; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +/** + * 分销统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class BrokerageStatisticsServiceImpl implements BrokerageStatisticsService { + + @Resource + private BrokerageStatisticsMapper brokerageStatisticsMapper; + + @Override + public Integer getBrokerageSettlementPriceSummary(LocalDateTime beginTime, LocalDateTime endTime) { + return brokerageStatisticsMapper.selectSummaryPriceByStatusAndUnfreezeTimeBetween( + BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), + beginTime, endTime); + } + + @Override + public Long getWithdrawCountByStatus(BrokerageWithdrawStatusEnum status) { + return brokerageStatisticsMapper.selectWithdrawCountByStatus(status.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java new file mode 100644 index 0000000..2197515 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.*; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeOrderSummaryRespBO; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 交易订单的统计 Service 接口 + * + * @author owen + */ +public interface TradeOrderStatisticsService { + + /** + * 获取订单统计 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 订单统计结果 + */ + TradeOrderSummaryRespBO getOrderSummary(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取地区订单统计 + * + * @return 订单统计结果 + */ + List getSummaryListByAreaId(); + + /** + * 获取下单用户数量 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 下单用户数量 + */ + Integer getOrderUserCount(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取支付用户数量 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 支付用户数量 + */ + Integer getPayUserCount(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获取支付金额 + * + * @param beginTime 起始时间 + * @param endTime 截止时间 + * @return 支付用户金额 + */ + Integer getOrderPayPrice(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 根据订单状态、物流类型,获得交易订单数量 + * + * @return 订单数量 + */ + Long getCountByStatusAndDeliveryType(Integer status, Integer deliveryType); + + /** + * 交易订单销售额对照 + * + * @return 销售额对照 + */ + DataComparisonRespVO getOrderComparison(); + + /** + * 获得订单量趋势统计 + * + * @param reqVO 统计参数 + * @return 订单量趋势统计 + */ + List> getOrderCountTrendComparison(TradeOrderTrendReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsServiceImpl.java new file mode 100644 index 0000000..8ad81fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsServiceImpl.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderSummaryRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderTrendReqVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderTrendRespVO; +import cn.iocoder.yudao.module.statistics.dal.mysql.trade.TradeOrderStatisticsMapper; +import cn.iocoder.yudao.module.statistics.enums.TimeRangeTypeEnum; +import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeOrderSummaryRespBO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 交易订单统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class TradeOrderStatisticsServiceImpl implements TradeOrderStatisticsService { + + @Resource + private TradeOrderStatisticsMapper tradeOrderStatisticsMapper; + + @Override + public TradeOrderSummaryRespBO getOrderSummary(LocalDateTime beginTime, LocalDateTime endTime) { + return new TradeOrderSummaryRespBO() + .setOrderCreateCount(tradeOrderStatisticsMapper.selectCountByCreateTimeBetween(beginTime, endTime)) + .setOrderPayCount(tradeOrderStatisticsMapper.selectCountByPayTimeBetween(beginTime, endTime)) + .setOrderPayPrice(tradeOrderStatisticsMapper.selectSummaryPriceByPayTimeBetween(beginTime, endTime)); + } + + @Override + public List getSummaryListByAreaId() { + return tradeOrderStatisticsMapper.selectSummaryListByAreaId(); + } + + @Override + public Integer getOrderUserCount(LocalDateTime beginTime, LocalDateTime endTime) { + return tradeOrderStatisticsMapper.selectUserCountByCreateTimeBetween(beginTime, endTime); + } + + @Override + public Integer getPayUserCount(LocalDateTime beginTime, LocalDateTime endTime) { + return tradeOrderStatisticsMapper.selectUserCountByPayTimeBetween(beginTime, endTime); + } + + @Override + public Integer getOrderPayPrice(LocalDateTime beginTime, LocalDateTime endTime) { + return tradeOrderStatisticsMapper.selectSummaryPriceByPayTimeBetween(beginTime, endTime); + } + + @Override + public Long getCountByStatusAndDeliveryType(Integer status, Integer deliveryType) { + return tradeOrderStatisticsMapper.selectCountByStatusAndDeliveryType(status, deliveryType); + } + + @Override + public DataComparisonRespVO getOrderComparison() { + return new DataComparisonRespVO() + .setValue(getPayPriceSummary(LocalDateTime.now())) + .setReference(getPayPriceSummary(LocalDateTime.now().minusDays(1))); + } + + private TradeOrderSummaryRespVO getPayPriceSummary(LocalDateTime date) { + LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(date); + LocalDateTime endTime = LocalDateTimeUtil.endOfDay(date); + return tradeOrderStatisticsMapper.selectPaySummaryByPayStatusAndPayTimeBetween( + Boolean.TRUE, beginTime, endTime); + } + + @Override + public List> getOrderCountTrendComparison(TradeOrderTrendReqVO reqVO) { + // 查询当前数据 + List value = getOrderCountTrend(reqVO.getType(), reqVO.getBeginTime(), reqVO.getEndTime()); + // 查询对照数据 + LocalDateTime referenceEndTime = reqVO.getBeginTime().minusDays(1); + LocalDateTime referenceBeginTime = referenceEndTime.minus(Duration.between(reqVO.getBeginTime(), reqVO.getEndTime())); + List reference = getOrderCountTrend(reqVO.getType(), referenceBeginTime, referenceEndTime); + // 顺序对比返回 + return IntStream.range(0, value.size()) + .mapToObj(index -> new DataComparisonRespVO() + .setValue(CollUtil.get(value, index)) + .setReference(CollUtil.get(reference, index))) + .collect(Collectors.toList()); + } + + private List getOrderCountTrend(Integer timeRangeType, LocalDateTime beginTime, LocalDateTime endTime) { + // 情况一:按年统计时,以月份分组 + if (TimeRangeTypeEnum.YEAR.getType().equals(timeRangeType)) { + return tradeOrderStatisticsMapper.selectListByPayTimeBetweenAndGroupByMonth(beginTime, endTime); + } + // 情况二:其它以天分组(天、周、月) + return tradeOrderStatisticsMapper.selectListByPayTimeBetweenAndGroupByDay(beginTime, endTime); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java new file mode 100644 index 0000000..e175985 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 交易统计 Service 接口 + * + * @author owen + */ +public interface TradeStatisticsService { + + /** + * 获得交易状况统计对照 + * + * @return 统计数据对照 + */ + DataComparisonRespVO getTradeStatisticsAnalyse( + LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获得交易状况统计 + * + * @param beginTime 开始时间 + * @param endTime 结束时间 + * @return 统计数据对照 + */ + Integer getExpensePrice(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获得交易状况明细 + * + * @param beginTime 开始时间 + * @param endTime 结束时间 + * @return 统计数据列表 + */ + List getTradeStatisticsList(LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 统计指定天数的交易数据 + * + * @return 统计结果 + */ + String statisticsTrade(Integer days); + + /** + * 统计指定日期的交易数据 + * + * @param days 增加的天数 + * @return 交易数据 + */ + TradeSummaryRespBO getTradeSummaryByDays(int days); + + /** + * 统计指定月份的交易数据 + * + * @param months 增加的月数 + * @return 交易数据 + */ + TradeSummaryRespBO getTradeSummaryByMonths(int months); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsServiceImpl.java new file mode 100644 index 0000000..5c608bd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsServiceImpl.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.statistics.service.trade; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; +import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; +import cn.iocoder.yudao.module.statistics.convert.trade.TradeStatisticsConvert; +import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; +import cn.iocoder.yudao.module.statistics.dal.mysql.trade.TradeStatisticsMapper; +import cn.iocoder.yudao.module.statistics.service.pay.PayWalletStatisticsService; +import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeOrderSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; +import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; +import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 交易统计 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class TradeStatisticsServiceImpl implements TradeStatisticsService { + + @Resource + private TradeStatisticsMapper tradeStatisticsMapper; + + @Resource + private TradeOrderStatisticsService tradeOrderStatisticsService; + @Resource + private AfterSaleStatisticsService afterSaleStatisticsService; + @Resource + private BrokerageStatisticsService brokerageStatisticsService; + @Resource + private PayWalletStatisticsService payWalletStatisticsService; + + @Override + public TradeSummaryRespBO getTradeSummaryByDays(int days) { + LocalDateTime date = LocalDateTime.now().plusDays(days); + return tradeStatisticsMapper.selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween( + LocalDateTimeUtil.beginOfDay(date), LocalDateTimeUtil.endOfDay(date)); + } + + @Override + public TradeSummaryRespBO getTradeSummaryByMonths(int months) { + LocalDateTime monthDate = LocalDateTime.now().plusMonths(months); + return tradeStatisticsMapper.selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween( + LocalDateTimeUtils.beginOfMonth(monthDate), LocalDateTimeUtils.endOfMonth(monthDate)); + } + + @Override + public DataComparisonRespVO getTradeStatisticsAnalyse(LocalDateTime beginTime, + LocalDateTime endTime) { + // 统计数据 + TradeTrendSummaryRespVO value = tradeStatisticsMapper.selectVoByTimeBetween(beginTime, endTime); + // 对照数据 + LocalDateTime referenceBeginTime = beginTime.minus(Duration.between(beginTime, endTime)); + TradeTrendSummaryRespVO reference = tradeStatisticsMapper.selectVoByTimeBetween(referenceBeginTime, beginTime); + return TradeStatisticsConvert.INSTANCE.convert(value, reference); + } + + @Override + public Integer getExpensePrice(LocalDateTime beginTime, LocalDateTime endTime) { + return tradeStatisticsMapper.selectExpensePriceByTimeBetween(beginTime, endTime); + } + + @Override + public List getTradeStatisticsList(LocalDateTime beginTime, LocalDateTime endTime) { + return tradeStatisticsMapper.selectListByTimeBetween(beginTime, endTime); + } + + @Override + public String statisticsTrade(Integer days) { + LocalDateTime today = LocalDateTime.now(); + return IntStream.rangeClosed(1, days) + .mapToObj(day -> statisticsTrade(today.minusDays(day))) + .sorted() + .collect(Collectors.joining("\n")); + } + + /** + * 统计交易数据 + * + * @param date 需要统计的日期 + * @return 统计结果 + */ + private String statisticsTrade(LocalDateTime date) { + // 1. 处理统计时间范围 + LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(date); + LocalDateTime endTime = LocalDateTimeUtil.endOfDay(date); + String dateStr = DatePattern.NORM_DATE_FORMATTER.format(date); + // 2. 检查该日是否已经统计过 + TradeStatisticsDO entity = tradeStatisticsMapper.selectByTimeBetween(beginTime, endTime); + if (entity != null) { + return dateStr + " 数据已存在,如果需要重新统计,请先删除对应的数据"; + } + + // 3. 从各个数据表,统计对应数据 + StopWatch stopWatch = new StopWatch(dateStr); + // 3.1 统计订单 + stopWatch.start("统计订单"); + TradeOrderSummaryRespBO orderSummary = tradeOrderStatisticsService.getOrderSummary(beginTime, endTime); + stopWatch.stop(); + // 3.2 统计售后 + stopWatch.start("统计售后"); + AfterSaleSummaryRespBO afterSaleSummary = afterSaleStatisticsService.getAfterSaleSummary(beginTime, endTime); + stopWatch.stop(); + // 3.3 统计佣金 + stopWatch.start("统计佣金"); + Integer brokerageSettlementPrice = brokerageStatisticsService.getBrokerageSettlementPriceSummary(beginTime, endTime); + stopWatch.stop(); + // 3.4 统计充值 + stopWatch.start("统计充值"); + WalletSummaryRespBO walletSummary = payWalletStatisticsService.getWalletSummary(beginTime, endTime); + stopWatch.stop(); + + // 4. 插入数据 + entity = TradeStatisticsConvert.INSTANCE.convert(date, orderSummary, afterSaleSummary, brokerageSettlementPrice, + walletSummary); + tradeStatisticsMapper.insert(entity); + return stopWatch.prettyPrint(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/AfterSaleSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/AfterSaleSummaryRespBO.java new file mode 100644 index 0000000..9856436 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/AfterSaleSummaryRespBO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.statistics.service.trade.bo; + +import lombok.Data; + +/** + * 售后统计 Response DTO + * + * @author owen + */ +@Data +public class AfterSaleSummaryRespBO { + + /** + * 退款订单数 + */ + private Integer afterSaleCount; + /** + * 总退款金额,单位:分 + */ + private Integer afterSaleRefundPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/MemberAreaStatisticsRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/MemberAreaStatisticsRespBO.java new file mode 100644 index 0000000..3d3572f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/MemberAreaStatisticsRespBO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.statistics.service.trade.bo; + +import lombok.Data; + +/** + * 会员地区统计 Response BO + * + * @author owen + */ +@Data +public class MemberAreaStatisticsRespBO { + + /** + * 省份编号 + */ + private Integer areaId; + /** + * 省份名称 + */ + private String areaName; + + /** + * 会员数量 + */ + private Integer userCount; + + /** + * 下单的会员数量 + */ + private Integer orderCreateUserCount; + /** + * 支付订单的会员数量 + */ + private Integer orderPayUserCount; + + /** + * 订单支付金额,单位:分 + */ + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeOrderSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeOrderSummaryRespBO.java new file mode 100644 index 0000000..bc4f390 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeOrderSummaryRespBO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.statistics.service.trade.bo; + +import lombok.Data; + +/** + * 订单统计 Response BO + * + * @author owen + */ +@Data +public class TradeOrderSummaryRespBO { + + /** + * 创建订单数 + */ + private Integer orderCreateCount; + /** + * 支付订单商品数 + */ + private Integer orderPayCount; + /** + * 总支付金额,单位:分 + */ + private Integer orderPayPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeSummaryRespBO.java new file mode 100644 index 0000000..8937c80 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/TradeSummaryRespBO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.statistics.service.trade.bo; + +import lombok.Data; + +/** + * 交易统计 Resp BO + * + * @author owen + */ +@Data +public class TradeSummaryRespBO { + + /** + * 数量 + */ + private Integer count; + + /** + * 合计 + */ + private Integer summary; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/WalletSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/WalletSummaryRespBO.java new file mode 100644 index 0000000..89371f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/bo/WalletSummaryRespBO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.statistics.service.trade.bo; + +import lombok.Data; + +/** + * 钱包统计 Response DTO + * + * @author owen + */ +@Data +public class WalletSummaryRespBO { + + /** + * 总支付金额(余额),单位:分 + */ + private Integer walletPayPrice; + + /** + * 充值订单数 + */ + private Integer rechargePayCount; + /** + * 充值金额,单位:分 + */ + private Integer rechargePayPrice; + /** + * 充值退款订单数 + */ + private Integer rechargeRefundCount; + /** + * 充值退款金额,单位:分 + */ + private Integer rechargeRefundPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/infra/ApiAccessLogStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/infra/ApiAccessLogStatisticsMapper.xml new file mode 100644 index 0000000..e641615 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/infra/ApiAccessLogStatisticsMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/member/MemberStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/member/MemberStatisticsMapper.xml new file mode 100644 index 0000000..33500fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/member/MemberStatisticsMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/pay/PayWalletStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/pay/PayWalletStatisticsMapper.xml new file mode 100644 index 0000000..0977808 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/pay/PayWalletStatisticsMapper.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/product/ProductStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/product/ProductStatisticsMapper.xml new file mode 100644 index 0000000..e640d1d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/product/ProductStatisticsMapper.xml @@ -0,0 +1,64 @@ + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/AfterSaleStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/AfterSaleStatisticsMapper.xml new file mode 100644 index 0000000..933c456 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/AfterSaleStatisticsMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/BrokerageStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/BrokerageStatisticsMapper.xml new file mode 100644 index 0000000..dff7e44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/BrokerageStatisticsMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeOrderStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeOrderStatisticsMapper.xml new file mode 100644 index 0000000..07d2f0d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeOrderStatisticsMapper.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeStatisticsMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeStatisticsMapper.xml new file mode 100644 index 0000000..2415f6d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-statistics-biz/src/main/resources/mapper/trade/TradeStatisticsMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/pom.xml new file mode 100644 index 0000000..6dd926b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-trade-api + jar + + ${project.artifactId} + + trade 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java new file mode 100644 index 0000000..744a7b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.trade.api.order; + +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 订单 API 接口 + * + * @author HUIHUI + */ +public interface TradeOrderApi { + + /** + * 获得订单列表 + * + * @param ids 订单编号数组 + * @return 订单列表 + */ + List getOrderList(Collection ids); + + /** + * 获得订单 + * + * @param id 订单编号 + * @return 订单 + */ + TradeOrderRespDTO getOrder(Long id); + + // TODO 芋艿:需要优化下; + /** + * 取消支付订单 + * + * @param userId 用户编号 + * @param orderId 订单编号 + */ + void cancelPaidOrder(Long userId, Long orderId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java new file mode 100644 index 0000000..52b167c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.trade.api.order.dto; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 订单信息 Response DTO + * + * @author HUIHUI + */ +@Data +public class TradeOrderRespDTO { + + // ========== 订单基本信息 ========== + /** + * 订单编号,主键自增 + */ + private Long id; + /** + * 订单流水号 + * + * 例如说,1146347329394184195 + */ + private String no; + /** + * 订单类型 + * + * 枚举 {@link TradeOrderTypeEnum} + */ + private Integer type; + /** + * 订单来源 + * + * 枚举 {@link TerminalEnum} + */ + private Integer terminal; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户 IP + */ + private String userIp; + /** + * 用户备注 + */ + private String userRemark; + /** + * 订单状态 + * + * 枚举 {@link TradeOrderStatusEnum} + */ + private Integer status; + /** + * 购买的商品数量 + */ + private Integer productCount; + /** + * 订单完成时间 + */ + private LocalDateTime finishTime; + /** + * 订单取消时间 + */ + private LocalDateTime cancelTime; + /** + * 取消类型 + * + * 枚举 {@link TradeOrderCancelTypeEnum} + */ + private Integer cancelType; + /** + * 商家备注 + */ + private String remark; + /** + * 是否评价 + */ + private Boolean commentStatus; + + // ========== 价格 + 支付基本信息 ========== + /** + * 支付订单编号 + */ + private Long payOrderId; + /** + * 是否已支付 + */ + private Boolean payStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java new file mode 100644 index 0000000..5b0e37d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.trade.api; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/DictTypeConstants.java new file mode 100644 index 0000000..ff09e59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/DictTypeConstants.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.trade.enums; + +/** + * Trade 字典类型的枚举类 + * + * @author owen + */ +public interface DictTypeConstants { + + String BROKERAGE_WITHDRAW_STATUS = "brokerage_withdraw_status"; // 佣金提现状态 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..33081d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.trade.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Trade 错误码枚举类 + * trade 系统,使用 1-011-000-000 段 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +public interface ErrorCodeConstants { + + // ========== Order 模块 1-011-000-000 ========== + ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1_011_000_010, "交易订单项不存在"); + ErrorCode ORDER_NOT_FOUND = new ErrorCode(1_011_000_011, "交易订单不存在"); + ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1_011_000_012, "交易订单项更新售后状态失败,请重试"); + ErrorCode ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_011_000_013, "交易订单更新支付状态失败,订单不是【未支付】状态"); + ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1_011_000_014, "交易订单更新支付状态失败,支付单编号不匹配"); + ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1_011_000_015, "交易订单更新支付状态失败,支付单状态不是【支付成功】状态"); + ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1_011_000_016, "交易订单更新支付状态失败,支付单金额不匹配"); + ErrorCode ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED = new ErrorCode(1_011_000_017, "交易订单发货失败,订单不是【待发货】状态"); + ErrorCode ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1_011_000_018, "交易订单收货失败,订单不是【待收货】状态"); + ErrorCode ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED = new ErrorCode(1_011_000_019, "创建交易订单项的评价失败,订单不是【已完成】状态"); + ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(1_011_000_020, "创建交易订单项的评价失败,订单已评价"); + ErrorCode ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE = new ErrorCode(1_011_000_021, "交易订单发货失败,订单已退款或部分退款"); + ErrorCode ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1_011_000_022, "交易订单发货失败,拼团未成功"); + ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1_011_000_023, "交易订单发货失败,砍价未成功"); + ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1_011_000_024, "交易订单发货失败,发货类型不是快递"); + ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1_011_000_025, "交易订单取消失败,订单不是【待支付】状态"); + ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1_011_000_026, "支付订单调价失败,原因:支付订单已付款,不能调价"); + ErrorCode ORDER_UPDATE_PRICE_FAIL_ALREADY = new ErrorCode(1_011_000_027, "支付订单调价失败,原因:已经修改过价格"); + ErrorCode ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR = new ErrorCode(1_011_000_028, "支付订单调价失败,原因:调整后支付价格不能小于 0.01 元"); + ErrorCode ORDER_DELETE_FAIL_STATUS_NOT_CANCEL = new ErrorCode(1_011_000_029, "交易订单删除失败,订单不是【已取消】状态"); + ErrorCode ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP = new ErrorCode(1_011_000_030, "交易订单自提失败,收货方式不是【用户自提】"); + ErrorCode ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1_011_000_031, "交易订单修改收货地址失败,原因:订单不是【待发货】状态"); + ErrorCode ORDER_CREATE_FAIL_EXIST_UNPAID = new ErrorCode(1_011_000_032, "交易订单创建失败,原因:存在未付款订单"); + + // ========== After Sale 模块 1-011-000-100 ========== + ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1_011_000_100, "售后单不存在"); + ErrorCode AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR = new ErrorCode(1_011_000_101, "申请退款金额错误"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED = new ErrorCode(1_011_000_102, "订单已关闭,无法申请售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1_011_000_103, "订单未支付,无法申请售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1_011_000_104, "订单未发货,无法申请【退货退款】售后"); + ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1_011_000_105, "订单项已申请售后,无法重复申请"); + ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1_011_000_106, "审批失败,售后状态不处于审批中"); + ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1_011_000_107, "操作售后单失败,请刷新后重试"); + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1_011_000_108, "退货失败,售后单状态不处于【待买家退货】"); + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1_011_000_109, "确认收货失败,售后单状态不处于【待确认收货】"); + ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1_011_000_110, "退款失败,售后单状态不是【待退款】"); + ErrorCode AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY = + new ErrorCode(1_011_000_111, "取消售后单失败,售后单状态不是【待审核】或【卖家同意】或【商家待收货】"); + + // ========== Cart 模块 1-011-002-000 ========== + ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1_011_002_000, "购物车项不存在"); + + // ========== Price 相关 1-011-003-000 ============ + ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); + ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); + ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); + + // ========== 物流 Express 模块 1-011-004-000 ========== + ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); + ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1_011_004_001, "已经存在该编码的快递公司"); + ErrorCode EXPRESS_CLIENT_NOT_PROVIDE = new ErrorCode(1_011_004_002, "需要接入快递服务商,比如【快递100】"); + ErrorCode EXPRESS_STATUS_NOT_ENABLE = new ErrorCode(1_011_004_003, "快递公司未启用"); + + ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1_011_004_101, "快递查询接口异常"); + ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1_011_004_102, "快递查询返回失败,原因:{}"); + + // ========== 物流 Template 模块 1-011-005-000 ========== + ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1_011_005_000, "已经存在该运费模板名"); + ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_011_005_001, "运费模板不存在"); + + // ========== 物流 PICK_UP 模块 1-011-006-000 ========== + ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1_011_006_000, "自提门店不存在"); + + // ========== 分销用户 模块 1-011-007-000 ========== + ErrorCode BROKERAGE_USER_NOT_EXISTS = new ErrorCode(1_011_007_000, "分销用户不存在"); + ErrorCode BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH = new ErrorCode(1_011_007_001, "用户冻结佣金({})数量不足"); + ErrorCode BROKERAGE_BIND_SELF = new ErrorCode(1_011_007_002, "不能绑定自己"); + ErrorCode BROKERAGE_BIND_USER_NOT_ENABLED = new ErrorCode(1_011_007_003, "绑定用户没有推广资格"); + ErrorCode BROKERAGE_BIND_CONDITION_ADMIN = new ErrorCode(1_011_007_004, "仅可在后台绑定推广员"); + ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1_011_007_005, "只有在注册时可以绑定"); + ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1_011_007_006, "已绑定了推广人"); + ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1_011_007_007, "下级不能绑定自己的上级"); + ErrorCode BROKERAGE_USER_LEVEL_NOT_SUPPORT = new ErrorCode(1_011_007_008, "目前只支持 level 小于等于 2"); + + // ========== 分销提现 模块 1-011-008-000 ========== + ErrorCode BROKERAGE_WITHDRAW_NOT_EXISTS = new ErrorCode(1_011_008_000, "佣金提现记录不存在"); + ErrorCode BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING = new ErrorCode(1_011_008_001, "佣金提现记录状态不是审核中"); + ErrorCode BROKERAGE_WITHDRAW_MIN_PRICE = new ErrorCode(1_011_008_002, "提现金额不能低于 {} 元"); + ErrorCode BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH = new ErrorCode(1_011_008_003, "您当前最多可提现 {} 元"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java new file mode 100644 index 0000000..5041139 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.trade.enums; + +// TODO @芋艿:枚举 +/** + * 通知模板枚举类 + * + * @author HUIHUI + */ +public interface MessageTemplateConstants { + + String ORDER_DELIVERY = "order_delivery"; // 短信模版编号 + + String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过) + String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过) + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java new file mode 100644 index 0000000..db870c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 售后操作类型的枚举 + * + * @author 陈賝 + * @since 2023/6/13 13:53 + */ +@RequiredArgsConstructor +@Getter +public enum AfterSaleOperateTypeEnum { + + MEMBER_CREATE(10, "会员申请退款"), + ADMIN_AGREE_APPLY(11, "商家同意退款"), + ADMIN_DISAGREE_APPLY(12, "商家拒绝退款"), + MEMBER_DELIVERY(20, "会员填写退货物流信息,快递公司:{deliveryName},快递单号:{logisticsNo}"), + ADMIN_AGREE_RECEIVE(21, "商家收货"), + ADMIN_DISAGREE_RECEIVE(22, "商家拒绝收货,原因:{reason}"), + ADMIN_REFUND(30, "商家退款"), + MEMBER_CANCEL(40, "会员取消退款"), + ; + + /** + * 操作类型 + */ + private final Integer type; + /** + * 操作描述 + */ + private final String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleStatusEnum.java new file mode 100644 index 0000000..23c1b2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleStatusEnum.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Collection; + +import static cn.hutool.core.util.ArrayUtil.firstMatch; + +/** + * 售后状态的枚举 + * + * 状态流转 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum AfterSaleStatusEnum implements IntArrayValuable { + + /** + * 【申请售后】 + */ + APPLY(10,"申请中", "会员申请退款"), // 有赞的状态提示:退款申请待商家处理 + /** + * 卖家通过售后;【商品待退货】 + */ + SELLER_AGREE(20, "卖家通过", "商家同意退款"), // 有赞的状态提示:请退货并填写物流信息 + /** + * 买家已退货,等待卖家收货;【商家待收货】 + */ + BUYER_DELIVERY(30,"待卖家收货", "会员填写退货物流信息"), // 有赞的状态提示:退货退款申请待商家处理 + /** + * 卖家已收货,等待平台退款;等待退款【等待退款】 + */ + WAIT_REFUND(40, "等待平台退款", "商家收货"), // 有赞的状态提示:无(有赞无该状态) + /** + * 完成退款【退款成功】 + */ + COMPLETE(50, "完成", "商家确认退款"), // 有赞的状态提示:退款成功 + /** + * 【买家取消】 + */ + BUYER_CANCEL(61, "买家取消售后", "会员取消退款"), // 有赞的状态提示:退款关闭 + /** + * 卖家拒绝售后;商家拒绝【商家拒绝】 + */ + SELLER_DISAGREE(62,"卖家拒绝", "商家拒绝退款"), // 有赞的状态提示:商家不同意退款申请 + /** + * 卖家拒绝收货,终止售后;【商家拒收货】 + */ + SELLER_REFUSE(63,"卖家拒绝收货", "商家拒绝收货"), // 有赞的状态提示:商家拒绝收货,不同意退款 + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleStatusEnum::getStatus).toArray(); + + /** + * 进行中的售后状态 + * + * 不包括已经结束的状态 + */ + public static final Collection APPLYING_STATUSES = Arrays.asList( + APPLY.getStatus(), + SELLER_AGREE.getStatus(), + BUYER_DELIVERY.getStatus(), + WAIT_REFUND.getStatus() + ); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + /** + * 操作内容 + * + * 目的:记录售后日志的内容 + */ + private final String content; + + @Override + public int[] array() { + return ARRAYS; + } + + public static AfterSaleStatusEnum valueOf(Integer status) { + return firstMatch(value -> value.getStatus().equals(status), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleTypeEnum.java new file mode 100644 index 0000000..dfb32f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleTypeEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易售后 - 类型 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum AfterSaleTypeEnum implements IntArrayValuable { + + IN_SALE(10, "售中退款"), // 交易完成前买家申请退款 + AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款 + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleWayEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleWayEnum.java new file mode 100644 index 0000000..1d608a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleWayEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.enums.aftersale; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易售后 - 方式 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum AfterSaleWayEnum implements IntArrayValuable { + + REFUND(10, "仅退款"), + RETURN_AND_REFUND(20, "退货退款"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AfterSaleWayEnum::getWay).toArray(); + + /** + * 方式 + */ + private final Integer way; + /** + * 方式名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java new file mode 100644 index 0000000..72ce100 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageBindModeEnum.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 分销关系绑定模式枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageBindModeEnum implements IntArrayValuable { + + /** + * 只要用户没有推广人,随时都可以绑定分销关系 + */ + ANYTIME(1, "首次绑定"), + /** + * 仅新用户注册时才能绑定推广关系 + */ + REGISTER(2, "注册绑定"), + /** + * 每次扫码都覆盖 + */ + OVERRIDE(3, "覆盖绑定"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageBindModeEnum::getMode).toArray(); + + /** + * 模式 + */ + private final Integer mode; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageEnabledConditionEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageEnabledConditionEnum.java new file mode 100644 index 0000000..990d10e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageEnabledConditionEnum.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 分佣模式枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageEnabledConditionEnum implements IntArrayValuable { + + /** + * 所有用户都可以分销 + */ + ALL(1, "人人分销"), + /** + * 仅可后台手动设置推广员 + */ + ADMIN(2, "指定分销"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageEnabledConditionEnum::getCondition).toArray(); + + /** + * 模式 + */ + private final Integer condition; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java new file mode 100644 index 0000000..5460694 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordBizTypeEnum.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 佣金记录业务类型枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageRecordBizTypeEnum implements IntArrayValuable { + + ORDER(1, "获得推广佣金", "获得推广佣金 {}", true), + WITHDRAW(2, "提现申请", "提现申请扣除佣金 {}", false), + WITHDRAW_REJECT(3, "提现申请驳回", "提现申请驳回,返还佣金 {}", true), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordBizTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 标题 + */ + private final String title; + /** + * 描述 + */ + private final String description; + /** + * 是否为增加佣金 + */ + private final boolean add; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordStatusEnum.java new file mode 100644 index 0000000..8273909 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageRecordStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 佣金记录状态枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageRecordStatusEnum implements IntArrayValuable { + + WAIT_SETTLEMENT(0, "待结算"), + SETTLEMENT(1, "已结算"), + CANCEL(2, "已取消"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageRecordStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java new file mode 100644 index 0000000..b68db4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawStatusEnum.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +// TODO 芋艿:提现的打通,在纠结下; +/** + * 佣金提现状态枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageWithdrawStatusEnum implements IntArrayValuable { + + AUDITING(0, "审核中"), + AUDIT_SUCCESS(10, "审核通过"), + WITHDRAW_SUCCESS(11, "提现成功"), + AUDIT_FAIL(20, "审核不通过"), + WITHDRAW_FAIL(21, "提现失败"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java new file mode 100644 index 0000000..46edf01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.trade.enums.brokerage; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 佣金提现类型枚举 + * + * @author owen + */ +@AllArgsConstructor +@Getter +public enum BrokerageWithdrawTypeEnum implements IntArrayValuable { + + WALLET(1, "钱包"), + BANK(2, "银行卡"), + WECHAT(3, "微信"), + ALIPAY(4, "支付宝"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageWithdrawTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryExpressChargeModeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryExpressChargeModeEnum.java new file mode 100644 index 0000000..7503dd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryExpressChargeModeEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.trade.enums.delivery; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 快递配送计费方式枚举 + * + * @author jason + */ +@AllArgsConstructor +@Getter +public enum DeliveryExpressChargeModeEnum implements IntArrayValuable { + + COUNT(1, "按件"), + WEIGHT(2,"按重量"), + VOLUME(3, "按体积"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryExpressChargeModeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 描述 + */ + private final String desc; + + @Override + public int[] array() { + return ARRAYS; + } + + public static DeliveryExpressChargeModeEnum valueOf(Integer value) { + return ArrayUtil.firstMatch(chargeMode -> chargeMode.getType().equals(value), DeliveryExpressChargeModeEnum.values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryTypeEnum.java new file mode 100644 index 0000000..27e1137 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryTypeEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.enums.delivery; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 配送方式枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum DeliveryTypeEnum implements IntArrayValuable { + + EXPRESS(1, "快递发货"), + PICK_UP(2, "用户自提"),; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DeliveryTypeEnum::getType).toArray(); + + /** + * 配送方式 + */ + private final Integer type; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/notify/TradeNotifyEnums.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/notify/TradeNotifyEnums.java new file mode 100644 index 0000000..74c6b23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/notify/TradeNotifyEnums.java @@ -0,0 +1,5 @@ +package cn.iocoder.yudao.module.trade.enums.notify; + +// TODO @芋艿:这个枚举的作用? +public interface TradeNotifyEnums { +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java new file mode 100644 index 0000000..8ec1e9b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易订单 - 关闭类型 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderCancelTypeEnum implements IntArrayValuable { + + PAY_TIMEOUT(10, "超时未支付"), + AFTER_SALE_CLOSE(20, "退款关闭"), + MEMBER_CANCEL(30, "买家取消"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray(); + + /** + * 关闭类型 + */ + private final Integer type; + /** + * 关闭类型名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java new file mode 100644 index 0000000..5064071 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderItemAfterSaleStatusEnum.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易订单项 - 售后状态 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderItemAfterSaleStatusEnum implements IntArrayValuable { + + NONE(0, "未售后"), + APPLY(10, "售后中"), + SUCCESS(20, "售后成功"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderItemAfterSaleStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + /** + * 判断指定状态,是否正处于【未申请】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isNone(Integer status) { + return ObjectUtil.equals(status, NONE.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java new file mode 100644 index 0000000..986d064 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 订单操作类型的枚举 + * + * @author 陈賝 + * @since 2023/7/6 15:31 + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderOperateTypeEnum { + + MEMBER_CREATE(1, "用户下单"), + ADMIN_UPDATE_PRICE(2, "订单价格 {oldPayPrice} 修改,调整价格 {adjustPrice},实际支付金额为 {newPayPrice} 元"), + MEMBER_PAY(10, "用户付款成功"), + ADMIN_UPDATE_ADDRESS(11, "收货地址修改"), + ADMIN_DELIVERY(20, "已发货,快递公司:{expressName},快递单号:{logisticsNo}"), + MEMBER_RECEIVE(30, "用户已收货"), + SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"), + ADMIN_PICK_UP_RECEIVE(32, "管理员自提收货"), + MEMBER_COMMENT(33, "用户评价"), + SYSTEM_COMMENT(34, "到期未评价,系统自动评价"), + MEMBER_CANCEL(40, "取消订单"), + SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"), + // 42 预留:管理员取消订单 + ADMIN_CANCEL_AFTER_SALE(43, "订单全部售后,管理员自动取消订单"), + MEMBER_DELETE(49, "删除订单"), + ; + + /** + * 操作类型 + */ + private final Integer type; + /** + * 操作描述 + */ + private final String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java new file mode 100644 index 0000000..d0e4190 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易订单 - 退款状态 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderRefundStatusEnum implements IntArrayValuable { + + NONE(0, "未退款"), + PART(10, "部分退款"), + ALL(20, "全部退款"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderRefundStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java new file mode 100644 index 0000000..86d3d99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易订单 - 状态 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderStatusEnum implements IntArrayValuable { + + UNPAID(0, "待支付"), + UNDELIVERED(10, "待发货"), + DELIVERED(20, "已发货"), + COMPLETED(30, "已完成"), + CANCELED(40, "已取消"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + // ========== 问:为什么写了很多 isXXX 和 haveXXX 的判断逻辑呢? ========== + // ========== 答:方便找到某一类判断,哪些业务正在使用 ========== + + /** + * 判断指定状态,是否正处于【未付款】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isUnpaid(Integer status) { + return ObjectUtil.equal(UNPAID.getStatus(), status); + } + + /** + * 判断指定状态,是否正处于【待发货】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isUndelivered(Integer status) { + return ObjectUtil.equal(UNDELIVERED.getStatus(), status); + } + + /** + * 判断指定状态,是否正处于【已发货】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isDelivered(Integer status) { + return ObjectUtil.equals(status, DELIVERED.getStatus()); + } + + /** + * 判断指定状态,是否正处于【已取消】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isCanceled(Integer status) { + return ObjectUtil.equals(status, CANCELED.getStatus()); + } + + /** + * 判断指定状态,是否正处于【已完成】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isCompleted(Integer status) { + return ObjectUtil.equals(status, COMPLETED.getStatus()); + } + + /** + * 判断指定状态,是否有过【已付款】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean havePaid(Integer status) { + return ObjectUtils.equalsAny(status, UNDELIVERED.getStatus(), + DELIVERED.getStatus(), COMPLETED.getStatus()); + } + + /** + * 判断指定状态,是否有过【已发货】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean haveDelivered(Integer status) { + return ObjectUtils.equalsAny(status, DELIVERED.getStatus(), COMPLETED.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java new file mode 100644 index 0000000..f820712 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 交易订单 - 类型 + * + * @author Sin + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderTypeEnum implements IntArrayValuable { + + NORMAL(0, "普通订单"), + SECKILL(1, "秒杀订单"), + BARGAIN(2, "砍价订单"), + COMBINATION(3, "拼团订单"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static boolean isNormal(Integer type) { + return ObjectUtil.equal(type, NORMAL.getType()); + } + + public static boolean isSeckill(Integer type) { + return ObjectUtil.equal(type, SECKILL.getType()); + } + + public static boolean isBargain(Integer type) { + return ObjectUtil.equal(type, BARGAIN.getType()); + } + + public static boolean isCombination(Integer type) { + return ObjectUtil.equal(type, COMBINATION.getType()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/pom.xml new file mode 100644 index 0000000..fb046ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/pom.xml @@ -0,0 +1,97 @@ + + + + cn.iocoder.boot + yudao-module-mall + ${revision} + + 4.0.0 + yudao-module-trade-biz + jar + + ${project.artifactId} + + trade 模块,主要实现交易相关功能 + 例如:订单、退款、购物车等功能。 + + + + + cn.iocoder.boot + yudao-module-trade-api + ${revision} + + + cn.iocoder.boot + yudao-module-product-api + ${revision} + + + cn.iocoder.boot + yudao-module-pay-api + ${revision} + + + cn.iocoder.boot + yudao-module-promotion-api + ${revision} + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java new file mode 100644 index 0000000..3cb7bba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.trade.api.order; + +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 订单 API 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class TradeOrderApiImpl implements TradeOrderApi { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + + @Override + public List getOrderList(Collection ids) { + return TradeOrderConvert.INSTANCE.convertList04(tradeOrderQueryService.getOrderList(ids)); + } + + @Override + public TradeOrderRespDTO getOrder(Long id) { + return TradeOrderConvert.INSTANCE.convert(tradeOrderQueryService.getOrder(id)); + } + + @Override + public void cancelPaidOrder(Long userId, Long orderId) { + tradeOrderUpdateService.cancelPaidOrder(userId, orderId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java new file mode 100644 index 0000000..5b0e37d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.trade.api; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java new file mode 100644 index 0000000..b89db05 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java @@ -0,0 +1,144 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.*; +import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 售后订单") +@RestController +@RequestMapping("/trade/after-sale") +@Validated +@Slf4j +public class AfterSaleController { + + @Resource + private AfterSaleService afterSaleService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + @Resource + private AfterSaleLogService afterSaleLogService; + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/page") + @Operation(summary = "获得售后订单分页") + @PreAuthorize("@ss.hasPermission('trade:after-sale:query')") + public CommonResult> getAfterSalePage(@Valid AfterSalePageReqVO pageVO) { + // 查询售后 + PageResult pageResult = afterSaleService.getAfterSalePage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 查询会员 + Map memberUsers = memberUserApi.getUserMap( + convertSet(pageResult.getList(), AfterSaleDO::getUserId)); + return success(AfterSaleConvert.INSTANCE.convertPage(pageResult, memberUsers)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得售后订单详情") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:query')") + public CommonResult getOrderDetail(@RequestParam("id") Long id) { + // 查询订单 + AfterSaleDO afterSale = afterSaleService.getAfterSale(id); + if (afterSale == null) { + return success(null); + } + + // 查询订单 + TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); + // 查询订单项 + TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(afterSale.getOrderItemId()); + // 拼接数据 + MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId()); + List logs = afterSaleLogService.getAfterSaleLogList(afterSale.getId()); + return success(AfterSaleConvert.INSTANCE.convert(afterSale, order, orderItem, user, logs)); + } + + @PutMapping("/agree") + @Operation(summary = "同意售后") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')") + public CommonResult agreeAfterSale(@RequestParam("id") Long id) { + afterSaleService.agreeAfterSale(getLoginUserId(), id); + return success(true); + } + + @PutMapping("/disagree") + @Operation(summary = "拒绝售后") + @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')") + public CommonResult disagreeAfterSale(@RequestBody AfterSaleDisagreeReqVO confirmReqVO) { + afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO); + return success(true); + } + + @PutMapping("/receive") + @Operation(summary = "确认收货") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") + public CommonResult receiveAfterSale(@RequestParam("id") Long id) { + afterSaleService.receiveAfterSale(getLoginUserId(), id); + return success(true); + } + + @PutMapping("/refuse") + @Operation(summary = "拒绝收货") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") + public CommonResult refuseAfterSale(AfterSaleRefuseReqVO refuseReqVO) { + afterSaleService.refuseAfterSale(getLoginUserId(), refuseReqVO); + return success(true); + } + + @PutMapping("/refund") + @Operation(summary = "确认退款") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')") + public CommonResult refundAfterSale(@RequestParam("id") Long id) { + afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id); + return success(true); + } + + @PostMapping("/update-refunded") + @Operation(summary = "更新售后订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 + public CommonResult updateAfterRefund(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { + // 目前业务逻辑,不需要做任何事情 + // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警 + log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http new file mode 100644 index 0000000..81cb35c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http @@ -0,0 +1,33 @@ +### 获得交易售后分页 => 成功 +GET {{baseUrl}}/trade/after-sale/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 同意售后 => 成功 +PUT {{baseUrl}}/trade/after-sale/agree?id=7 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +Content-Type: application/json + +### 拒绝售后 => 成功 +PUT {{baseUrl}}/trade/after-sale/disagree +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +Content-Type: application/json + +{ + "id": 6, + "auditReason": "阿巴巴" +} + +### 确认退款 => 成功 +PUT {{baseUrl}}/trade/after-sale/refund?id=6 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +Content-Type: application/json + +### 确认收货 => 成功 +PUT {{baseUrl}}/trade/after-sale/receive?id=7 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +Content-Type: application/json diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java new file mode 100644 index 0000000..ae7bd39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 交易售后 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class AfterSaleBaseVO { + + @Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202211190847450020500077") + @NotNull(message = "售后流水号不能为空") + private String no; + + @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "售后状态不能为空") + private Integer status; + + @Schema(description = "售后类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @NotNull(message = "售后类型不能为空") + private Integer type; + + @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "售后方式不能为空") + private Integer way; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30337") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不喜欢") + @NotNull(message = "申请原因不能为空") + private String applyReason; + + @Schema(description = "补充描述", example = "你说的对") + private String applyDescription; + + @Schema(description = "补充凭证图片", example = "https://www.iocoder.cn/1.png") + private List applyPicUrls; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18078") + @NotNull(message = "订单编号不能为空") + private Long orderId; + + @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022111917190001") + @NotNull(message = "订单流水号不能为空") + private String orderNo; + + @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "572") + @NotNull(message = "订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2888") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "商品 SPU 名称不能为空") + private String spuName; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15657") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "商品图片", example = "https://www.iocoder.cn/2.png") + private String picUrl; + + @Schema(description = "购买数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20012") + @NotNull(message = "购买数量不能为空") + private Integer count; + + @Schema(description = "审批时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime auditTime; + + @Schema(description = "审批人", example = "30835") + private Long auditUserId; + + @Schema(description = "审批备注", example = "不香") + private String auditReason; + + @Schema(description = "退款金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "18077") + @NotNull(message = "退款金额,单位:分不能为空") + private Integer refundPrice; + + @Schema(description = "支付退款编号", example = "10271") + private Long payRefundId; + + @Schema(description = "退款时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime refundTime; + + @Schema(description = "退货物流公司编号", example = "10") + private Long logisticsId; + + @Schema(description = "退货物流单号", example = "610003952009") + private String logisticsNo; + + @Schema(description = "退货时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime deliveryTime; + + @Schema(description = "收货时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime receiveTime; + + @Schema(description = "收货备注", example = "不喜欢") + private String receiveReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java new file mode 100644 index 0000000..3f22077 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderItemBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 售后订单的详情 Response VO") +@Data +public class AfterSaleDetailRespVO extends AfterSaleBaseVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + + + /** + * 订单基本信息 + */ + private TradeOrderBaseVO order; + /** + * 订单项列表 + */ + private OrderItem orderItem; + + /** + * 用户信息 + */ + private MemberUserRespVO user; + + /** + * 售后日志 + */ + private List logs; + + @Schema(description = "管理后台 - 交易订单的详情的订单项目") + @Data + public static class OrderItem extends TradeOrderItemBaseVO { + + /** + * 属性数组 + */ + private List properties; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java new file mode 100644 index 0000000..6fa511a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 交易售后拒绝 Request VO") +@Data +public class AfterSaleDisagreeReqVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @Schema(description = "审批备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + @NotEmpty(message = "审批备注不能为空") + private String auditReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java new file mode 100644 index 0000000..f74c84b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 交易售后分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AfterSalePageReqVO extends PageParam { + + @Schema(description = "售后流水号", example = "202211190847450020500077") + private String no; + + @Schema(description = "售后状态", example = "10") + @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}") + private Integer status; + + @Schema(description = "售后类型", example = "20") + @InEnum(value = AfterSaleTypeEnum.class, message = "售后类型必须是 {value}") + private Integer type; + + @Schema(description = "售后方式", example = "10") + @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}") + private Integer way; + + @Schema(description = "订单编号", example = "18078") + private String orderNo; + + @Schema(description = "商品 SPU 名称", example = "李四") + private String spuName; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java new file mode 100644 index 0000000..6dfced4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 交易售后拒绝收货 Request VO") +@Data +public class AfterSaleRefuseReqVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @Schema(description = "收货备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + @NotNull(message = "收货备注不能为空") + private String refuseMemo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java new file mode 100644 index 0000000..3e76405 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 交易售后分页的每一条记录 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AfterSaleRespPageItemVO extends AfterSaleBaseVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27630") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + /** + * 商品属性数组 + */ + private List properties; + + /** + * 用户信息 + */ + private MemberUserRespVO user; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java new file mode 100644 index 0000000..0a5e019 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 交易售后日志 Response VO") +@Data +public class AfterSaleLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22634") + private Long userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3023") + private Long afterSaleId; + + @Schema(description = "售后状态(之前)", example = "2") + private Integer beforeStatus; + + @Schema(description = "售后状态(之后)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer afterStatus; + + @Schema(description = "操作明细", requiredMode = Schema.RequiredMode.REQUIRED, example = "维权完成,退款金额:¥37776.00") + private String content; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java new file mode 100644 index 0000000..f874e48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,可忽略 + */ +package cn.iocoder.yudao.module.trade.controller.admin.base.member; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java new file mode 100644 index 0000000..2d7c351 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.trade.controller.admin.base.member.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 会员用户 Response VO") +@Data +public class MemberUserRespVO { + + @Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String nickname; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java new file mode 100644 index 0000000..0baa83e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java @@ -0,0 +1,4 @@ +/** + * 放置该模块通用的 VO 类 + */ +package cn.iocoder.yudao.module.trade.controller.admin.base; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java new file mode 100644 index 0000000..3d6d3b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.base.product.property; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 商品属性值的明细 Response VO") +@Data +public class ProductPropertyValueDetailRespVO { + + @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long propertyId; + + @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色") + private String propertyName; + + @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long valueId; + + @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色") + private String valueName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java new file mode 100644 index 0000000..ff9bd52 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordRespVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 佣金记录") +@RestController +@RequestMapping("/trade/brokerage-record") +@Validated +public class BrokerageRecordController { + + @Resource + private BrokerageRecordService brokerageRecordService; + + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/get") + @Operation(summary = "获得佣金记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") + public CommonResult getBrokerageRecord(@RequestParam("id") Integer id) { + BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id); + return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord)); + } + + @GetMapping("/page") + @Operation(summary = "获得佣金记录分页") + @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") + public CommonResult> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) { + PageResult pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO); + + // 查询用户信息 + Set userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId); + userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId)); + Map userMap = memberUserApi.getUserMap(userIds); + // 拼接数据 + return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java new file mode 100644 index 0000000..622ff87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.*; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageUserConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 分销用户") +@RestController +@RequestMapping("/trade/brokerage-user") +@Validated +public class BrokerageUserController { + + @Resource + private BrokerageUserService brokerageUserService; + @Resource + private BrokerageRecordService brokerageRecordService; + @Resource + private BrokerageWithdrawService brokerageWithdrawService; + + @Resource + private MemberUserApi memberUserApi; + + @PutMapping("/update-bind-user") + @Operation(summary = "修改推广员") + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')") + public CommonResult updateBindUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) { + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId()); + return success(true); + } + + @PutMapping("/clear-bind-user") + @Operation(summary = "清除推广员") + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-bind-user')") + public CommonResult clearBindUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) { + brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null); + return success(true); + } + + @PutMapping("/update-brokerage-enable") + @Operation(summary = "修改推广资格") + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')") + public CommonResult updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) { + brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled()); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得分销用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") + public CommonResult getBrokerageUser(@RequestParam("id") Long id) { + BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id); + // TODO @疯狂:是不是搞成一个统一的 convert? + BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser); + return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO)); + } + + @GetMapping("/page") + @Operation(summary = "获得分销用户分页") + @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')") + public CommonResult> getBrokerageUserPage(@Valid BrokerageUserPageReqVO pageVO) { + // 分页查询 + PageResult pageResult = brokerageUserService.getBrokerageUserPage(pageVO); + + // 查询用户信息 + Set userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId); + Map userMap = memberUserApi.getUserMap(userIds); + // 合计分佣的推广订单 + Map brokerageOrderSummaryMap = brokerageRecordService.getUserBrokerageSummaryMapByUserId( + userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()); + // 合计分佣的推广用户 + // TODO @疯狂:转成 map 批量读取 + Map brokerageUserCountMap = convertMap(userIds, + userId -> userId, + userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null)); + // 合计分佣的提现 + // TODO @疯狂:如果未来支持了打款这个动作,可能 status 会不对; + Map withdrawMap = brokerageWithdrawService.getWithdrawSummaryMapByUserId( + userIds, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS); + // 拼接返回 + return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap, + brokerageOrderSummaryMap, withdrawMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java new file mode 100644 index 0000000..609cfa4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRejectReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRespVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 佣金提现") +@RestController +@RequestMapping("/trade/brokerage-withdraw") +@Validated +public class BrokerageWithdrawController { + + @Resource + private BrokerageWithdrawService brokerageWithdrawService; + + @Resource + private MemberUserApi memberUserApi; + + @PutMapping("/approve") + @Operation(summary = "通过申请") + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')") + public CommonResult approveBrokerageWithdraw(@RequestParam("id") Integer id) { + brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, ""); + return success(true); + } + + @PutMapping("/reject") + @Operation(summary = "驳回申请") + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')") + public CommonResult rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawRejectReqVO reqVO) { + brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason()); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得佣金提现") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')") + public CommonResult getBrokerageWithdraw(@RequestParam("id") Integer id) { + BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id); + return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw)); + } + + @GetMapping("/page") + @Operation(summary = "获得佣金提现分页") + @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')") + public CommonResult> getBrokerageWithdrawPage(@Valid BrokerageWithdrawPageReqVO pageVO) { + // 分页查询 + PageResult pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(pageVO); + + // 拼接信息 + Map userMap = memberUserApi.getUserMap( + convertSet(pageResult.getList(), BrokerageWithdrawDO::getUserId)); + return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java new file mode 100644 index 0000000..0c53f99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 佣金记录 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BrokerageRecordBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25973") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353") + @NotEmpty(message = "业务编号不能为空") + private String bizId; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "业务类型不能为空") + private Integer bizType; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "标题不能为空") + private String title; + + @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731") + @NotNull(message = "金额不能为空") + private Integer price; + + @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "13226") + @NotNull(message = "当前总佣金不能为空") + private Integer totalPrice; + + @Schema(description = "说明", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对") + @NotNull(message = "说明不能为空") + private String description; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "冻结时间(天)不能为空") + private Integer frozenDays; + + @Schema(description = "解冻时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime unfreezeTime; + + @Schema(description = "来源用户等级") + private Integer sourceUserLevel; + + @Schema(description = "来源用户编号") + private Long sourceUserId; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java new file mode 100644 index 0000000..36c4744 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 佣金记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageRecordPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "25973") + private Long userId; + + @Schema(description = "业务类型", example = "1") + private Integer bizType; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "用户类型", example = "1") + private Integer sourceUserLevel; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java new file mode 100644 index 0000000..224ecf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 佣金记录 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageRecordRespVO extends BrokerageRecordBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896") + private Integer id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + + // ========== 用户信息 ========== + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String userAvatar; + @Schema(description = "用户昵称", example = "李四") + private String userNickname; + + + // ========== 来源用户信息 ========== + + @Schema(description = "来源用户头像", example = "https://www.iocoder.cn/xxx.png") + private String sourceUserAvatar; + @Schema(description = "来源用户昵称", example = "李四") + private String sourceUserNickname; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java new file mode 100644 index 0000000..05e5935 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 分销用户 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BrokerageUserBaseVO { + + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587") + @NotNull(message = "推广员编号不能为空") + private Long bindUserId; + + @Schema(description = "推广员绑定时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime bindUserTime; + + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "推广资格不能为空") + private Boolean brokerageEnabled; + + @Schema(description = "成为分销员时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime brokerageTime; + + @Schema(description = "可用佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "11089") + @NotNull(message = "可用佣金不能为空") + private Integer price; + + @Schema(description = "冻结佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "30916") + @NotNull(message = "冻结佣金不能为空") + private Integer frozenPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java new file mode 100644 index 0000000..5a05c56 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 分销用户 - 清除推广员 Request VO") +@Data +@ToString(callSuper = true) +public class BrokerageUserClearBrokerageUserReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + @NotNull(message = "用户编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java new file mode 100644 index 0000000..cb0ce89 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 分销用户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageUserPageReqVO extends PageParam { + + @Schema(description = "推广员编号", example = "4587") + private Long bindUserId; + + @Schema(description = "推广资格", example = "true") + private Boolean brokerageEnabled; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "用户等级", example = "1") // 注意,这了不是用户的会员等级,而是过滤推广的层级 + private Integer level; + + @Schema(description = "绑定时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] bindUserTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java new file mode 100644 index 0000000..3f5fe25 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 分销用户 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageUserRespVO extends BrokerageUserBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 用户信息 ========== + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.png") + private String avatar; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String nickname; + + // ========== 推广信息 ========== 注意:是包括 1 + 2 级的数据 + + @Schema(description = "推广用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Integer brokerageUserCount; + @Schema(description = "推广订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Integer brokerageOrderCount; + @Schema(description = "推广订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Integer brokerageOrderPrice; + + // ========== 提现信息 ========== + + @Schema(description = "已提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Integer withdrawPrice; + @Schema(description = "已提现次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + private Integer withdrawCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java new file mode 100644 index 0000000..d097855 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO") +@Data +@ToString(callSuper = true) +public class BrokerageUserUpdateBrokerageEnabledReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + @NotNull(message = "用户编号不能为空") + private Long id; + + @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "推广资格不能为空") + private Boolean enabled; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java new file mode 100644 index 0000000..56391c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO") +@Data +@ToString(callSuper = true) +public class BrokerageUserUpdateBrokerageUserReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019") + @NotNull(message = "用户编号不能为空") + private Long id; + + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587") + @NotNull(message = "推广员编号不能为空") + private Long bindUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java new file mode 100644 index 0000000..8aca8a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 佣金提现 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BrokerageWithdrawBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11436") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18781") + @NotNull(message = "提现金额不能为空") + private Integer price; + + @Schema(description = "提现手续费", requiredMode = Schema.RequiredMode.REQUIRED, example = "11417") + @NotNull(message = "提现手续费不能为空") + private Integer feePrice; + + @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "18576") + @NotNull(message = "当前总佣金不能为空") + private Integer totalPrice; + + @Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "提现类型不能为空") + private Integer type; + + @Schema(description = "真实姓名", example = "赵六") + private String name; + + @Schema(description = "账号", example = "88677912132") + private String accountNo; + + @Schema(description = "银行名称", example = "1") + private String bankName; + + @Schema(description = "开户地址", example = "海淀支行") + private String bankAddress; + + @Schema(description = "收款码", example = "https://www.iocoder.cn") + private String accountQrCodeUrl; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "审核驳回原因", example = "不对") + private String auditReason; + + @Schema(description = "审核时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime auditTime; + + @Schema(description = "备注", example = "随便") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java new file mode 100644 index 0000000..b18ff74 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 佣金提现分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageWithdrawPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "11436") + private Long userId; + + @Schema(description = "提现类型", example = "1") + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现类型必须是 {value}") + private Integer type; + + @Schema(description = "真实姓名", example = "赵六") + private String name; + + @Schema(description = "账号", example = "886779132") + private String accountNo; + + @Schema(description = "银行名称", example = "1") + private String bankName; + + @Schema(description = "状态", example = "1") + @InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java new file mode 100644 index 0000000..23e6c28 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 驳回申请 Request VO") +@Data +@ToString(callSuper = true) +public class BrokerageWithdrawRejectReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") + @NotNull(message = "编号不能为空") + private Integer id; + + @Schema(description = "审核驳回原因", example = "不对") + @NotEmpty(message = "审核驳回原因不能为空") + private String auditReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java new file mode 100644 index 0000000..de74bb4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 佣金提现 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") + private Integer id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String userNickname; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java new file mode 100644 index 0000000..5e0558f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.trade.controller.admin.config; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 交易中心配置") +@RestController +@RequestMapping("/trade/config") +@Validated +public class TradeConfigController { + + @Resource + private TradeConfigService tradeConfigService; + + @Value("${yudao.tencent-lbs-key}") + private String tencentLbsKey; + + @PutMapping("/save") + @Operation(summary = "更新交易中心配置") + @PreAuthorize("@ss.hasPermission('trade:config:save')") + public CommonResult updateConfig(@Valid @RequestBody TradeConfigSaveReqVO updateReqVO) { + tradeConfigService.saveTradeConfig(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得交易中心配置") + @PreAuthorize("@ss.hasPermission('trade:config:query')") + public CommonResult getConfig() { + TradeConfigDO config = tradeConfigService.getTradeConfig(); + TradeConfigRespVO configVO = TradeConfigConvert.INSTANCE.convert(config); + if (configVO != null) { + configVO.setTencentLbsKey(tencentLbsKey); + } + return success(configVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java new file mode 100644 index 0000000..3c58275 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.trade.controller.admin.config.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.PositiveOrZero; +import java.util.List; + +/** + * 交易中心配置 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class TradeConfigBaseVO { + + // ========== 售后相关 ========== + + @Schema(description = "售后的退款理由", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "售后的退款理由不能为空") + private List afterSaleRefundReasons; + + @Schema(description = "售后的退货理由", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "售后的退货理由不能为空") + private List afterSaleReturnReasons; + + // ========== 配送相关 ========== + + /** + * 是否启用全场包邮 + */ + @Schema(description = "是否启用全场包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否启用全场包邮不能为空") + private Boolean deliveryExpressFreeEnabled; + + @Schema(description = "全场包邮的最小金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "全场包邮的最小金额不能为空") + @PositiveOrZero(message = "全场包邮的最小金额不能是负数") + private Integer deliveryExpressFreePrice; + + @Schema(description = "是否开启自提", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启自提不能为空") + private Boolean deliveryPickUpEnabled; + + // ========== 分销相关 ========== + + @Schema(description = "是否启用分佣", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否启用分佣不能为空") + private Boolean brokerageEnabled; + + @Schema(description = "分佣模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "分佣模式不能为空") + @InEnum(value = BrokerageEnabledConditionEnum.class, message = "分佣模式必须是 {value}") + private Integer brokerageEnabledCondition; + + @Schema(description = "分销关系绑定模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "分销关系绑定模式不能为空") + @InEnum(value = BrokerageBindModeEnum.class, message = "分销关系绑定模式必须是 {value}") + private Integer brokerageBindMode; + + @Schema(description = "分销海报图地址数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/yudao.jpg]") + private List brokeragePosterUrls; + + @Schema(description = "一级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "一级返佣比例不能为空") + @Range(min = 0, max = 100, message = "一级返佣比例必须在 0 - 100 之间") + private Integer brokerageFirstPercent; + + @Schema(description = "二级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "二级返佣比例不能为空") + @Range(min = 0, max = 100, message = "二级返佣比例必须在 0 - 100 之间") + private Integer brokerageSecondPercent; + + @Schema(description = "用户提现最低金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "用户提现最低金额不能为空") + @PositiveOrZero(message = "用户提现最低金额不能是负数") + private Integer brokerageWithdrawMinPrice; + + @Schema(description = "用户提现手续费百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "用户提现手续费百分比不能为空") + @PositiveOrZero(message = "用户提现手续费百分比不能是负数") + private Integer brokerageWithdrawFeePercent; + + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "7") + @NotNull(message = "佣金冻结时间(天)不能为空") + @PositiveOrZero(message = "佣金冻结时间不能是负数") + private Integer brokerageFrozenDays; + + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]") + @NotEmpty(message = "提现方式不能为空") + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") + private List brokerageWithdrawTypes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java new file mode 100644 index 0000000..5ded00a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 交易中心配置 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TradeConfigRespVO extends TradeConfigBaseVO { + + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "腾讯地图 KEY", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String tencentLbsKey; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java new file mode 100644 index 0000000..03a0c41 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.trade.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 交易中心配置更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TradeConfigSaveReqVO extends TradeConfigBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java new file mode 100644 index 0000000..63f77c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.*; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 快递公司") +@RestController +@RequestMapping("/trade/delivery/express") +@Validated +public class DeliveryExpressController { + + @Resource + private DeliveryExpressService deliveryExpressService; + + @PostMapping("/create") + @Operation(summary = "创建快递公司") + @PreAuthorize("@ss.hasPermission('trade:delivery:express:create')") + public CommonResult createDeliveryExpress(@Valid @RequestBody DeliveryExpressCreateReqVO createReqVO) { + return success(deliveryExpressService.createDeliveryExpress(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新快递公司") + @PreAuthorize("@ss.hasPermission('trade:delivery:express:update')") + public CommonResult updateDeliveryExpress(@Valid @RequestBody DeliveryExpressUpdateReqVO updateReqVO) { + deliveryExpressService.updateDeliveryExpress(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除快递公司") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('trade:delivery:express:delete')") + public CommonResult deleteDeliveryExpress(@RequestParam("id") Long id) { + deliveryExpressService.deleteDeliveryExpress(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得快递公司") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:delivery:express:query')") + public CommonResult getDeliveryExpress(@RequestParam("id") Long id) { + DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(id); + return success(DeliveryExpressConvert.INSTANCE.convert(deliveryExpress)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取快递公司精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getSimpleDeliveryExpressList() { + List list = deliveryExpressService.getDeliveryExpressListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(DeliveryExpressConvert.INSTANCE.convertList1(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得快递公司分页") + @PreAuthorize("@ss.hasPermission('trade:delivery:express:query')") + public CommonResult> getDeliveryExpressPage(@Valid DeliveryExpressPageReqVO pageVO) { + PageResult pageResult = deliveryExpressService.getDeliveryExpressPage(pageVO); + return success(DeliveryExpressConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出快递公司 Excel") + @PreAuthorize("@ss.hasPermission('trade:delivery:express:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDeliveryExpressExcel(@Valid DeliveryExpressExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = deliveryExpressService.getDeliveryExpressList(exportReqVO); + // 导出 Excel + List dataList = DeliveryExpressConvert.INSTANCE.convertList02(list); + ExcelUtils.write(response, "快递公司.xls", "数据", DeliveryExpressExcelVO.class, dataList); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java new file mode 100644 index 0000000..5dc8368 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 快递运费模板") +@RestController +@RequestMapping("/trade/delivery/express-template") +@Validated +public class DeliveryExpressTemplateController { + + @Resource + private DeliveryExpressTemplateService deliveryExpressTemplateService; + + @PostMapping("/create") + @Operation(summary = "创建快递运费模板") + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:create')") + public CommonResult createDeliveryExpressTemplate(@Valid @RequestBody DeliveryExpressTemplateCreateReqVO createReqVO) { + return success(deliveryExpressTemplateService.createDeliveryExpressTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新快递运费模板") + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:update')") + public CommonResult updateDeliveryExpressTemplate(@Valid @RequestBody DeliveryExpressTemplateUpdateReqVO updateReqVO) { + deliveryExpressTemplateService.updateDeliveryExpressTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除快递运费模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:delete')") + public CommonResult deleteDeliveryExpressTemplate(@RequestParam("id") Long id) { + deliveryExpressTemplateService.deleteDeliveryExpressTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得快递运费模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") + public CommonResult getDeliveryExpressTemplate(@RequestParam("id") Long id) { + return success(deliveryExpressTemplateService.getDeliveryExpressTemplate(id)); + } + + @GetMapping("/list") + @Operation(summary = "获得快递运费模板列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") + public CommonResult> getDeliveryExpressTemplateList(@RequestParam("ids") Collection ids) { + List list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(ids); + return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取快递模版精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getSimpleTemplateList() { + // 获取运费模版列表,只要开启状态的 + List list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(); + // 排序后,返回给前端 + return success(DeliveryExpressTemplateConvert.INSTANCE.convertList1(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得快递运费模板分页") + @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") + public CommonResult> getDeliveryExpressTemplatePage(@Valid DeliveryExpressTemplatePageReqVO pageVO) { + PageResult pageResult = deliveryExpressTemplateService.getDeliveryExpressTemplatePage(pageVO); + return success(DeliveryExpressTemplateConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java new file mode 100644 index 0000000..4235d6e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.*; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryPickUpStoreConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 自提门店") +@RestController +@RequestMapping("/trade/delivery/pick-up-store") +@Validated +public class DeliveryPickUpStoreController { + + @Resource + private DeliveryPickUpStoreService deliveryPickUpStoreService; + + @PostMapping("/create") + @Operation(summary = "创建自提门店") + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:create')") + public CommonResult createDeliveryPickUpStore(@Valid @RequestBody DeliveryPickUpStoreCreateReqVO createReqVO) { + return success(deliveryPickUpStoreService.createDeliveryPickUpStore(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新自提门店") + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:update')") + public CommonResult updateDeliveryPickUpStore(@Valid @RequestBody DeliveryPickUpStoreUpdateReqVO updateReqVO) { + deliveryPickUpStoreService.updateDeliveryPickUpStore(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除自提门店") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:delete')") + public CommonResult deleteDeliveryPickUpStore(@RequestParam("id") Long id) { + deliveryPickUpStoreService.deleteDeliveryPickUpStore(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得自提门店") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')") + public CommonResult getDeliveryPickUpStore(@RequestParam("id") Long id) { + DeliveryPickUpStoreDO deliveryPickUpStore = deliveryPickUpStoreService.getDeliveryPickUpStore(id); + return success(DeliveryPickUpStoreConvert.INSTANCE.convert(deliveryPickUpStore)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获得自提门店精简信息列表") + public CommonResult> getSimpleDeliveryPickUpStoreList() { + List list = deliveryPickUpStoreService.getDeliveryPickUpStoreListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + return success(DeliveryPickUpStoreConvert.INSTANCE.convertList1(list)); + } + + @GetMapping("/list") + @Operation(summary = "获得自提门店列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')") + public CommonResult> getDeliveryPickUpStoreList(@RequestParam("ids") Collection ids) { + List list = deliveryPickUpStoreService.getDeliveryPickUpStoreList(ids); + return success(DeliveryPickUpStoreConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得自提门店分页") + @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')") + public CommonResult> getDeliveryPickUpStorePage(@Valid DeliveryPickUpStorePageReqVO pageVO) { + PageResult pageResult = deliveryPickUpStoreService.getDeliveryPickUpStorePage(pageVO); + return success(DeliveryPickUpStoreConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java new file mode 100644 index 0000000..cc7b8be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** +* 快递公司 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DeliveryExpressBaseVO { + + @Schema(description = "快递公司编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "快递公司编码不能为空") + private String code; + + @Schema(description = "快递公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "快递公司名称不能为空") + private String name; + + @Schema(description = "快递公司logo") + private String logo; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java new file mode 100644 index 0000000..a9ba8a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "管理后台 - 快递公司创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressCreateReqVO extends DeliveryExpressBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java new file mode 100644 index 0000000..c84a3a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 快递公司 Excel VO + */ +@Data +public class DeliveryExpressExcelVO { + + @ExcelProperty("编号") + private Long id; + + @ExcelProperty("快递公司编码") + private String code; + + @ExcelProperty("快递公司名称") + private String name; + + @ExcelProperty("快递公司 logo") + private String logo; + + @ExcelProperty("排序") + private Integer sort; + + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java new file mode 100644 index 0000000..c601721 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 快递公司 Excel 导出 Request VO") +@Data +public class DeliveryExpressExportReqVO { + + @Schema(description = "快递公司编码") + private String code; + + @Schema(description = "快递公司名称", example = "李四") + private String name; + + @Schema(description = "状态(0正常 1停用)", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java new file mode 100644 index 0000000..4a000f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 快递公司分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressPageReqVO extends PageParam { + + @Schema(description = "快递公司编码") + private String code; + + @Schema(description = "快递公司名称", example = "李四") + private String name; + + @Schema(description = "状态(0正常 1停用)", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java new file mode 100644 index 0000000..cc314d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 快递公司 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressRespVO extends DeliveryExpressBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java new file mode 100644 index 0000000..b97cc23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 快递公司精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeliveryExpressSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "快递公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "顺丰速运") + @NotNull(message = "快递公司名称不能为空") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java new file mode 100644 index 0000000..e51366d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 快递公司更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressUpdateReqVO extends DeliveryExpressBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java new file mode 100644 index 0000000..3be8ffc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** +* 快递运费模板 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DeliveryExpressTemplateBaseVO { + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotNull(message = "模板名称不能为空") + private String name; + + @Schema(description = "配送计费方式 1:按件 2:按重量 3:按体积", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "配送计费方式 1:按件 2:按重量 3:按体积不能为空") + private Integer chargeMode; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "排序不能为空") + private Integer sort; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java new file mode 100644 index 0000000..efb15c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 快递运费模板运费设置 Base VO,提供给添加运费模板使用 + */ +@Data +public class DeliveryExpressTemplateChargeBaseVO { + + @Schema(description = "编号", example = "6592", hidden = true) // 由于想简单一点,复用这个 VO 在更新操作,所以 hidden 为 false + private Long id; + + @Schema(description = "区域编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,120000]") + @NotEmpty(message = "区域编号列表不能为空") + private List areaIds; + + @Schema(description = "首件数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "首件数量不能为空") + private Double startCount; + + @Schema(description = "起步价", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @NotNull(message = "起步价不能为空") + private Integer startPrice; + + @Schema(description = "续件数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "续件数量不能为空") + private Double extraCount; + + @Schema(description = "额外价", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + @NotNull(message = "额外价不能为空") + private Integer extraPrice; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java new file mode 100644 index 0000000..c5eeaeb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import java.util.List; + +@Schema(description = "管理后台 - 快递运费模板创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressTemplateCreateReqVO extends DeliveryExpressTemplateBaseVO { + + @Schema(description = "区域运费列表") + @Valid + private List charges; + + @Schema(description = "包邮区域列表") + @Valid + private List frees; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java new file mode 100644 index 0000000..272ab59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 快递运费模板的详细 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressTemplateDetailRespVO extends DeliveryExpressTemplateBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371") + private Long id; + + @Schema(description = "运费模板运费设置", requiredMode = Schema.RequiredMode.REQUIRED) + private List charges; + + @Schema(description = "运费模板包邮区域", requiredMode = Schema.RequiredMode.REQUIRED) + private List frees; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java new file mode 100644 index 0000000..b3e0f12 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 快递运费模板包邮 Base VO,提供给添加运费模板使用 + */ +@Data +public class DeliveryExpressTemplateFreeBaseVO { + + @Schema(description = "区域编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,120000]") + @NotEmpty(message = "区域编号列表不能为空") + private List areaIds; + + @Schema(description = "包邮金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "5000") + @NotNull(message = "包邮金额不能为空") + private Integer freePrice; + + @Schema(description = "包邮件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "包邮件数不能为空") + private Integer freeCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java new file mode 100644 index 0000000..ea1e4ab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 快递运费模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressTemplatePageReqVO extends PageParam { + + @Schema(description = "模板名称", example = "王五") + private String name; + + @Schema(description = "配送计费方式 1:按件 2:按重量 3:按体积") + private Integer chargeMode; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java new file mode 100644 index 0000000..19a8c16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 快递运费模板 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressTemplateRespVO extends DeliveryExpressTemplateBaseVO { + + @Schema(description = "编号,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "371") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java new file mode 100644 index 0000000..074cc53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Schema(description = "管理后台 - 模版精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeliveryExpressTemplateSimpleRespVO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java new file mode 100644 index 0000000..4c17745 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 快递运费模板更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryExpressTemplateUpdateReqVO extends DeliveryExpressTemplateBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "区域运费列表") + @Valid + private List charges; + + @Schema(description = "包邮区域列表") + @Valid + private List frees; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java new file mode 100644 index 0000000..6a4ab11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalTime; + +/** +* 自提门店 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DeliveryPickUpStoreBaseVO { + + @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotBlank(message = "门店名称不能为空") + private String name; + + @Schema(description = "门店简介", example = "我是门店简介") + private String introduction; + + @Schema(description = "门店手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601892312") + @NotBlank(message = "门店手机不能为空") + @Mobile + private String phone; + + @Schema(description = "区域编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18733") + @NotNull(message = "区域编号不能为空") + private Integer areaId; + + @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号") + @NotBlank(message = "门店详细地址不能为空") + private String detailAddress; + + @Schema(description = "门店 logo", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + @NotBlank(message = "门店 logo 不能为空") + private String logo; + + @Schema(description = "营业开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "营业开始时间不能为空") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + private LocalTime openingTime; + + @Schema(description = "营业结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "营业结束时间不能为空") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") + private LocalTime closingTime; + + @Schema(description = "纬度", requiredMode = Schema.RequiredMode.REQUIRED, example = "5.88") + @NotNull(message = "纬度不能为空") + private Double latitude; + + @Schema(description = "经度", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.99") + @NotNull(message = "经度不能为空") + private Double longitude; + + @Schema(description = "门店状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "门店状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java new file mode 100644 index 0000000..2185a2a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 自提门店创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryPickUpStoreCreateReqVO extends DeliveryPickUpStoreBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java new file mode 100644 index 0000000..ee3ce2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import lombok.*; + +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 自提门店分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryPickUpStorePageReqVO extends PageParam { + + @Schema(description = "门店名称", example = "李四") + private String name; + + @Schema(description = "门店手机") + private String phone; + + @Schema(description = "区域编号", example = "18733") + private Integer areaId; + + @Schema(description = "门店状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java new file mode 100644 index 0000000..5b5bd0d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 自提门店 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryPickUpStoreRespVO extends DeliveryPickUpStoreBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java new file mode 100644 index 0000000..c12fc9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 自提门店精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeliveryPickUpStoreSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128") + private Long id; + + @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String name; + + @Schema(description = "门店手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601892312") + private String phone; + + @Schema(description = "区域编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18733") + private Integer areaId; + + @Schema(description = "区域名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xx市") + private String areaName; + + @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号") + private String detailAddress; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java new file mode 100644 index 0000000..2b0548d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 自提门店更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DeliveryPickUpStoreUpdateReqVO extends DeliveryPickUpStoreBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http new file mode 100644 index 0000000..0bf8812 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http @@ -0,0 +1,9 @@ +### 获得交易订单分页 => 成功 +GET {{baseUrl}}/trade/order/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 获得交易订单分页 => 成功 +GET {{baseUrl}}/trade/order/get-detail?id=21 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java new file mode 100644 index 0000000..58acde4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java @@ -0,0 +1,169 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 交易订单") +@RestController +@RequestMapping("/trade/order") +@Validated +@Slf4j +public class TradeOrderController { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + @Resource + private TradeOrderLogService tradeOrderLogService; + + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/page") + @Operation(summary = "获得交易订单分页") + @PreAuthorize("@ss.hasPermission('trade:order:query')") + public CommonResult> getOrderPage(TradeOrderPageReqVO reqVO) { + // 查询订单 + PageResult pageResult = tradeOrderQueryService.getOrderPage(reqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 查询用户信息 + Set userIds = CollUtil.unionDistinct(convertList(pageResult.getList(), TradeOrderDO::getUserId), + convertList(pageResult.getList(), TradeOrderDO::getBrokerageUserId, Objects::nonNull)); + Map userMap = memberUserApi.getUserMap(userIds); + // 查询订单项 + List orderItems = tradeOrderQueryService.getOrderItemListByOrderId( + convertSet(pageResult.getList(), TradeOrderDO::getId)); + // 最终组合 + return success(TradeOrderConvert.INSTANCE.convertPage(pageResult, orderItems, userMap)); + } + + @GetMapping("/summary") + @Operation(summary = "获得交易订单统计") + @PreAuthorize("@ss.hasPermission('trade:order:query')") + public CommonResult getOrderSummary(TradeOrderPageReqVO reqVO) { + return success(tradeOrderQueryService.getOrderSummary(reqVO)); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得交易订单详情") + @Parameter(name = "id", description = "订单编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:order:query')") + public CommonResult getOrderDetail(@RequestParam("id") Long id) { + // 查询订单 + TradeOrderDO order = tradeOrderQueryService.getOrder(id); + if (order == null) { + return success(null); + } + // 查询订单项 + List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); + + // 拼接数据 + MemberUserRespDTO user = memberUserApi.getUser(order.getUserId()); + MemberUserRespDTO brokerageUser = order.getBrokerageUserId() != null ? + memberUserApi.getUser(order.getBrokerageUserId()) : null; + List orderLogs = tradeOrderLogService.getOrderLogListByOrderId(id); + return success(TradeOrderConvert.INSTANCE.convert(order, orderItems, orderLogs, user, brokerageUser)); + } + + @GetMapping("/get-express-track-list") + @Operation(summary = "获得交易订单的物流轨迹") + @Parameter(name = "id", description = "交易订单编号") + @PreAuthorize("@ss.hasPermission('trade:order:query')") + public CommonResult> getOrderExpressTrackList(@RequestParam("id") Long id) { + return success(TradeOrderConvert.INSTANCE.convertList02( + tradeOrderQueryService.getExpressTrackList(id))); + } + + @PutMapping("/delivery") + @Operation(summary = "订单发货") + @PreAuthorize("@ss.hasPermission('trade:order:update')") + public CommonResult deliveryOrder(@RequestBody TradeOrderDeliveryReqVO deliveryReqVO) { + tradeOrderUpdateService.deliveryOrder(deliveryReqVO); + return success(true); + } + + @PutMapping("/update-remark") + @Operation(summary = "订单备注") + @PreAuthorize("@ss.hasPermission('trade:order:update')") + public CommonResult updateOrderRemark(@RequestBody TradeOrderRemarkReqVO reqVO) { + tradeOrderUpdateService.updateOrderRemark(reqVO); + return success(true); + } + + @PutMapping("/update-price") + @Operation(summary = "订单调价") + @PreAuthorize("@ss.hasPermission('trade:order:update')") + public CommonResult updateOrderPrice(@RequestBody TradeOrderUpdatePriceReqVO reqVO) { + tradeOrderUpdateService.updateOrderPrice(reqVO); + return success(true); + } + + @PutMapping("/update-address") + @Operation(summary = "修改订单收货地址") + @PreAuthorize("@ss.hasPermission('trade:order:update')") + public CommonResult updateOrderAddress(@RequestBody TradeOrderUpdateAddressReqVO reqVO) { + tradeOrderUpdateService.updateOrderAddress(reqVO); + return success(true); + } + + @PutMapping("/pick-up-by-id") + @Operation(summary = "订单核销") + @Parameter(name = "id", description = "交易订单编号") + @PreAuthorize("@ss.hasPermission('trade:order:pick-up')") + public CommonResult pickUpOrderById(@RequestParam("id") Long id) { + tradeOrderUpdateService.pickUpOrderByAdmin(id); + return success(true); + } + + @PutMapping("/pick-up-by-verify-code") + @Operation(summary = "订单核销") + @Parameter(name = "pickUpVerifyCode", description = "自提核销码") + @PreAuthorize("@ss.hasPermission('trade:order:pick-up')") + public CommonResult pickUpOrderByVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) { + tradeOrderUpdateService.pickUpOrderByAdmin(pickUpVerifyCode); + return success(true); + } + + @GetMapping("/get-by-pick-up-verify-code") + @Operation(summary = "查询核销码对应的订单") + @Parameter(name = "pickUpVerifyCode", description = "自提核销码") + @PreAuthorize("@ss.hasPermission('trade:order:query')") + public CommonResult getByPickUpVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) { + TradeOrderDO tradeOrder = tradeOrderUpdateService.getByPickUpVerifyCode(pickUpVerifyCode); + return success(TradeOrderConvert.INSTANCE.convert2(tradeOrder, null)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java new file mode 100644 index 0000000..88f5b0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java @@ -0,0 +1,151 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 交易订单 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class TradeOrderBaseVO { + + // ========== 订单基本信息 ========== + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195") + private String no; + + @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "订单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "订单来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer terminal; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long userId; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String userIp; + + @Schema(description = "用户备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String userRemark; + + @Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer productCount; + + @Schema(description = "订单完成时间") + private LocalDateTime finishTime; + + @Schema(description = "订单取消时间") + private LocalDateTime cancelTime; + + @Schema(description = "取消类型", example = "10") + private Integer cancelType; + + @Schema(description = "商家备注", example = "你猜一下") + private String remark; + + // ========== 价格 + 支付基本信息 ========== + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long payOrderId; + + @Schema(description = "是否已支付", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean payStatus; + + @Schema(description = "付款时间") + private LocalDateTime payTime; + + @Schema(description = "支付渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_lite") + private String payChannelCode; + + @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer totalPrice; + + @Schema(description = "订单优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer discountPrice; + + @Schema(description = "运费金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer deliveryPrice; + + @Schema(description = "订单调价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer adjustPrice; + + @Schema(description = "应付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer payPrice; + + // ========== 收件 + 物流基本信息 ========== + + @Schema(description = "配送方式", example = "10") + private Integer deliveryType; + + @Schema(description = "自提门店", example = "10") + private Long pickUpStoreId; + + @Schema(description = "自提核销码", example = "10") + private Long pickUpVerifyCode; + + @Schema(description = "配送模板编号", example = "1024") + private Long deliveryTemplateId; + + @Schema(description = "发货物流公司编号", example = "1024") + private Long logisticsId; + + @Schema(description = "发货物流单号", example = "1024") + private String logisticsNo; + + @Schema(description = "发货时间") + private LocalDateTime deliveryTime; + + @Schema(description = "收货时间") + private LocalDateTime receiveTime; + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String receiverName; + + @Schema(description = "收件人手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "13800138000") + private String receiverMobile; + + @Schema(description = "收件人地区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer receiverAreaId; + + @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "中关村大街 1 号") + private String receiverDetailAddress; + + // ========== 售后基本信息 ========== + + @Schema(description = "售后状态", example = "1") + private Integer afterSaleStatus; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer refundPrice; + + // ========== 营销基本信息 ========== + + @Schema(description = "优惠劵编号", example = "1024") + private Long couponId; + + @Schema(description = "优惠劵减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer couponPrice; + + @Schema(description = "积分抵扣的金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer pointPrice; + + @Schema(description = "VIP 减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Integer vipPrice; + + @Schema(description = "推广人编号", example = "1") + private Long brokerageUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java new file mode 100644 index 0000000..791c408 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 订单发货 Request VO") +@Data +public class TradeOrderDeliveryReqVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "订单编号不能为空") + private Long id; + + @Schema(description = "发货物流公司编号", example = "1") + @NotNull(message = "发货物流公司不能为空") + private Long logisticsId; + + @Schema(description = "发货物流单号", example = "SF123456789") + private String logisticsNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java new file mode 100644 index 0000000..055639e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 交易订单的详情 Response VO") +@Data +public class TradeOrderDetailRespVO extends TradeOrderBaseVO { + + /** + * 订单项列表 + */ + private List items; + + /** + * 下单用户信息 + */ + private MemberUserRespVO user; + /** + * 推广用户信息 + */ + private MemberUserRespVO brokerageUser; + + /** + * 操作日志列表 + */ + private List logs; + + @Schema(description = "收件人地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海 上海市 普陀区") + private String receiverAreaName; + + @Schema(description = "管理后台 - 交易订单的操作日志") + @Data + public static class OrderLog { + + @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货") + private String content; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20") + private LocalDateTime createTime; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer userType; + + } + + @Schema(description = "管理后台 - 交易订单的详情的订单项目") + @Data + public static class Item extends TradeOrderItemBaseVO { + + /** + * 属性数组 + */ + private List properties; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderItemBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderItemBaseVO.java new file mode 100644 index 0000000..ded1fe7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderItemBaseVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 交易订单项 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class TradeOrderItemBaseVO { + + // ========== 订单项基本信息 ========== + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long userId; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long orderId; + + // ========== 商品基本信息 ========== + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long spuId; + + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String spuName; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long skuId; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "购买数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + + // ========== 价格 + 支付基本信息 ========== + + @Schema(description = "商品原价(单)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer price; + + @Schema(description = "商品优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer discountPrice; + + @Schema(description = "商品实付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer payPrice; + + @Schema(description = "子订单分摊金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer orderPartPrice; + + @Schema(description = "分摊后子订单实付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer orderDividePrice; + + // ========== 营销基本信息 ========== + + // TODO 芋艿:在捉摸一下 + + // ========== 售后基本信息 ========== + + @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer afterSaleStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageItemRespVO.java new file mode 100644 index 0000000..704067e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageItemRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 交易订单的分页项 Response VO") +@Data +public class TradeOrderPageItemRespVO extends TradeOrderBaseVO { + + @Schema(description = "收件人地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海 上海市 普陀区") + private String receiverAreaName; + + @Schema(description = "订单项列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED) + private MemberUserRespVO user; + + @Schema(description = "推广人信息") + private MemberUserRespVO brokerageUser; + + @Schema(description = "管理后台 - 交易订单的分页项的订单项目") + @Data + public static class Item extends TradeOrderItemBaseVO { + + @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List properties; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java new file mode 100644 index 0000000..074a1e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 交易订单的分页 Request VO") +@Data +public class TradeOrderPageReqVO extends PageParam { + + @Schema(description = "订单号", example = "88888888") + private String no; + + @Schema(description = "用户编号", example = "1024") + private Long userId; + + @Schema(description = "用户昵称", example = "小王") + private String userNickname; + + @Schema(description = "用户手机号", example = "小王") + @Mobile + private String userMobile; + + @Schema(description = "配送方式", example = "1") + private Integer deliveryType; + + @Schema(description = "发货物流公司编号", example = "1") + private Long logisticsId; + + @Schema(description = "自提门店编号", example = "[1,2]") + private List pickUpStoreIds; + + @Schema(description = "自提核销码", example = "12345678") + private String pickUpVerifyCode; + + @Schema(description = "订单类型", example = "1") + private Integer type; + + @Schema(description = "订单状态", example = "1") + @InEnum(value = TradeOrderStatusEnum.class, message = "订单状态必须是 {value}") + private Integer status; + + @Schema(description = "支付渠道", example = "wx_lite") + private String payChannelCode; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "订单来源", example = "10") + @InEnum(value = TerminalEnum.class, message = "订单来源 {value}") + private Integer terminal; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderRemarkReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderRemarkReqVO.java new file mode 100644 index 0000000..4ef8da4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderRemarkReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 订单备注 Request VO") +@Data +public class TradeOrderRemarkReqVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "订单编号不能为空") + private Long id; + + @Schema(description = "商家备注", example = "你猜一下") + @NotEmpty(message = "订单备注不能为空") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderSummaryRespVO.java new file mode 100644 index 0000000..184c8db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderSummaryRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 交易订单统计 Response VO") +@Data +public class TradeOrderSummaryRespVO { + + @Schema(description = "订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long orderCount; + + @Schema(description = "订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long orderPayPrice; + + @Schema(description = "退款单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long afterSaleCount; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long afterSalePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdateAddressReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdateAddressReqVO.java new file mode 100644 index 0000000..b66216b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdateAddressReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 订单修改地址 Request VO") +@Data +public class TradeOrderUpdateAddressReqVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "订单编号不能为空") + private Long id; + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "z张三") + @NotEmpty(message = "收件人名称不能为空") + private String receiverName; + + @Schema(description = "收件人手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "19988188888") + @NotEmpty(message = "收件人手机不能为空") + private String receiverMobile; + + @Schema(description = "收件人地区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7310") + @NotNull(message = "收件人地区编号不能为空") + private Integer receiverAreaId; + + @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "昆明市五华区xxx小区xxx") + @NotEmpty(message = "收件人详细地址不能为空") + private String receiverDetailAddress; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdatePriceReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdatePriceReqVO.java new file mode 100644 index 0000000..d3e0afb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderUpdatePriceReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 订单改价 Request VO") +@Data +public class TradeOrderUpdatePriceReqVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "订单编号不能为空") + private Long id; + + @Schema(description = "订单调价,单位:分。正数,加价;负数,减价", requiredMode = Schema.RequiredMode.REQUIRED, example = "-100") + @NotNull(message = "订单调价价格不能为空") + private Integer adjustPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java new file mode 100644 index 0000000..4874610 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO; +import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 交易售后") +@RestController +@RequestMapping("/trade/after-sale") +@Validated +@Slf4j +public class AppAfterSaleController { + + @Resource + private AfterSaleService afterSaleService; + + @GetMapping(value = "/page") + @Operation(summary = "获得售后分页") + public CommonResult> getAfterSalePage(PageParam pageParam) { + return success(AfterSaleConvert.INSTANCE.convertPage02( + afterSaleService.getAfterSalePage(getLoginUserId(), pageParam))); + } + + @GetMapping(value = "/get") + @Operation(summary = "获得售后订单") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + public CommonResult getAfterSale(@RequestParam("id") Long id) { + return success(AfterSaleConvert.INSTANCE.convert(afterSaleService.getAfterSale(getLoginUserId(), id))); + } + + @PostMapping(value = "/create") + @Operation(summary = "申请售后") + public CommonResult createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) { + return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); + } + + @PutMapping(value = "/delivery") + @Operation(summary = "退回货物") + public CommonResult deliveryAfterSale(@RequestBody AppAfterSaleDeliveryReqVO deliveryReqVO) { + afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO); + return success(true); + } + + @DeleteMapping(value = "/cancel") + @Operation(summary = "取消售后") + @Parameter(name = "id", description = "售后编号", required = true, example = "1") + public CommonResult cancelAfterSale(@RequestParam("id") Long id) { + afterSaleService.cancelAfterSale(getLoginUserId(), id); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleLogController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleLogController.java new file mode 100644 index 0000000..c54ed0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleLogController.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.log.AppAfterSaleLogRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 售后日志") +@RestController +@RequestMapping("/trade/after-sale-log") +@Validated +@Slf4j +public class AppAfterSaleLogController { + + @Resource + private AfterSaleLogService afterSaleLogService; + + @GetMapping("/list") + @Operation(summary = "获得售后日志列表") + @Parameter(name = "afterSaleId", description = "售后编号", required = true, example = "1") + public CommonResult> getAfterSaleLogList( + @RequestParam("afterSaleId") Long afterSaleId) { + List logs = afterSaleLogService.getAfterSaleLogList(afterSaleId); + return success(BeanUtils.toBean(logs, AppAfterSaleLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java new file mode 100644 index 0000000..253db62 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 交易售后创建 Request VO") +@Data +public class AppAfterSaleCreateReqVO { + + @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "售后方式不能为空") + @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}") + private Integer way; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "退款金额不能为空") + @Min(value = 1, message = "退款金额必须大于 0") + private Integer refundPrice; + + @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "申请原因不能为空") + private String applyReason; + + @Schema(description = "补充描述", example = "商品质量不好") + private String applyDescription; + + @Schema(description = "补充凭证图片", example = "https://www.iocoder.cn/1.png, https://www.iocoder.cn/2.png") + private List applyPicUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleDeliveryReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleDeliveryReqVO.java new file mode 100644 index 0000000..83b88d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleDeliveryReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 交易售后退回货物 Request VO") +@Data +public class AppAfterSaleDeliveryReqVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @Schema(description = "退货物流公司编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "退货物流公司编号不能为空") + private Long logisticsId; + + @Schema(description = "退货物流单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SF123456789") + @NotNull(message = "退货物流单号不能为空") + private String logisticsNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleRespVO.java new file mode 100644 index 0000000..1da0595 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleRespVO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 交易售后 Response VO") +@Data +public class AppAfterSaleRespVO { + + @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195") + private String no; + + @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer way; + + @Schema(description = "售后类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String applyReason; + + @Schema(description = "补充描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String applyDescription; + + @Schema(description = "补充凭证图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private List applyPicUrls; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + + // ========== 交易订单相关 ========== + + @Schema(description = "交易订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long orderId; + + @Schema(description = "交易订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String orderNo; + + @Schema(description = "交易订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long orderItemId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long spuId; + + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String spuName; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long skuId; + + /** + * 属性数组 + */ + private List properties; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/01.jpg") + private String picUrl; + + @Schema(description = "退货商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + + // ========== 审批相关 ========== + + /** + * 审批备注 + * + * 注意,只有审批不通过才会填写 + */ + private String auditReason; + + // ========== 退款相关 ========== + + @Schema(description = "退款金额,单位:分", example = "100") + private Integer refundPrice; + + @Schema(description = "退款时间") + private LocalDateTime refundTime; + + // ========== 退货相关 ========== + + @Schema(description = "退货物流公司编号", example = "1") + private Long logisticsId; + + @Schema(description = "退货物流单号", example = "SF123456789") + private String logisticsNo; + + @Schema(description = "退货时间") + private LocalDateTime deliveryTime; + + @Schema(description = "收货时间") + private LocalDateTime receiveTime; + + @Schema(description = "收货备注") + private String receiveReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/log/AppAfterSaleLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/log/AppAfterSaleLogRespVO.java new file mode 100644 index 0000000..4d7fb66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/log/AppAfterSaleLogRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.log; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - App 交易售后日志 Response VO") +@Data +public class AppAfterSaleLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669") + private Long id; + + @Schema(description = "操作明细", requiredMode = Schema.RequiredMode.REQUIRED, example = "维权完成,退款金额:¥37776.00") + private String content; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java new file mode 100644 index 0000000..08acfdb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java @@ -0,0 +1,4 @@ +/** + * 基础包,放一些通用的 VO 类 + */ +package cn.iocoder.yudao.module.trade.controller.app.base; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java new file mode 100644 index 0000000..750f16b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.property; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 商品属性值的明细 Response VO") +@Data +public class AppProductPropertyValueDetailRespVO { + + @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long propertyId; + + @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色") + private String propertyName; + + @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long valueId; + + @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色") + private String valueName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java new file mode 100644 index 0000000..ac0c0ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.sku; + +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 商品 SKU 基础 Response VO + * + * @author 芋道源码 + */ +@Data +public class AppProductSkuBaseRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "图片地址", example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @Schema(description = "销售价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer price; + + @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer stock; + + /** + * 属性数组 + */ + private List properties; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java new file mode 100644 index 0000000..a0e1bc6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.spu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 商品 SPU 基础 Response VO + * + * @author 芋道源码 + */ +@Data +public class AppProductSpuBaseRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "商品 SPU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "商品主图地址", example = "https://www.iocoder.cn/xx.png") + private String picUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java new file mode 100644 index 0000000..212db07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 分销用户") +@RestController +@RequestMapping("/trade/brokerage-record") +@Validated +@Slf4j +public class AppBrokerageRecordController { + @Resource + private BrokerageRecordService brokerageRecordService; + + @GetMapping("/page") + @Operation(summary = "获得分销记录分页") + @PreAuthenticated + public CommonResult> getBrokerageRecordPage(@Valid AppBrokerageRecordPageReqVO pageReqVO) { + PageResult pageResult = brokerageRecordService.getBrokerageRecordPage( + BrokerageRecordConvert.INSTANCE.convert(pageReqVO, getLoginUserId())); + return success(BeanUtils.toBean(pageResult, AppBrokerageRecordRespVO.class)); + } + + @GetMapping("/get-product-brokerage-price") + @Operation(summary = "获得商品的分销金额") + public CommonResult getProductBrokeragePrice(@RequestParam("spuId") Long spuId) { + return success(brokerageRecordService.calculateProductBrokeragePrice(getLoginUserId(), spuId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java new file mode 100644 index 0000000..141ee68 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java @@ -0,0 +1,141 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.*; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageUserConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 分销用户") +@RestController +@RequestMapping("/trade/brokerage-user") +@Validated +@Slf4j +public class AppBrokerageUserController { + + @Resource + private BrokerageUserService brokerageUserService; + @Resource + private BrokerageRecordService brokerageRecordService; + @Resource + private BrokerageWithdrawService brokerageWithdrawService; + + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/get") + @Operation(summary = "获得个人分销信息") + @PreAuthenticated + public CommonResult getBrokerageUser() { + Optional user = Optional.ofNullable(brokerageUserService.getBrokerageUser(getLoginUserId())); + // 返回数据 + AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO() + .setBrokerageEnabled(user.map(BrokerageUserDO::getBrokerageEnabled).orElse(false)) + .setBrokeragePrice(user.map(BrokerageUserDO::getBrokeragePrice).orElse(0)) + .setFrozenPrice(user.map(BrokerageUserDO::getFrozenPrice).orElse(0)); + return success(respVO); + } + + @PutMapping("/bind") + @Operation(summary = "绑定推广员") + @PreAuthenticated + public CommonResult bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) { + return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId())); + } + + @GetMapping("/get-summary") + @Operation(summary = "获得个人分销统计") + @PreAuthenticated + public CommonResult getBrokerageUserSummary() { + // 查询当前登录用户信息 + BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(getLoginUserId()); + // 统计用户昨日的佣金 + LocalDateTime yesterday = LocalDateTime.now().minusDays(1); + LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(yesterday); + LocalDateTime endTime = LocalDateTimeUtil.endOfDay(yesterday); + Integer yesterdayPrice = brokerageRecordService.getSummaryPriceByUserId(brokerageUser.getId(), + BrokerageRecordBizTypeEnum.ORDER, BrokerageRecordStatusEnum.SETTLEMENT, beginTime, endTime); + // 统计用户提现的佣金 + Integer withdrawPrice = brokerageWithdrawService.getWithdrawSummaryListByUserId(Collections.singleton(brokerageUser.getId()), + BrokerageWithdrawStatusEnum.AUDIT_SUCCESS).stream() + .findFirst().map(BrokerageWithdrawSummaryRespBO::getPrice).orElse(0); + // 统计分销用户数量(一级) + Long firstBrokerageUserCount = brokerageUserService.getBrokerageUserCountByBindUserId(brokerageUser.getId(), 1); + // 统计分销用户数量(二级) + Long secondBrokerageUserCount = brokerageUserService.getBrokerageUserCountByBindUserId(brokerageUser.getId(), 2); + + // 拼接返回 + return success(BrokerageUserConvert.INSTANCE.convert(yesterdayPrice, withdrawPrice, firstBrokerageUserCount, secondBrokerageUserCount, brokerageUser)); + } + + @GetMapping("/rank-page-by-user-count") + @Operation(summary = "获得分销用户排行分页(基于用户量)") + @PreAuthenticated + public CommonResult> getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO) { + // 分页查询 + PageResult pageResult = brokerageUserService.getBrokerageUserRankPageByUserCount(pageReqVO); + // 拼接数据 + Map userMap = memberUserApi.getUserMap(convertSet(pageResult.getList(), AppBrokerageUserRankByUserCountRespVO::getId)); + return success(BrokerageUserConvert.INSTANCE.convertPage03(pageResult, userMap)); + } + + @GetMapping("/rank-page-by-price") + @Operation(summary = "获得分销用户排行分页(基于佣金)") + @PreAuthenticated + public CommonResult> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) { + // 分页查询 + PageResult pageResult = brokerageRecordService.getBrokerageUserChildSummaryPageByPrice(pageReqVO); + // 拼接数据 + Map userMap = memberUserApi.getUserMap(convertSet(pageResult.getList(), AppBrokerageUserRankByPriceRespVO::getId)); + return success(BrokerageRecordConvert.INSTANCE.convertPage03(pageResult, userMap)); + } + + @GetMapping("/child-summary-page") + @Operation(summary = "获得下级分销统计分页") + @PreAuthenticated + public CommonResult> getBrokerageUserChildSummaryPage( + AppBrokerageUserChildSummaryPageReqVO pageReqVO) { + PageResult pageResult = brokerageUserService.getBrokerageUserChildSummaryPage(pageReqVO, getLoginUserId()); + return success(pageResult); + } + + @GetMapping("/get-rank-by-price") + @Operation(summary = "获得分销用户排行(基于佣金)") + @Parameter(name = "times", description = "时间段", required = true) + public CommonResult getRankByPrice( + @RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) { + return success(brokerageRecordService.getUserRankByPrice(getLoginUserId(), times)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageWithdrawController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageWithdrawController.java new file mode 100644 index 0000000..b1ef5f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageWithdrawController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 分销提现") +@RestController +@RequestMapping("/trade/brokerage-withdraw") +@Validated +@Slf4j +public class AppBrokerageWithdrawController { + + @Resource + private BrokerageWithdrawService brokerageWithdrawService; + + @GetMapping("/page") + @Operation(summary = "获得分销提现分页") + @PreAuthenticated + public CommonResult> getBrokerageWithdrawPage(AppBrokerageWithdrawPageReqVO pageReqVO) { + PageResult pageResult = brokerageWithdrawService.getBrokerageWithdrawPage( + BrokerageWithdrawConvert.INSTANCE.convert(pageReqVO, getLoginUserId())); + return success(BrokerageWithdrawConvert.INSTANCE.convertPage03(pageResult)); + } + + @PostMapping("/create") + @Operation(summary = "创建分销提现") + @PreAuthenticated + public CommonResult createBrokerageWithdraw(@RequestBody @Valid AppBrokerageWithdrawCreateReqVO createReqVO) { + return success(brokerageWithdrawService.createBrokerageWithdraw(getLoginUserId(), createReqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java new file mode 100644 index 0000000..6b2191d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 商品的分销金额 Response VO") +@Data +public class AppBrokerageProductPriceRespVO { + + @Schema(description = "是否开启", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Boolean enabled; + + @Schema(description = "分销最小金额,单位:分", example = "100") + private Integer brokerageMinPrice; + + @Schema(description = "分销最大金额,单位:分", example = "100") + private Integer brokerageMaxPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordPageReqVO.java new file mode 100644 index 0000000..2100c23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "应用 App - 分销记录分页 Request VO") +@Data +public class AppBrokerageRecordPageReqVO extends PageParam { + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = BrokerageRecordBizTypeEnum.class, message = "业务类型必须是 {value}") + private Integer bizType; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = BrokerageRecordStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordRespVO.java new file mode 100644 index 0000000..993006e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageRecordRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 分销记录 Response VO") +@Data +public class AppBrokerageRecordRespVO { + + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long id; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private String bizId; + + @Schema(description = "分销标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户下单") + private String title; + + @Schema(description = "分销金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer price; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "完成时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime finishTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java new file mode 100644 index 0000000..f2a1499 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserBindReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "应用 App - 绑定推广员 Request VO") +@Data +public class AppBrokerageUserBindReqVO extends PageParam { + + @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "推广员编号不能为空") + private Long bindUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryPageReqVO.java new file mode 100644 index 0000000..890500c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.SortingField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 下级分销统计分页 Request VO") +@Data +public class AppBrokerageUserChildSummaryPageReqVO extends PageParam { + + public static final String SORT_FIELD_USER_COUNT = "userCount"; + public static final String SORT_FIELD_ORDER_COUNT = "orderCount"; + public static final String SORT_FIELD_PRICE = "price"; + + @Schema(description = "用户昵称", example = "李") // 模糊匹配 + private String nickname; + + @Schema(description = "排序字段", example = "userCount") + private SortingField sortingField; + + @Schema(description = "下级的级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 1 - 直接下级;2 - 间接下级 + @NotNull(message = "下级的级别不能为空") + @Range(min = 1, max = 2, message = "下级的级别只能是 {min} 或者 {max}") + private Integer level; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java new file mode 100644 index 0000000..6bc4184 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 下级分销统计 Response VO") +@Data +public class AppBrokerageUserChildSummaryRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + @Schema(description = "佣金金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer brokeragePrice; + + @Schema(description = "分销订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer brokerageOrderCount; + + @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer brokerageUserCount; + + @Schema(description = "绑定推广员的时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime brokerageTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java new file mode 100644 index 0000000..8a0c387 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 个人分销统计 Response VO") +@Data +public class AppBrokerageUserMySummaryRespVO { + + @Schema(description = "昨天的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer yesterdayPrice; + + @Schema(description = "提现的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer withdrawPrice; + + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") + private Integer brokeragePrice; + + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") + private Integer frozenPrice; + + @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long firstBrokerageUserCount; + + @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long secondBrokerageUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java new file mode 100644 index 0000000..91345ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO") +@Data +public class AppBrokerageUserRankByPriceRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + @Schema(description = "佣金金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer brokeragePrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByUserCountRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByUserCountRespVO.java new file mode 100644 index 0000000..1a6de81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByUserCountRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 分销排行用户(基于用户量) Response VO") +@Data +public class AppBrokerageUserRankByUserCountRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + + @Schema(description = "邀请用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer brokerageUserCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankPageReqVO.java new file mode 100644 index 0000000..de1d61a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankPageReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "应用 App - 分销用户排行 Request VO") +@Data +public class AppBrokerageUserRankPageReqVO extends PageParam { + + @Schema(description = "开始 + 结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "时间不能为空") + private LocalDateTime[] times; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java new file mode 100644 index 0000000..f98da7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 分销用户信息 Response VO") +@Data +public class AppBrokerageUserRespVO { + + @Schema(description = "是否有分销资格", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean brokerageEnabled; + + @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") + private Integer brokeragePrice; + + @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") + private Integer frozenPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java new file mode 100644 index 0000000..d49957d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw; + +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.Validator; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.PositiveOrZero; + +@Schema(description = "用户 App - 分销提现创建 Request VO") +@Data +public class AppBrokerageWithdrawCreateReqVO { + + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}") + private Integer type; + + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @PositiveOrZero(message = "提现金额不能小于 0") + @NotNull(message = "提现金额不能为空") + private Integer price; + + // ========== 银行卡、微信、支付宝 提现相关字段 ========== + + @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") + @NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class}) + private String accountNo; + + // ========== 微信、支付宝 提现相关字段 ========== + + @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png") + @URL(message = "收款码的图片,必须是一个 URL") + private String accountQrCodeUrl; + + // ========== 银行卡 提现相关字段 ========== + + @Schema(description = "持卡人姓名", example = "张三") + @NotBlank(message = "持卡人姓名不能为空", groups = {Bank.class}) + private String name; + @Schema(description = "提现银行", example = "1") + @NotNull(message = "提现银行不能为空", groups = {Bank.class}) + private Integer bankName; + @Schema(description = "开户地址", example = "海淀支行") + private String bankAddress; + + public interface Wallet { + } + + public interface Bank { + } + + public interface Wechat { + } + + public interface Alipay { + } + + public void validate(Validator validator) { + if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(type)) { + ValidationUtils.validate(validator, this, Wallet.class); + } else if (BrokerageWithdrawTypeEnum.BANK.getType().equals(type)) { + ValidationUtils.validate(validator, this, Bank.class); + } else if (BrokerageWithdrawTypeEnum.WECHAT.getType().equals(type)) { + ValidationUtils.validate(validator, this, Wechat.class); + } else if (BrokerageWithdrawTypeEnum.ALIPAY.getType().equals(type)) { + ValidationUtils.validate(validator, this, Alipay.class); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawPageReqVO.java new file mode 100644 index 0000000..b1757d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawPageReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "应用 App - 分销提现分页 Request VO") +@Data +public class AppBrokerageWithdrawPageReqVO extends PageParam { + + @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "类型必须是 {value}") + private Integer type; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawRespVO.java new file mode 100644 index 0000000..4cfe930 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 分销提现 Response VO") +@Data +public class AppBrokerageWithdrawRespVO { + + @Schema(description = "提现编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long id; + + @Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer status; + + @Schema(description = "提现状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "审核中") + private String statusName; + + @Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer price; + + @Schema(description = "提现时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.http new file mode 100644 index 0000000..b341a48 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.http @@ -0,0 +1,42 @@ +### 请求 /trade/cart/add 接口 => 成功 +POST {{appApi}}/trade/cart/add +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} +Content-Type: application/json + +{ + "skuId": 1, + "count": 10, + "addStatus": true +} + +### 请求 /trade/cart/update 接口 => 成功 +PUT {{appApi}}/trade/cart/update +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} +Content-Type: application/json + +{ + "id": 35, + "count": 5 +} + +### 请求 /trade/cart/delete 接口 => 成功 +DELETE {{appApi}}/trade/cart/delete?ids=1 +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /trade/cart/get-count 接口 => 成功 +GET {{appApi}}/trade/cart/get-count +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /trade/cart/get-count-map 接口 => 成功 +GET {{appApi}}/trade/cart/get-count-map +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /trade/cart/list 接口 => 成功 +GET {{appApi}}/trade/cart/list +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.java new file mode 100644 index 0000000..2c9d77b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/AppCartController.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.*; +import cn.iocoder.yudao.module.trade.service.cart.CartService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 购物车") +@RestController +@RequestMapping("/trade/cart") +@RequiredArgsConstructor +@Validated +@Slf4j +public class AppCartController { + + @Resource + private CartService cartService; + + @PostMapping("/add") + @Operation(summary = "添加购物车商品") + @PreAuthenticated + public CommonResult addCart(@Valid @RequestBody AppCartAddReqVO addCountReqVO) { + return success(cartService.addCart(getLoginUserId(), addCountReqVO)); + } + + @PutMapping("/update-count") + @Operation(summary = "更新购物车商品数量") + @PreAuthenticated + public CommonResult updateCartCount(@Valid @RequestBody AppCartUpdateCountReqVO updateReqVO) { + cartService.updateCartCount(getLoginUserId(), updateReqVO); + return success(true); + } + + @PutMapping("/update-selected") + @Operation(summary = "更新购物车商品选中") + @PreAuthenticated + public CommonResult updateCartSelected(@Valid @RequestBody AppCartUpdateSelectedReqVO updateReqVO) { + cartService.updateCartSelected(getLoginUserId(), updateReqVO); + return success(true); + } + + @PutMapping("/reset") + @Operation(summary = "重置购物车商品") + @PreAuthenticated + public CommonResult resetCart(@Valid @RequestBody AppCartResetReqVO updateReqVO) { + cartService.resetCart(getLoginUserId(), updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除购物车商品") + @Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048") + @PreAuthenticated + public CommonResult deleteCart(@RequestParam("ids") List ids) { + cartService.deleteCart(getLoginUserId(), ids); + return success(true); + } + + @GetMapping("get-count") + @Operation(summary = "查询用户在购物车中的商品数量") + @PreAuthenticated + public CommonResult getCartCount() { + return success(cartService.getCartCount(getLoginUserId())); + } + + @GetMapping("/list") + @Operation(summary = "查询用户的购物车列表") + @PreAuthenticated + public CommonResult getCartList() { + return success(cartService.getCartList(getLoginUserId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java new file mode 100644 index 0000000..57eb058 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 购物车添加购物项 Request VO") +@Data +public class AppCartAddReqVO { + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "新增商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数量不能为空") + @Min(value = 1, message = "商品数量必须大于等于 1") + private Integer count; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartDetailRespVO.java new file mode 100644 index 0000000..1a28d96 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartDetailRespVO.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 用户的购物车明细 Response VO") +@Data +public class AppCartDetailRespVO { + + /** + * 商品分组数组 + */ + private List itemGroups; + + /** + * 费用 + */ + private Order order; + + @Schema(description = "商品分组") // 多个商品,参加同一个活动,从而形成分组 + @Data + public static class ItemGroup { + + /** + * 商品数组 + */ + private List items; + /** + * 营销活动,订单级别 + */ + private Promotion promotion; + + } + + @Schema(description = "商品 SKU") + @Data + public static class Sku extends AppProductSkuBaseRespVO { + + /** + * SPU 信息 + */ + private AppProductSkuBaseRespVO spu; + + // ========== 购物车相关的字段 ========== + + @Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + @Schema(description = "是否选中", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean selected; + + // ========== 价格相关的字段,对应 PriceCalculateRespDTO.OrderItem 的属性 ========== + + // TODO 芋艿:后续可以去除一些无用的字段 + + @Schema(description = "商品原价(单)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer originalPrice; + @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer totalOriginalPrice; + @Schema(description = "商品级优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "300") + private Integer totalPromotionPrice; + @Schema(description = "最终购买金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "400") + private Integer totalPresentPrice; + @Schema(description = "最终购买金额(单)", requiredMode = Schema.RequiredMode.REQUIRED, example = "500") + private Integer presentPrice; + @Schema(description = "应付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "600") + private Integer totalPayPrice; + + // ========== 营销相关的字段 ========== + /** + * 营销活动,商品级别 + */ + private Promotion promotion; + + } + + @Schema(description = "订单") // 对应 PriceCalculateRespDTO.Order 类,用于费用(合计) + @Data + public static class Order { + + // TODO 芋艿:后续可以去除一些无用的字段 + + @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer skuOriginalPrice; + @Schema(description = "商品优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer skuPromotionPrice; + @Schema(description = "订单优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "300") + private Integer orderPromotionPrice; + @Schema(description = "运费金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "400") + private Integer deliveryPrice; + @Schema(description = "应付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "500") + private Integer payPrice; + + } + + @Schema(description = "营销活动") // 对应 PriceCalculateRespDTO.Promotion 类的属性 + @Data + public static class Promotion { + + @Schema(description = "营销编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") // 营销活动的编号、优惠劵的编号 + private Long id; + @Schema(description = "营销名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "xx 活动") + private String name; + @Schema(description = "营销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + // ========== 匹配情况 ========== + @Schema(description = "是否满足优惠条件", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean meet; + @Schema(description = "满足条件的提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "圣诞价:省 150.00 元") + private String meetTip; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartListRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartListRespVO.java new file mode 100644 index 0000000..cef09f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartListRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 用户的购物列表 Response VO") +@Data +public class AppCartListRespVO { + + /** + * 有效的购物项数组 + */ + private List validList; + + /** + * 无效的购物项数组 + */ + private List invalidList; + + @Schema(description = "购物项") + @Data + public static class Cart { + + @Schema(description = "购物项的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + + @Schema(description = "是否选中", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean selected; + + /** + * 商品 SPU + */ + private AppProductSpuBaseRespVO spu; + /** + * 商品 SKU + */ + private AppProductSkuBaseRespVO sku; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartResetReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartResetReqVO.java new file mode 100644 index 0000000..1ef82c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartResetReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 购物车重置 Request VO") +@Data +public class AppCartResetReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED,example = "1024") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数量不能为空") + @Min(message = "数量必须大于 0", value = 1L) + private Integer count; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateCountReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateCountReqVO.java new file mode 100644 index 0000000..4341d50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateCountReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 购物车更新数量 Request VO") +@Data +public class AppCartUpdateCountReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数量不能为空") + @Min(message = "数量必须大于 0", value = 1L) + private Integer count; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateSelectedReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateSelectedReqVO.java new file mode 100644 index 0000000..3348d2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartUpdateSelectedReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Collection; + +@Schema(description = "用户 App - 购物车更新是否选中 Request VO") +@Data +public class AppCartUpdateSelectedReqVO { + + @Schema(description = "编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024,2048") + @NotNull(message = "编号列表不能为空") + private Collection ids; + + @Schema(description = "是否选中", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否选中不能为空") + private Boolean selected; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/AppTradeConfigController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/AppTradeConfigController.java new file mode 100644 index 0000000..5046c65 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/AppTradeConfigController.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.controller.app.config; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.app.config.vo.AppTradeConfigRespVO; +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 交易配置") +@RestController +@RequestMapping("/trade/config") +@RequiredArgsConstructor +@Validated +@Slf4j +public class AppTradeConfigController { + + @Resource + private TradeConfigService tradeConfigService; + + @Value("${yudao.tencent-lbs-key}") + private String tencentLbsKey; + + @GetMapping("/get") + @Operation(summary = "获得交易配置") + public CommonResult getTradeConfig() { + TradeConfigDO config = ObjUtil.defaultIfNull(tradeConfigService.getTradeConfig(), new TradeConfigDO()); + return success(TradeConfigConvert.INSTANCE.convert02(config).setTencentLbsKey(tencentLbsKey)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/vo/AppTradeConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/vo/AppTradeConfigRespVO.java new file mode 100644 index 0000000..c80472c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/config/vo/AppTradeConfigRespVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.controller.app.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 交易配置 Response VO") +@Data +public class AppTradeConfigRespVO { + + @Schema(description = "腾讯地图 KEY", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String tencentLbsKey; + + // ========== 配送相关 ========== + + @Schema(description = "是否开启自提", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启自提不能为空") + private Boolean deliveryPickUpEnabled; + + // ========== 售后相关 ========== + + @Schema(description = "售后的退款理由", requiredMode = Schema.RequiredMode.REQUIRED) + private List afterSaleRefundReasons; + + @Schema(description = "售后的退货理由", requiredMode = Schema.RequiredMode.REQUIRED) + private List afterSaleReturnReasons; + + // ========== 分销相关 ========== + + @Schema(description = "分销海报地址数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List brokeragePosterUrls; + + @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer brokerageFrozenDays; + + @Schema(description = "佣金提现最小金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer brokerageWithdrawMinPrice; + + @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + private List brokerageWithdrawTypes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverConfigController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverConfigController.java new file mode 100644 index 0000000..1d4e36f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverConfigController.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.app.delivery.vo.config.AppDeliveryConfigRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 配送配置") +@RestController +@RequestMapping("/trade/delivery/config") +@Validated +public class AppDeliverConfigController { + + // TODO @芋艿:这里后面干掉,合并到 AppTradeConfigController 中 + @GetMapping("/get") + @Operation(summary = "获得配送配置") + public CommonResult getDeliveryConfig() { + return success(new AppDeliveryConfigRespVO().setPickUpEnable(true).setTencentLbsKey("123456")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverExpressController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverExpressController.java new file mode 100644 index 0000000..20cdef5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverExpressController.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.app.delivery.vo.express.AppDeliveryExpressRespVO; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 快递公司") +@RestController +@RequestMapping("/trade/delivery/express") +@Validated +public class AppDeliverExpressController { + + @Resource + private DeliveryExpressService deliveryExpressService; + + @GetMapping("/list") + @Operation(summary = "获得快递公司列表") + public CommonResult> getDeliveryExpressList() { + List list = deliveryExpressService.getDeliveryExpressListByStatus(CommonStatusEnum.ENABLE.getStatus()); + list.sort(Comparator.comparing(DeliveryExpressDO::getSort)); + return success(DeliveryExpressConvert.INSTANCE.convertList03(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java new file mode 100644 index 0000000..fcc4993 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.trade.controller.app.delivery.vo.pickup.AppDeliveryPickUpStoreRespVO; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryPickUpStoreConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 自提门店") +@RestController +@RequestMapping("/trade/delivery/pick-up-store") +@Validated +public class AppDeliverPickUpStoreController { + + @Resource + private DeliveryPickUpStoreService deliveryPickUpStoreService; + + @GetMapping("/list") + @Operation(summary = "获得自提门店列表") + @Parameters({ + @Parameter(name = "latitude", description = "精度", example = "110"), + @Parameter(name = "longitude", description = "纬度", example = "120") + }) + public CommonResult> getDeliveryPickUpStoreList( + @RequestParam(value = "latitude", required = false) Double latitude, + @RequestParam(value = "longitude", required = false) Double longitude) { + List list = deliveryPickUpStoreService.getDeliveryPickUpStoreListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + return success(DeliveryPickUpStoreConvert.INSTANCE.convertList(list, latitude, longitude)); + } + + @GetMapping("/get") + @Operation(summary = "获得自提门店") + @Parameter(name = "id", description = "门店编号") + public CommonResult getOrder(@RequestParam("id") Long id) { + DeliveryPickUpStoreDO store = deliveryPickUpStoreService.getDeliveryPickUpStore(id); + return success(DeliveryPickUpStoreConvert.INSTANCE.convert03(store)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/config/AppDeliveryConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/config/AppDeliveryConfigRespVO.java new file mode 100644 index 0000000..f3b50bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/config/AppDeliveryConfigRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +// TODO 芋艿:后续要实现下,配送配置;后续融合到 AppTradeConfigRespVO 中 +@Schema(description = "用户 App - 配送配置 Response VO") +@Data +public class AppDeliveryConfigRespVO { + + @Schema(description = "腾讯地图 KEY", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String tencentLbsKey; + + @Schema(description = "是否开启自提", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean pickUpEnable; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/express/AppDeliveryExpressRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/express/AppDeliveryExpressRespVO.java new file mode 100644 index 0000000..d01d905 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/express/AppDeliveryExpressRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.express; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 快递公司 Response VO") +@Data +public class AppDeliveryExpressRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "顺丰") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/pickup/AppDeliveryPickUpStoreRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/pickup/AppDeliveryPickUpStoreRespVO.java new file mode 100644 index 0000000..1ca25ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/pickup/AppDeliveryPickUpStoreRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.pickup; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 自提门店 Response VO") +@Data +public class AppDeliveryPickUpStoreRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128") + private Long id; + + @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String name; + + @Schema(description = "门店 logo", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String logo; + + @Schema(description = "门店手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601892312") + private String phone; + + @Schema(description = "区域编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18733") + private Integer areaId; + + @Schema(description = "地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海上海市普陀区") + private String areaName; + + @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号") + private String detailAddress; + + @Schema(description = "纬度", requiredMode = Schema.RequiredMode.REQUIRED, example = "5.88") + private Double latitude; + + @Schema(description = "经度", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.99") + private Double longitude; + + @Schema(description = "距离,单位:千米", example = "100") // 只有在用户传递了经纬度时,才进行计算 + private Double distance; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http new file mode 100644 index 0000000..4a94416 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http @@ -0,0 +1,64 @@ +### /trade-order/settlement 获得订单结算信息(基于商品) +GET {{appApi}}/trade/order/settlement?type=0&items[0].skuId=1&items[0].count=2&items[1].skuId=2&items[1].count=3&couponId=1 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### /trade-order/settlement 获得订单结算信息(基于购物车) +GET {{appApi}}/trade/order/settlement?type=0&items[0].cartId=50&couponId=1 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### /trade-order/create 创建订单(基于商品)【快递】 +POST {{appApi}}/trade/order/create +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "pointStatus": true, + "deliveryType": 1, + "addressId": 21, + "items": [ + { + "skuId": 1, + "count": 2 + } + ], + "remark": "我是备注" +} + +### /trade-order/create 创建订单(基于商品)【自提】 +POST {{appApi}}/trade/order/create +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "pointStatus": true, + "deliveryType": 2, + "pickUpStoreId": 1, + "items": [ + { + "skuId": 1, + "count": 2 + } + ], + "remark": "我是备注", + "receiverName": "土豆", + "receiverMobile": "15601691300" +} + +### 获得订单交易的分页 +GET {{appApi}}/trade/order/page?pageNo=1&pageSize=10 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得订单交易的详细 +GET {{appApi}}/trade/order/get-detail?id=21 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得交易订单的物流轨迹 +GET {{appApi}}/trade/order/get-express-track-list?id=70 +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java new file mode 100644 index 0000000..762b238 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -0,0 +1,182 @@ +package cn.iocoder.yudao.module.trade.controller.app.order; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import com.google.common.collect.Maps; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 交易订单") +@RestController +@RequestMapping("/trade/order") +@Validated +@Slf4j +public class AppTradeOrderController { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + @Resource + private DeliveryExpressService deliveryExpressService; + + @Resource + private AfterSaleService afterSaleService; + + @Resource + private TradeOrderProperties tradeOrderProperties; + + @GetMapping("/settlement") + @Operation(summary = "获得订单结算信息") + @PreAuthenticated + public CommonResult settlementOrder(@Valid AppTradeOrderSettlementReqVO settlementReqVO) { + return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO)); + } + + @PostMapping("/create") + @Operation(summary = "创建订单") + @PreAuthenticated + public CommonResult createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) { + TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO); + return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); + } + + @PostMapping("/update-paid") + @Operation(summary = "更新订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + public CommonResult updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { + tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), + notifyReqDTO.getPayOrderId()); + return success(true); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得交易订单") + @Parameter(name = "id", description = "交易订单编号") + public CommonResult getOrder(@RequestParam("id") Long id) { + // 查询订单 + TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); + if (order == null) { + return success(null); + } + + // 查询订单项 + List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId()); + // 查询物流公司 + DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ? + deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null; + // 最终组合 + return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems, tradeOrderProperties, express)); + } + + @GetMapping("/get-express-track-list") + @Operation(summary = "获得交易订单的物流轨迹") + @Parameter(name = "id", description = "交易订单编号") + public CommonResult> getOrderExpressTrackList(@RequestParam("id") Long id) { + return success(TradeOrderConvert.INSTANCE.convertList02( + tradeOrderQueryService.getExpressTrackList(id, getLoginUserId()))); + } + + @GetMapping("/page") + @Operation(summary = "获得交易订单分页") + public CommonResult> getOrderPage(AppTradeOrderPageReqVO reqVO) { + // 查询订单 + PageResult pageResult = tradeOrderQueryService.getOrderPage(getLoginUserId(), reqVO); + // 查询订单项 + List orderItems = tradeOrderQueryService.getOrderItemListByOrderId( + convertSet(pageResult.getList(), TradeOrderDO::getId)); + // 最终组合 + return success(TradeOrderConvert.INSTANCE.convertPage02(pageResult, orderItems)); + } + + @GetMapping("/get-count") + @Operation(summary = "获得交易订单数量") + public CommonResult> getOrderCount() { + Map orderCount = Maps.newLinkedHashMapWithExpectedSize(5); + // 全部 + orderCount.put("allCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), null, null)); + // 待付款(未支付) + orderCount.put("unpaidCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), + TradeOrderStatusEnum.UNPAID.getStatus(), null)); + // 待发货 + orderCount.put("undeliveredCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), + TradeOrderStatusEnum.UNDELIVERED.getStatus(), null)); + // 待收货 + orderCount.put("deliveredCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), + TradeOrderStatusEnum.DELIVERED.getStatus(), null)); + // 待评价 + orderCount.put("uncommentedCount", tradeOrderQueryService.getOrderCount(getLoginUserId(), + TradeOrderStatusEnum.COMPLETED.getStatus(), false)); + // 售后数量 + orderCount.put("afterSaleCount", afterSaleService.getApplyingAfterSaleCount(getLoginUserId())); + return success(orderCount); + } + + @PutMapping("/receive") + @Operation(summary = "确认交易订单收货") + @Parameter(name = "id", description = "交易订单编号") + public CommonResult receiveOrder(@RequestParam("id") Long id) { + tradeOrderUpdateService.receiveOrderByMember(getLoginUserId(), id); + return success(true); + } + + @DeleteMapping("/cancel") + @Operation(summary = "取消交易订单") + @Parameter(name = "id", description = "交易订单编号") + public CommonResult cancelOrder(@RequestParam("id") Long id) { + tradeOrderUpdateService.cancelOrderByMember(getLoginUserId(), id); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除交易订单") + @Parameter(name = "id", description = "交易订单编号") + public CommonResult deleteOrder(@RequestParam("id") Long id) { + tradeOrderUpdateService.deleteOrder(getLoginUserId(), id); + return success(true); + } + + // ========== 订单项 ========== + + @GetMapping("/item/get") + @Operation(summary = "获得交易订单项") + @Parameter(name = "id", description = "交易订单项编号") + public CommonResult getOrderItem(@RequestParam("id") Long id) { + TradeOrderItemDO item = tradeOrderQueryService.getOrderItem(getLoginUserId(), id); + return success(TradeOrderConvert.INSTANCE.convert03(item)); + } + + @PostMapping("/item/create-comment") + @Operation(summary = "创建交易订单项的评价") + public CommonResult createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) { + return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppOrderExpressTrackRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppOrderExpressTrackRespDTO.java new file mode 100644 index 0000000..2324c40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppOrderExpressTrackRespDTO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 快递查询的轨迹 Resp DTO + * + * @author jason + */ +@Schema(description = "用户 App - 快递查询的轨迹 Response VO") +@Data +public class AppOrderExpressTrackRespDTO { + + @Schema(description = "发生时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime time; + + @Schema(description = "快递状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "已签收") + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java new file mode 100644 index 0000000..2f4503d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; + +@Schema(description = "用户 App - 交易订单创建 Request VO") +@Data +public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO { + + @Schema(description = "备注", example = "这个是我的订单哟") + private String remark; + + @AssertTrue(message = "配送方式不能为空") + @JsonIgnore + public boolean isDeliveryTypeNotNull() { + return getDeliveryType() != null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateRespVO.java new file mode 100644 index 0000000..ae3f831 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 交易订单创建 Response VO") +@Data +public class AppTradeOrderCreateRespVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long payOrderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java new file mode 100644 index 0000000..b91bbf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java @@ -0,0 +1,151 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 订单交易的明细 Response VO") +@Data +public class AppTradeOrderDetailRespVO { + + // ========== 订单基本信息 ========== + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195") + private String no; + + @Schema(description = "订单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer type; + + @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "用户备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String userRemark; + + @Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer productCount; + + @Schema(description = "订单完成时间") + private LocalDateTime finishTime; + + @Schema(description = "订单取消时间") + private LocalDateTime cancelTime; + + @Schema(description = "是否评价", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean commentStatus; + + // ========== 价格 + 支付基本信息 ========== + + @Schema(description = "是否已支付", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean payStatus; + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long payOrderId; + + @Schema(description = "付款时间") + private LocalDateTime payTime; + + @Schema(description = "付款超时时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime payExpireTime; + + @Schema(description = "支付渠道", example = "wx_lite_pay") + private String payChannelCode; + @Schema(description = "支付渠道名", example = "微信小程序支付") + private String payChannelName; + + @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer totalPrice; + + @Schema(description = "订单优惠(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer discountPrice; + + @Schema(description = "运费金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer deliveryPrice; + + @Schema(description = "订单调价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer adjustPrice; + + @Schema(description = "应付金额(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer payPrice; + + // ========== 收件 + 物流基本信息 ========== + + @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer deliveryType; + + @Schema(description = "发货物流公司编号", example = "10") + private Long logisticsId; + + @Schema(description = "发货物流名称", example = "顺丰快递") + private String logisticsName; + + @Schema(description = "发货物流单号", example = "1024") + private String logisticsNo; + + @Schema(description = "发货时间") + private LocalDateTime deliveryTime; + + @Schema(description = "收货时间") + private LocalDateTime receiveTime; + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String receiverName; + + @Schema(description = "收件人手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "13800138000") + private String receiverMobile; + + @Schema(description = "收件人地区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer receiverAreaId; + + @Schema(description = "收件人地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海 上海市 普陀区") + private String receiverAreaName; + + @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "中关村大街 1 号") + private String receiverDetailAddress; + + @Schema(description = "自提门店编号", example = "1088") + private Long pickUpStoreId; + + @Schema(description = "自提核销码", example = "40964096") + private String pickUpVerifyCode; + + // ========== 售后基本信息 ========== + + @Schema(description = "售后状态", example = "0") + private Integer refundStatus; + + @Schema(description = "退款金额,单位:分", example = "100") + private Integer refundPrice; + + // ========== 营销基本信息 ========== + + @Schema(description = "优惠劵编号", example = "1024") + private Long couponId; + + @Schema(description = "优惠劵减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer couponPrice; + + @Schema(description = "积分抵扣的金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer pointPrice; + + @Schema(description = "VIP 减免金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Integer vipPrice; + + @Schema(description = "拼团记录编号", example = "100") + private Long combinationRecordId; + + /** + * 订单项数组 + */ + private List items; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageItemRespVO.java new file mode 100644 index 0000000..ba7b813 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageItemRespVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "用户 App - 订单交易的分页项 Response VO") +@Data +public class AppTradeOrderPageItemRespVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1146347329394184195") + private String no; + + @Schema(description = "订单类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer type; + + @Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "购买的商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer productCount; + + @Schema(description = "是否评价", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean commentStatus; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 价格 + 支付基本信息 ========== + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long payOrderId; + + @Schema(description = "应付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer payPrice; + + // ========== 收件 + 物流基本信息 ========== + + @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer deliveryType; + + /** + * 订单项数组 + */ + private List items; + + // ========== 营销基本信息 ========== + + @Schema(description = "拼团记录编号", example = "100") + private Long combinationRecordId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageReqVO.java new file mode 100644 index 0000000..c1e07c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderPageReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "交易订单分页 Request VO") +@Data +public class AppTradeOrderPageReqVO extends PageParam { + + @Schema(description = "订单状态", example = "1") + @InEnum(value = TradeOrderStatusEnum.class, message = "订单状态必须是 {value}") + private Integer status; + + @Schema(description = "是否评价", example = "true") + private Boolean commentStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java new file mode 100644 index 0000000..e8ed038 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 交易订单结算 Request VO") +@Data +@Valid +public class AppTradeOrderSettlementReqVO { + + @Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "商品不能为空") + private List items; + + @Schema(description = "优惠劵编号", example = "1024") + private Long couponId; + + @Schema(description = "是否使用积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否使用积分不能为空") + private Boolean pointStatus; + + // ========== 配送相关相关字段 ========== + @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = DeliveryTypeEnum.class, message = "配送方式不正确") + private Integer deliveryType; + + @Schema(description = "收件地址编号", example = "1") + private Long addressId; + + @Schema(description = "自提门店编号", example = "1088") + private Long pickUpStoreId; + @Schema(description = "收件人名称", example = "芋艿") // 选择门店自提时,该字段为联系人名 + private String receiverName; + @Schema(description = "收件人手机", example = "15601691300") // 选择门店自提时,该字段为联系人手机 + @Mobile(message = "收件人手机格式不正确") + private String receiverMobile; + + // ========== 秒杀活动相关字段 ========== + @Schema(description = "秒杀活动编号", example = "1024") + private Long seckillActivityId; + + // ========== 拼团活动相关字段 ========== + @Schema(description = "拼团活动编号", example = "1024") + private Long combinationActivityId; + + @Schema(description = "拼团团长编号", example = "2048") + private Long combinationHeadId; + + // ========== 砍价活动相关字段 ========== + @Schema(description = "砍价记录编号", example = "123") + private Long bargainRecordId; + + @AssertTrue(message = "活动商品每次只能购买一种规格") + @JsonIgnore + public boolean isValidActivityItems() { + // 校验是否是活动订单 + if (ObjUtil.isAllEmpty(seckillActivityId, combinationActivityId, combinationHeadId, bargainRecordId)) { + return true; + } + // 校验订单项是否超出 + return items.size() == 1; + } + + @Data + @Schema(description = "用户 App - 商品项") + @Valid + public static class Item { + + @Schema(description = "商品 SKU 编号", example = "2048") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "购买数量", example = "1") + @Min(value = 1, message = "购买数量最小值为 {value}") + private Integer count; + + @Schema(description = "购物车项的编号", example = "1024") + private Long cartId; + + @AssertTrue(message = "商品不正确") + @JsonIgnore + public boolean isValid() { + // 组合一:skuId + count 使用商品 SKU + if (skuId != null && count != null) { + return true; + } + // 组合二:cartId 使用购物车项 + return cartId != null; + } + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java new file mode 100644 index 0000000..0c851bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java @@ -0,0 +1,125 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "用户 App - 交易订单结算信息 Response VO") +@Data +public class AppTradeOrderSettlementRespVO { + + @Schema(description = "交易类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 对应 TradeOrderTypeEnum 枚举 + private Integer type; + + @Schema(description = "购物项数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List items; + + @Schema(description = "费用", requiredMode = Schema.RequiredMode.REQUIRED) + private Price price; + + @Schema(description = "收件地址", requiredMode = Schema.RequiredMode.REQUIRED) + private Address address; + + @Schema(description = "已使用的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer usedPoint; + + @Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer totalPoint; + + @Schema(description = "购物项") + @Data + public static class Item { + + // ========== SPU 信息 ========== + + @Schema(description = "品类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long categoryId; + @Schema(description = "SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long spuId; + @Schema(description = "SPU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "Apple iPhone 12") + private String spuName; + + // ========== SKU 信息 ========== + + @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer skuId; + @Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer price; + @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "属性数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private List properties; + + // ========== 购物车信息 ========== + + @Schema(description = "购物车编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long cartId; + + @Schema(description = "购买数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + + } + + @Schema(description = "费用(合计)") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Price { + + @Schema(description = "商品原价(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "500") + private Integer totalPrice; + + @Schema(description = "订单优惠(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") + private Integer discountPrice; + + @Schema(description = "运费金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer deliveryPrice; + + @Schema(description = "优惠劵减免金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer couponPrice; + + @Schema(description = "积分抵扣的金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer pointPrice; + + @Schema(description = "VIP 减免金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer vipPrice; + + @Schema(description = "实际支付金额(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "450") + private Integer payPrice; + + } + + @Schema(description = "地址信息") + @Data + public static class Address { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小王") + private String name; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + private String mobile; + + @Schema(description = "地区编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "地区编号不能为空") + private Long areaId; + @Schema(description = "地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海上海市普陀区") + private String areaName; + + @Schema(description = "详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "望京悠乐汇 A 座") + private String detailAddress; + + @Schema(description = "是否默认收件地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean defaultStatus; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java new file mode 100644 index 0000000..a6a8b95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo.item; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Schema(description = "用户 App - 商品评价创建 Request VO") +@Data +public class AppTradeOrderItemCommentCreateReqVO { + + @Schema(description = "是否匿名", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否匿名不能为空") + private Boolean anonymous; + + @Schema(description = "交易订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2312312") + @NotNull(message = "交易订单项编号不能为空") + private Long orderItemId; + + @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "描述星级 1-5 分不能为空") + private Integer descriptionScores; + + @Schema(description = "服务星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "服务星级 1-5 分不能为空") + private Integer benefitScores; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "穿身上很漂亮诶(*^▽^*)") + @NotNull(message = "评论内容不能为空") + private String content; + + @Schema(description = "评论图片地址数组,以逗号分隔最多上传 9 张", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]") + @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张") + private List picUrls; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java new file mode 100644 index 0000000..98d1820 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.trade.controller.app.order.vo.item; + +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 订单交易项 Response VO") +@Data +public class AppTradeOrderItemRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long orderId; + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long spuId; + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String spuName; + + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long skuId; + + /** + * 属性数组 + */ + private List properties; + + @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "购买数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + + @Schema(description = "是否评价", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean commentStatus; + + // ========== 价格 + 支付基本信息 ========== + + @Schema(description = "商品原价(单)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer price; + + @Schema(description = "应付金额(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer payPrice; + + // ========== 营销基本信息 ========== + + // TODO 芋艿:在捉摸一下 + + // ========== 售后基本信息 ========== + + @Schema(description = "售后编号", example = "1024") + private Long afterSaleId; + + @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer afterSaleStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/package-info.java new file mode 100644 index 0000000..aa2f99f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.trade.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java new file mode 100644 index 0000000..fd759c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.trade.convert.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRespPageItemVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface AfterSaleConvert { + + AfterSaleConvert INSTANCE = Mappers.getMapper(AfterSaleConvert.class); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(target = "createTime", ignore = true), + @Mapping(target = "updateTime", ignore = true), + @Mapping(target = "creator", ignore = true), + @Mapping(target = "updater", ignore = true), + }) + AfterSaleDO convert(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + + @Mappings({ + @Mapping(source = "afterSale.orderId", target = "merchantOrderId"), + @Mapping(source = "afterSale.id", target = "merchantRefundId"), + @Mapping(source = "afterSale.applyReason", target = "reason"), + @Mapping(source = "afterSale.refundPrice", target = "price") + }) + PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale, + TradeOrderProperties orderProperties); + + MemberUserRespVO convert(MemberUserRespDTO bean); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult pageResult, + Map memberUsers) { + PageResult voPageResult = convertPage(pageResult); + // 处理会员 + voPageResult.getList().forEach(afterSale -> afterSale.setUser( + convert(memberUsers.get(afterSale.getUserId())))); + return voPageResult; + } + + ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); + + AppAfterSaleRespVO convert(AfterSaleDO bean); + + PageResult convertPage02(PageResult page); + + default AfterSaleDetailRespVO convert(AfterSaleDO afterSale, TradeOrderDO order, TradeOrderItemDO orderItem, + MemberUserRespDTO user, List logs) { + AfterSaleDetailRespVO respVO = convert02(afterSale); + // 处理用户信息 + respVO.setUser(convert(user)); + // 处理订单信息 + respVO.setOrder(convert(order)); + respVO.setOrderItem(convert02(orderItem)); + // 处理售后日志 + respVO.setLogs(convertList1(logs)); + return respVO; + } + + List convertList1(List list); + AfterSaleDetailRespVO convert02(AfterSaleDO bean); + AfterSaleDetailRespVO.OrderItem convert02(TradeOrderItemDO bean); + TradeOrderBaseVO convert(TradeOrderDO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleLogConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleLogConvert.java new file mode 100644 index 0000000..e8960c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleLogConvert.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.trade.convert.aftersale; + +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface AfterSaleLogConvert { + + AfterSaleLogConvert INSTANCE = Mappers.getMapper(AfterSaleLogConvert.class); + + AfterSaleLogDO convert(AfterSaleLogCreateReqBO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageRecordConvert.java new file mode 100644 index 0000000..0f1fe61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageRecordConvert.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.trade.convert.brokerage; + +import cn.hutool.core.math.Money; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByPriceRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 佣金记录 Convert + * + * @author owen + */ +@Mapper +public interface BrokerageRecordConvert { + + BrokerageRecordConvert INSTANCE = Mappers.getMapper(BrokerageRecordConvert.class); + + BrokerageRecordRespVO convert(BrokerageRecordDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, + Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, + String title, Long sourceUserId, Integer sourceUserLevel) { + brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); + // 不冻结时,佣金直接就是结算状态 + Integer status = brokerageFrozenDays > 0 + ? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus() + : BrokerageRecordStatusEnum.SETTLEMENT.getStatus(); + return new BrokerageRecordDO().setUserId(user.getId()) + .setBizType(bizType.getType()).setBizId(bizId) + .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice()) + .setTitle(title) + .setDescription(StrUtil.format(bizType.getDescription(), MoneyUtils.fenToYuanStr(Math.abs(brokeragePrice)))) + .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime) + .setSourceUserLevel(sourceUserLevel).setSourceUserId(sourceUserId); + } + + default PageResult convertPage(PageResult pageResult, Map userMap) { + PageResult result = convertPage(pageResult); + for (BrokerageRecordRespVO respVO : result.getList()) { + Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user -> + respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar())); + Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user -> + respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar())); + } + return result; + } + + BrokerageRecordPageReqVO convert(AppBrokerageRecordPageReqVO pageReqVO, Long userId); + + default PageResult convertPage03(PageResult pageResult, Map userMap) { + for (AppBrokerageUserRankByPriceRespVO vo : pageResult.getList()) { + copyTo(userMap.get(vo.getId()), vo); + } + return pageResult; + } + + void copyTo(MemberUserRespDTO from, @MappingTarget AppBrokerageUserRankByPriceRespVO to); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java new file mode 100644 index 0000000..aa4ba34 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageUserConvert.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.trade.convert.brokerage; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserMySummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 分销用户 Convert + * + * @author owen + */ +@Mapper +public interface BrokerageUserConvert { + + BrokerageUserConvert INSTANCE = Mappers.getMapper(BrokerageUserConvert.class); + + BrokerageUserRespVO convert(BrokerageUserDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page, Map userMap, Map brokerageUserCountMap, Map userOrderSummaryMap); + + default PageResult convertPage(PageResult pageResult, + Map userMap, + Map brokerageUserCountMap, + Map userOrderSummaryMap, + Map withdrawMap) { + PageResult result = convertPage(pageResult, userMap, brokerageUserCountMap, userOrderSummaryMap); + for (BrokerageUserRespVO userVO : result.getList()) { + // 用户信息 + copyTo(userMap.get(userVO.getId()), userVO); + // 推广用户数量 + userVO.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, userVO.getId(), 0)); + // 推广订单数量、推广订单金额 + Optional orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(userVO.getId())); + userVO.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryRespBO::getCount).orElse(0)) + .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryRespBO::getPrice).orElse(0)); + // 已提现次数、已提现金额 + Optional withdrawSummaryOptional = Optional.ofNullable(withdrawMap.get(userVO.getId())); + userVO.setWithdrawCount(withdrawSummaryOptional.map(BrokerageWithdrawSummaryRespBO::getCount).orElse(0)) + .setWithdrawPrice(withdrawSummaryOptional.map(BrokerageWithdrawSummaryRespBO::getPrice).orElse(0)); + } + return result; + } + + default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) { + Optional.ofNullable(source).ifPresent( + user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar())); + return target; + } + + default PageResult convertPage03(PageResult pageResult, + Map userMap) { + pageResult.getList().forEach(vo -> copyTo(userMap.get(vo.getId()), vo)); + return pageResult; + } + + void copyTo(MemberUserRespDTO from, @MappingTarget AppBrokerageUserRankByUserCountRespVO to); + + default AppBrokerageUserMySummaryRespVO convert(Integer yesterdayPrice, Integer withdrawPrice, + Long firstBrokerageUserCount, Long secondBrokerageUserCount, + BrokerageUserDO brokerageUser) { + AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO() + .setYesterdayPrice(ObjUtil.defaultIfNull(yesterdayPrice, 0)) + .setWithdrawPrice(ObjUtil.defaultIfNull(withdrawPrice, 0)) + .setBrokeragePrice(0).setFrozenPrice(0) + .setFirstBrokerageUserCount(ObjUtil.defaultIfNull(firstBrokerageUserCount, 0L)) + .setSecondBrokerageUserCount(ObjUtil.defaultIfNull(secondBrokerageUserCount, 0L)); + // 设置 brokeragePrice、frozenPrice 字段 + Optional.ofNullable(brokerageUser) + .ifPresent(user -> respVO.setBrokeragePrice(user.getBrokeragePrice()).setFrozenPrice(user.getFrozenPrice())); + return respVO; + } + + default void copyTo(List list, Map userMap) { + for (AppBrokerageUserChildSummaryRespVO vo : list) { + Optional.ofNullable(userMap.get(vo.getId())).ifPresent(user -> + vo.setNickname(user.getNickname()).setAvatar(user.getAvatar())); + } + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java new file mode 100644 index 0000000..4b818af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.trade.convert.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.enums.DictTypeConstants; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 佣金提现 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BrokerageWithdrawConvert { + + BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class); + + BrokerageWithdrawDO convert(AppBrokerageWithdrawCreateReqVO createReqVO, Long userId, Integer feePrice); + + BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult pageResult, Map userMap) { + PageResult result = convertPage(pageResult); + for (BrokerageWithdrawRespVO vo : result.getList()) { + vo.setUserNickname(Optional.ofNullable(userMap.get(vo.getUserId())).map(MemberUserRespDTO::getNickname).orElse(null)); + } + return result; + } + + PageResult convertPage02(PageResult pageResult); + + default PageResult convertPage03(PageResult pageResult) { + PageResult result = convertPage02(pageResult); + for (AppBrokerageWithdrawRespVO vo : result.getList()) { + vo.setStatusName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_WITHDRAW_STATUS, vo.getStatus())); + } + return result; + } + + BrokerageWithdrawPageReqVO convert(AppBrokerageWithdrawPageReqVO pageReqVO, Long userId); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java new file mode 100644 index 0000000..83cd459 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.trade.convert.cart; + +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppCartListRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +@Mapper +public interface TradeCartConvert { + + TradeCartConvert INSTANCE = Mappers.getMapper(TradeCartConvert.class); + + default AppCartListRespVO convertList(List carts, + List spus, List skus) { + Map spuMap = convertMap(spus, ProductSpuRespDTO::getId); + Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); + // 遍历,开始转换 + List validList = new ArrayList<>(carts.size()); + List invalidList = new ArrayList<>(); + carts.forEach(cart -> { + AppCartListRespVO.Cart cartVO = new AppCartListRespVO.Cart(); + cartVO.setId(cart.getId()).setCount(cart.getCount()).setSelected(cart.getSelected()); + ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); + ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); + cartVO.setSpu(convert(spu)).setSku(convert(sku)); + // 如果 SPU 不存在,或者下架,或者库存不足,说明是无效的 + if (spu == null + || !ProductSpuStatusEnum.isEnable(spu.getStatus()) + || spu.getStock() <= 0) { + cartVO.setSelected(false); // 强制设置成不可选中 + invalidList.add(cartVO); + } else { + // 虽然 SKU 可能也会不存在,但是可以通过购物车重新选择 + validList.add(cartVO); + } + }); + return new AppCartListRespVO().setValidList(validList).setInvalidList(invalidList); + } + AppProductSpuBaseRespVO convert(ProductSpuRespDTO spu); + AppProductSkuBaseRespVO convert(ProductSkuRespDTO sku); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/config/TradeConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/config/TradeConfigConvert.java new file mode 100644 index 0000000..57da020 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/config/TradeConfigConvert.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.convert.config; + +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; +import cn.iocoder.yudao.module.trade.controller.app.config.vo.AppTradeConfigRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 交易中心配置 Convert + * + * @author owen + */ +@Mapper +public interface TradeConfigConvert { + + TradeConfigConvert INSTANCE = Mappers.getMapper(TradeConfigConvert.class); + + TradeConfigDO convert(TradeConfigSaveReqVO bean); + + TradeConfigRespVO convert(TradeConfigDO bean); + + AppTradeConfigRespVO convert02(TradeConfigDO tradeConfig); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressConvert.java new file mode 100644 index 0000000..3910dca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressConvert.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.trade.convert.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.*; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExcelVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.delivery.vo.express.AppDeliveryExpressRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface DeliveryExpressConvert { + + DeliveryExpressConvert INSTANCE = Mappers.getMapper(DeliveryExpressConvert.class); + + DeliveryExpressDO convert(DeliveryExpressCreateReqVO bean); + + DeliveryExpressDO convert(DeliveryExpressUpdateReqVO bean); + + DeliveryExpressRespVO convert(DeliveryExpressDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + + List convertList1(List list); + + List convertList03(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java new file mode 100644 index 0000000..b917d87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.trade.convert.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; +import com.google.common.collect.Maps; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; + +@Mapper +public interface DeliveryExpressTemplateConvert { + + DeliveryExpressTemplateConvert INSTANCE = Mappers.getMapper(DeliveryExpressTemplateConvert.class); + + // ========== Template ========== + + DeliveryExpressTemplateDO convert(DeliveryExpressTemplateCreateReqVO bean); + + DeliveryExpressTemplateDO convert(DeliveryExpressTemplateUpdateReqVO bean); + + DeliveryExpressTemplateRespVO convert(DeliveryExpressTemplateDO bean); + + DeliveryExpressTemplateDetailRespVO convert2(DeliveryExpressTemplateDO bean); + + List convertList(List list); + + List convertList1(List list); + + PageResult convertPage(PageResult page); + + default DeliveryExpressTemplateDetailRespVO convert(DeliveryExpressTemplateDO bean, + List chargeList, + List freeList) { + DeliveryExpressTemplateDetailRespVO respVO = convert2(bean); + respVO.setCharges(convertTemplateChargeList(chargeList)); + respVO.setFrees(convertTemplateFreeList(freeList)); + return respVO; + } + + // ========== Template Charge ========== + + DeliveryExpressTemplateChargeDO convertTemplateCharge(Long templateId, Integer chargeMode, DeliveryExpressTemplateChargeBaseVO vo); + + DeliveryExpressTemplateRespBO.Charge convertTemplateCharge(DeliveryExpressTemplateChargeDO bean); + + default List convertTemplateChargeList(Long templateId, Integer chargeMode, List list) { + return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo)); + } + + // ========== Template Free ========== + + DeliveryExpressTemplateFreeDO convertTemplateFree(Long templateId, DeliveryExpressTemplateFreeBaseVO vo); + + DeliveryExpressTemplateRespBO.Free convertTemplateFree(DeliveryExpressTemplateFreeDO bean); + + List convertTemplateChargeList(List list); + + List convertTemplateFreeList(List list); + + default List convertTemplateFreeList(Long templateId, List list) { + return CollectionUtils.convertList(list, vo -> convertTemplateFree(templateId, vo)); + } + + default Map convertMap(Integer areaId, List templateList, + List chargeList, + List freeList) { + Map> templateIdChargeMap = convertMultiMap(chargeList, + DeliveryExpressTemplateChargeDO::getTemplateId); + Map> templateIdFreeMap = convertMultiMap(freeList, + DeliveryExpressTemplateFreeDO::getTemplateId); + // 组合运费模板配置 RespBO + Map result = Maps.newHashMapWithExpectedSize(templateList.size()); + templateList.forEach(template -> { + DeliveryExpressTemplateRespBO bo = new DeliveryExpressTemplateRespBO() + .setChargeMode(template.getChargeMode()) + .setCharge(convertTemplateCharge(findFirst(templateIdChargeMap.get(template.getId()), charge -> charge.getAreaIds().contains(areaId)))) + .setFree(convertTemplateFree(findFirst(templateIdFreeMap.get(template.getId()), free -> free.getAreaIds().contains(areaId)))); + result.put(template.getId(), bo); + }); + return result; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java new file mode 100644 index 0000000..1d5b360 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.trade.convert.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreSimpleRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreUpdateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.delivery.vo.pickup.AppDeliveryPickUpStoreRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface DeliveryPickUpStoreConvert { + + DeliveryPickUpStoreConvert INSTANCE = Mappers.getMapper(DeliveryPickUpStoreConvert.class); + + DeliveryPickUpStoreDO convert(DeliveryPickUpStoreCreateReqVO bean); + + DeliveryPickUpStoreDO convert(DeliveryPickUpStoreUpdateReqVO bean); + + DeliveryPickUpStoreRespVO convert(DeliveryPickUpStoreDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList1(List list); + @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName") + DeliveryPickUpStoreSimpleRespVO convert02(DeliveryPickUpStoreDO bean); + + @Named("convertAreaIdToAreaName") + default String convertAreaIdToAreaName(Integer areaId) { + return AreaUtils.format(areaId); + } + + default List convertList(List list, + Double latitude, Double longitude) { + List voList = CollectionUtils.convertList(list, store -> { + AppDeliveryPickUpStoreRespVO storeVO = convert03(store); + if (latitude != null && longitude != null) { + storeVO.setDistance(NumberUtils.getDistance(latitude, longitude, storeVO.getLatitude(), storeVO.getLongitude())); + } + return storeVO; + }); + return voList; + } + @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName") + AppDeliveryPickUpStoreRespVO convert03(DeliveryPickUpStoreDO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java new file mode 100644 index 0000000..64f74c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -0,0 +1,288 @@ +package cn.iocoder.yudao.module.trade.convert.order; + +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*; +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; + +@Mapper +public interface TradeOrderConvert { + + TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(source = "userId", target = "userId"), + @Mapping(source = "createReqVO.couponId", target = "couponId"), + @Mapping(target = "remark", ignore = true), + @Mapping(source = "createReqVO.remark", target = "userRemark"), + @Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"), + @Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"), + @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"), + @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"), + @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"), + @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"), + @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice") + }) + TradeOrderDO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO); + + TradeOrderRespDTO convert(TradeOrderDO orderDO); + + default List convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { + return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { + TradeOrderItemDO orderItem = convert(item); + orderItem.setOrderId(tradeOrderDO.getId()); + orderItem.setUserId(tradeOrderDO.getUserId()); + orderItem.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + orderItem.setCommentStatus(false); + return orderItem; + }); + } + + TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item); + + default ProductSkuUpdateStockReqDTO convert(List list) { + List items = CollectionUtils.convertList(list, item -> + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount())); + return new ProductSkuUpdateStockReqDTO(items); + } + + default ProductSkuUpdateStockReqDTO convertNegative(List list) { + List items = CollectionUtils.convertList(list, item -> + new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount())); + return new ProductSkuUpdateStockReqDTO(items); + } + + default PayOrderCreateReqDTO convert(TradeOrderDO order, List orderItems, + TradeOrderProperties orderProperties) { + PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() + .setAppId(orderProperties.getAppId()).setUserIp(order.getUserIp()); + // 商户相关字段 + createReqDTO.setMerchantOrderId(String.valueOf(order.getId())); + String subject = orderItems.get(0).getSpuName(); + subject = StrUtils.maxLength(subject, PayOrderCreateReqDTO.SUBJECT_MAX_LENGTH); // 避免超过 32 位 + createReqDTO.setSubject(subject); + createReqDTO.setBody(subject); // TODO 芋艿:临时写死 + // 订单相关字段 + createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getPayExpireTime())); + return createReqDTO; + } + + default PageResult convertPage(PageResult pageResult, + List orderItems, + Map memberUserMap) { + Map> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); + // 转化 List + List orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> { + List xOrderItems = orderItemMap.get(order.getId()); + TradeOrderPageItemRespVO orderVO = convert(order, xOrderItems); + // 处理收货地址 + orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); + // 增加用户信息 + orderVO.setUser(convertUser(memberUserMap.get(orderVO.getUserId()))); + // 增加推广人信息 + orderVO.setBrokerageUser(convertUser(memberUserMap.get(orderVO.getBrokerageUserId()))); + return orderVO; + }); + return new PageResult<>(orderVOs, pageResult.getTotal()); + } + + MemberUserRespVO convertUser(MemberUserRespDTO memberUserRespDTO); + + TradeOrderPageItemRespVO convert(TradeOrderDO order, List items); + + ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); + + default TradeOrderDetailRespVO convert(TradeOrderDO order, List orderItems, + List orderLogs, + MemberUserRespDTO user, MemberUserRespDTO brokerageUser) { + TradeOrderDetailRespVO orderVO = convert2(order, orderItems); + // 处理收货地址 + orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); + // 处理用户信息 + orderVO.setUser(convert(user)); + orderVO.setBrokerageUser(convert(brokerageUser)); + // 处理日志 + orderVO.setLogs(convertList03(orderLogs)); + return orderVO; + } + List convertList03(List orderLogs); + + TradeOrderDetailRespVO convert2(TradeOrderDO order, List items); + + MemberUserRespVO convert(MemberUserRespDTO bean); + + default PageResult convertPage02(PageResult pageResult, + List orderItems) { + Map> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); + // 转化 List + List orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> { + List xOrderItems = orderItemMap.get(order.getId()); + return convert02(order, xOrderItems); + }); + return new PageResult<>(orderVOs, pageResult.getTotal()); + } + + AppTradeOrderPageItemRespVO convert02(TradeOrderDO order, List items); + + AppProductPropertyValueDetailRespVO convert02(ProductPropertyValueDetailRespDTO bean); + + default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List orderItems, + TradeOrderProperties tradeOrderProperties, + DeliveryExpressDO express) { + AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems); + orderVO.setPayExpireTime(addTime(tradeOrderProperties.getPayExpireTime())); + if (StrUtil.isNotEmpty(order.getPayChannelCode())) { + orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode())); + } + // 处理收货地址 + orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); + if (express != null) { + orderVO.setLogisticsId(express.getId()).setLogisticsName(express.getName()); + } + return orderVO; + } + + AppTradeOrderDetailRespVO convert3(TradeOrderDO order, List items); + + AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean); + + @Mappings({ + @Mapping(target = "skuId", source = "tradeOrderItemDO.skuId"), + @Mapping(target = "orderId", source = "tradeOrderItemDO.orderId"), + @Mapping(target = "orderItemId", source = "tradeOrderItemDO.id"), + @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores"), + @Mapping(target = "benefitScores", source = "createReqVO.benefitScores"), + @Mapping(target = "content", source = "createReqVO.content"), + @Mapping(target = "picUrls", source = "createReqVO.picUrls"), + @Mapping(target = "anonymous", source = "createReqVO.anonymous"), + @Mapping(target = "userId", source = "tradeOrderItemDO.userId") + }) + ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO); + + TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO); + + default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, + List cartList) { + TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId) + .setItems(new ArrayList<>(settlementReqVO.getItems().size())) + .setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus()) + // 物流信息 + .setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId()) + .setPickUpStoreId(settlementReqVO.getPickUpStoreId()) + // 各种活动 + .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) + .setBargainRecordId(settlementReqVO.getBargainRecordId()) + .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) + .setCombinationHeadId(settlementReqVO.getCombinationHeadId()); + // 商品项的构建 + Map cartMap = convertMap(cartList, CartDO::getId); + for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { + // 情况一:skuId + count + if (item.getSkuId() != null) { + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(item.getSkuId()).setCount(item.getCount()) + .setSelected(true)); // true 的原因,下单一定选中 + continue; + } + // 情况二:cartId + CartDO cart = cartMap.get(item.getCartId()); + if (cart == null) { + continue; + } + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(cart.getSkuId()).setCount(cart.getCount()) + .setCartId(item.getCartId()).setSelected(true)); // true 的原因,下单一定选中 + } + return reqBO; + } + + default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address) { + AppTradeOrderSettlementRespVO respVO = convert0(calculate, address); + if (address != null) { + respVO.getAddress().setAreaName(AreaUtils.format(address.getAreaId())); + } + return respVO; + } + + AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address); + + List convertList02(List list); + + TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO); + + TradeOrderDO convert(TradeOrderUpdatePriceReqVO reqVO); + + TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); + + default BrokerageAddReqBO convert(MemberUserRespDTO user, TradeOrderItemDO item, + ProductSpuRespDTO spu, ProductSkuRespDTO sku) { + BrokerageAddReqBO bo = new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId()) + .setBasePrice(item.getPayPrice() * item.getCount()) + .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName())) + .setFirstFixedPrice(0).setSecondFixedPrice(0); + if (BooleanUtil.isTrue(spu.getSubCommissionType())) { + bo.setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice()); + } + return bo; + } + + @Named("convertList04") + List convertList04(List list); + + @Mappings({ + @Mapping(target = "activityId", source = "order.combinationActivityId"), + @Mapping(target = "spuId", source = "item.spuId"), + @Mapping(target = "skuId", source = "item.skuId"), + @Mapping(target = "count", source = "item.count"), + @Mapping(target = "orderId", source = "order.id"), + @Mapping(target = "userId", source = "order.userId"), + @Mapping(target = "headId", source = "order.combinationHeadId"), + @Mapping(target = "combinationPrice", source = "item.payPrice"), + }) + CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderLogConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderLogConvert.java new file mode 100644 index 0000000..763f058 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderLogConvert.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.trade.convert.order; + +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.service.order.bo.TradeOrderLogCreateReqBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface TradeOrderLogConvert { + + TradeOrderLogConvert INSTANCE = Mappers.getMapper(TradeOrderLogConvert.class); + + TradeOrderLogDO convert(TradeOrderLogCreateReqBO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java new file mode 100644 index 0000000..214592b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java @@ -0,0 +1,201 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.aftersale; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 售后订单,用于处理 {@link TradeOrderDO} 交易订单的退款退货流程 + * + * @author 芋道源码 + */ +@TableName(value = "trade_after_sale", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class AfterSaleDO extends BaseDO { + + /** + * 售后编号,主键自增 + */ + private Long id; + /** + * 售后单号 + * + * 例如说,1146347329394184195 + */ + private String no; + /** + * 退款状态 + * + * 枚举 {@link AfterSaleStatusEnum} + */ + private Integer status; + /** + * 售后方式 + * + * 枚举 {@link AfterSaleWayEnum} + */ + private Integer way; + /** + * 售后类型 + * + * 枚举 {@link AfterSaleTypeEnum} + */ + private Integer type; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 申请原因 + * + * type = 退款,对应 trade_after_sale_refund_reason 类型 + * type = 退货退款,对应 trade_after_sale_refund_and_return_reason 类型 + */ + private String applyReason; + /** + * 补充描述 + */ + private String applyDescription; + /** + * 补充凭证图片 + * + * 数组,以逗号分隔 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List applyPicUrls; + + // ========== 交易订单相关 ========== + /** + * 交易订单编号 + * + * 关联 {@link TradeOrderDO#getId()} + */ + private Long orderId; + /** + * 订单流水号 + * + * 冗余 {@link TradeOrderDO#getNo()} + */ + private String orderNo; + /** + * 交易订单项编号 + * + * 关联 {@link TradeOrderItemDO#getId()} + */ + private Long orderItemId; + /** + * 商品 SPU 编号 + * + * 关联 ProductSpuDO 的 id 字段 + * 冗余 {@link TradeOrderItemDO#getSpuId()} + */ + private Long spuId; + /** + * 商品 SPU 名称 + * + * 关联 ProductSkuDO 的 name 字段 + * 冗余 {@link TradeOrderItemDO#getSpuName()} + */ + private String spuName; + /** + * 商品 SKU 编号 + * + * 关联 ProductSkuDO 的编号 + */ + private Long skuId; + /** + * 属性数组,JSON 格式 + * + * 冗余 {@link TradeOrderItemDO#getProperties()} + */ + @TableField(typeHandler = TradeOrderItemDO.PropertyTypeHandler.class) + private List properties; + /** + * 商品图片 + * + * 冗余 {@link TradeOrderItemDO#getPicUrl()} + */ + private String picUrl; + /** + * 退货商品数量 + */ + private Integer count; + + // ========== 审批相关 ========== + + /** + * 审批时间 + */ + private LocalDateTime auditTime; + /** + * 审批人 + * + * 关联 AdminUserDO 的 id 编号 + */ + private Long auditUserId; + /** + * 审批备注 + * + * 注意,只有审批不通过才会填写 + */ + private String auditReason; + + // ========== 退款相关 ========== + /** + * 退款金额,单位:分。 + */ + private Integer refundPrice; + /** + * 支付退款编号 + * + * 对接 pay-module-biz 支付服务的退款订单编号,即 PayRefundDO 的 id 编号 + */ + private Long payRefundId; + /** + * 退款时间 + */ + private LocalDateTime refundTime; + + // ========== 退货相关 ========== + /** + * 退货物流公司编号 + * + * 关联 LogisticsDO 的 id 编号 + */ + private Long logisticsId; + /** + * 退货物流单号 + */ + private String logisticsNo; + /** + * 退货时间 + */ + private LocalDateTime deliveryTime; + /** + * 收货时间 + */ + private LocalDateTime receiveTime; + /** + * 收货备注 + * + * 注意,只有拒绝收货才会填写 + */ + private String receiveReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleLogDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleLogDO.java new file mode 100644 index 0000000..2820f23 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleLogDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.aftersale; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 交易售后日志 DO + * + * @author 芋道源码 + */ +@TableName("trade_after_sale_log") +@KeySequence("trade_after_sale_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AfterSaleLogDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 1:AdminUserDO 的 id 字段 + * 关联 2:MemberUserDO 的 id 字段 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 售后编号 + * + * 关联 {@link AfterSaleDO#getId()} + */ + private Long afterSaleId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + private Integer afterStatus; + + /** + * 操作类型 + * + * 枚举 {@link AfterSaleOperateTypeEnum} + */ + private Integer operateType; + /** + * 操作明细 + */ + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageRecordDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageRecordDO.java new file mode 100644 index 0000000..c819d72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageRecordDO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 佣金记录 DO + * + * @author owen + */ +@TableName("trade_brokerage_record") +@KeySequence("trade_brokerage_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BrokerageRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Integer id; + /** + * 用户编号 + *

+ * 关联 MemberUserDO.id + */ + private Long userId; + /** + * 业务编号 + */ + private String bizId; + /** + * 业务类型 + *

+ * 枚举 {@link BrokerageRecordBizTypeEnum} + */ + private Integer bizType; + + /** + * 标题 + */ + private String title; + /** + * 说明 + */ + private String description; + + /** + * 金额 + */ + private Integer price; + /** + * 当前总佣金 + */ + private Integer totalPrice; + + /** + * 状态 + *

+ * 枚举 {@link BrokerageRecordStatusEnum} + */ + private Integer status; + + /** + * 冻结时间(天) + */ + private Integer frozenDays; + /** + * 解冻时间 + */ + private LocalDateTime unfreezeTime; + + /** + * 来源用户等级 + *

+ * 被推广用户和 {@link #userId} 的推广层级关系 + */ + private Integer sourceUserLevel; + /** + * 来源用户编号 + *

+ * 关联 MemberUserDO.id 字段,被推广用户的编号 + */ + private Long sourceUserId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageUserDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageUserDO.java new file mode 100644 index 0000000..8d73858 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageUserDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 分销用户 DO + * + * @author owen + */ +@TableName("trade_brokerage_user") +@KeySequence("trade_brokerage_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BrokerageUserDO extends BaseDO { + + /** + * 用户编号 + *

+ * 对应 MemberUserDO 的 id 字段 + */ + @TableId + private Long id; + + /** + * 推广员编号 + *

+ * 关联 MemberUserDO 的 id 字段 + */ + private Long bindUserId; + /** + * 推广员绑定时间 + */ + private LocalDateTime bindUserTime; + + /** + * 是否有分销资格 + */ + private Boolean brokerageEnabled; + /** + * 成为分销员时间 + */ + private LocalDateTime brokerageTime; + + /** + * 可用佣金 + */ + private Integer brokeragePrice; + /** + * 冻结佣金 + */ + private Integer frozenPrice; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageWithdrawDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageWithdrawDO.java new file mode 100644 index 0000000..f31c238 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageWithdrawDO.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 佣金提现 DO + * + * @author 芋道源码 + */ +@TableName("trade_brokerage_withdraw") +@KeySequence("trade_brokerage_withdraw_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BrokerageWithdrawDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 字段 + */ + private Long userId; + + /** + * 提现金额,单位:分 + */ + private Integer price; + /** + * 提现手续费,单位:分 + */ + private Integer feePrice; + /** + * 当前总佣金,单位:分 + */ + private Integer totalPrice; + /** + * 提现类型 + *

+ * 枚举 {@link BrokerageWithdrawTypeEnum} + */ + private Integer type; + + /** + * 真实姓名 + */ + private String name; + /** + * 账号 + */ + private String accountNo; + /** + * 银行名称 + */ + private String bankName; + /** + * 开户地址 + */ + private String bankAddress; + /** + * 收款码 + */ + private String accountQrCodeUrl; + /** + * 状态 + *

+ * 枚举 {@link BrokerageWithdrawStatusEnum} + */ + private Integer status; + /** + * 审核驳回原因 + */ + private String auditReason; + /** + * 审核时间 + */ + private LocalDateTime auditTime; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java new file mode 100644 index 0000000..d8bf140 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.cart; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 购物车的商品信息 DO + * + * 每个商品,对应一条记录,通过 {@link #spuId} 和 {@link #skuId} 关联 + * + * @author 芋道源码 + */ +@TableName("trade_cart") +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class CartDO extends BaseDO { + + // ========= 基础字段 BEGIN ========= + + /** + * 编号,唯一自增 + */ + private Long id; + + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + + // ========= 商品信息 ========= + + /** + * 商品 SPU 编号 + * + * 关联 ProductSpuDO 的 id 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + * + * 关联 ProductSkuDO 的 id 编号 + */ + private Long skuId; + /** + * 商品购买数量 + */ + private Integer count; + /** + * 是否选中 + */ + private Boolean selected; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java new file mode 100644 index 0000000..5d7116b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/config/TradeConfigDO.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.config; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 交易中心配置 DO + * + * @author owen + */ +@TableName(value = "trade_config", autoResultMap = true) +@KeySequence("trade_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TradeConfigDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + + // ========== 售后相关 ========== + + /** + * 售后的退款理由 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List afterSaleRefundReasons; + /** + * 售后的退货理由 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List afterSaleReturnReasons; + + // ========== 配送相关 ========== + + /** + * 是否启用全场包邮 + */ + private Boolean deliveryExpressFreeEnabled; + /** + * 全场包邮的最小金额,单位:分 + */ + private Integer deliveryExpressFreePrice; + + /** + * 是否开启自提 + */ + private Boolean deliveryPickUpEnabled; + + // ========== 分销相关 ========== + + /** + * 是否启用分佣 + */ + private Boolean brokerageEnabled; + /** + * 分佣模式 + *

+ * 枚举 {@link BrokerageEnabledConditionEnum 对应的类} + */ + private Integer brokerageEnabledCondition; + /** + * 分销关系绑定模式 + *

+ * 枚举 {@link BrokerageBindModeEnum 对应的类} + */ + private Integer brokerageBindMode; + /** + * 分销海报图地址数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List brokeragePosterUrls; + /** + * 一级返佣比例 + */ + private Integer brokerageFirstPercent; + /** + * 二级返佣比例 + */ + private Integer brokerageSecondPercent; + /** + * 用户提现最低金额 + */ + private Integer brokerageWithdrawMinPrice; + /** + * 用户提现手续费百分比 + */ + private Integer brokerageWithdrawFeePercent; + /** + * 佣金冻结时间(天) + */ + private Integer brokerageFrozenDays; + /** + * 提现方式 + *

+ * 枚举 {@link BrokerageWithdrawTypeEnum 对应的类} + */ + @TableField(typeHandler = IntegerListTypeHandler.class) + private List brokerageWithdrawTypes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressDO.java new file mode 100644 index 0000000..265066d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressDO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 快递公司 DO + * + * @author jason + */ +@TableName(value ="trade_delivery_express") +@KeySequence("trade_delivery_express_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryExpressDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + + /** + * 快递公司 code + */ + private String code; + + /** + * 快递公司名称 + */ + private String name; + + /** + * 快递公司 logo + */ + private String logo; + + /** + * 排序 + */ + private Integer sort; + + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + // TODO 芋艿:c 和结算相关的字段,后续在看 + // partnerId 是否需要月结账号 + // partnerKey 是否需要月结密码 + // net 是否需要取件网店 + // account 账号 + // password 网点名称 + // isShow 是否显示 +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateChargeDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateChargeDO.java new file mode 100644 index 0000000..c3bb30e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateChargeDO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.List; + +/** + * 快递运费模板计费配置 DO + * + * @author jason + */ +@TableName(value ="trade_delivery_express_template_charge", autoResultMap = true) +@KeySequence("trade_delivery_express_template_charge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryExpressTemplateChargeDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + + /** + * 配送模板编号 + * + * 关联 {@link DeliveryExpressTemplateDO#getId()} + */ + private Long templateId; + + /** + * 配送区域编号列表 + */ + @TableField(typeHandler = IntegerListTypeHandler.class) + private List areaIds; + + /** + * 配送计费方式 + * + * 冗余 {@link DeliveryExpressTemplateDO#getChargeMode()} + */ + private Integer chargeMode; + + /** + * 首件数量(件数,重量,或体积) + */ + private Double startCount; + /** + * 起步价,单位:分 + */ + private Integer startPrice; + + /** + * 续件数量(件, 重量,或体积) + */ + private Double extraCount; + /** + * 额外价,单位:分 + */ + private Integer extraPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateDO.java new file mode 100644 index 0000000..b6d6db3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateDO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 快递运费模板 DO + * + * @author jason + */ +@TableName("trade_delivery_express_template") +@KeySequence("trade_delivery_express_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryExpressTemplateDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + + /** + * 模板名称 + */ + private String name; + + /** + * 配送计费方式 + * + * 枚举 {@link DeliveryExpressChargeModeEnum} + */ + private Integer chargeMode; + + /** + * 排序 + */ + private Integer sort; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateFreeDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateFreeDO.java new file mode 100644 index 0000000..07eef1b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryExpressTemplateFreeDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.List; + +/** + * 快递运费模板包邮配置 DO + * + * @author jason + */ +@TableName(value ="trade_delivery_express_template_free", autoResultMap = true) +@KeySequence("trade_delivery_express_template_free_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryExpressTemplateFreeDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 配送模板编号 + * + * 关联 {@link DeliveryExpressTemplateDO#getId()} + */ + private Long templateId; + + + /** + * 配送区域编号列表 + */ + @TableField(typeHandler = IntegerListTypeHandler.class) + private List areaIds; + + /** + * 包邮金额,单位:分 + * + * 订单总金额 > 包邮金额时,才免运费 + */ + private Integer freePrice; + + /** + * 包邮件数 + * + * 订单总件数 > 包邮件数时,才免运费 + */ + private Integer freeCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreDO.java new file mode 100644 index 0000000..21ff993 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreDO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalTime; + +/** + * 自提门店 DO + * + * @author jason + */ +@TableName(value ="trade_delivery_pick_up_store") +@KeySequence("trade_delivery_pick_up_store_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryPickUpStoreDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 门店名称 + */ + private String name; + + /** + * 门店简介 + */ + private String introduction; + + /** + * 门店手机 + */ + private String phone; + + /** + * 区域编号 + */ + private Integer areaId; + + /** + * 门店详细地址 + */ + private String detailAddress; + + /** + * 门店 logo + */ + private String logo; + + /** + * 营业开始时间 + */ + private LocalTime openingTime; + + /** + * 营业结束时间 + */ + private LocalTime closingTime; + + /** + * 纬度 + */ + private Double latitude; + /** + * 经度 + */ + private Double longitude; + + /** + * 门店状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreStaffDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreStaffDO.java new file mode 100644 index 0000000..4c03a8e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/delivery/DeliveryPickUpStoreStaffDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +// TODO @芋艿:后续再详细 review 一轮 +// TODO @芋艿:可能改成 DeliveryPickUpStoreUserDO +/** + * 自提门店店员 DO + * + * @author jason + */ +@TableName(value ="trade_delivery_pick_up_store_staff") +@KeySequence("trade_delivery_pick_up_store_staff_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class DeliveryPickUpStoreStaffDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + + /** + * 自提门店编号 + * + * 关联 {@link DeliveryPickUpStoreDO#getId()} + */ + private Long storeId; + + /** + * 管理员用户id + * + * 关联 {AdminUserDO#getId()} + */ + private Long adminUserId; + + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java new file mode 100644 index 0000000..b127004 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -0,0 +1,333 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.order; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 交易订单 DO + * + * @author 芋道源码 + */ +@TableName("trade_order") +@KeySequence("trade_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TradeOrderDO extends BaseDO { + + /** + * 发货物流公司编号 - 空(无需发货) + */ + public static final Long LOGISTICS_ID_NULL = 0L; + + // ========== 订单基本信息 ========== + /** + * 订单编号,主键自增 + */ + private Long id; + /** + * 订单流水号 + * + * 例如说,1146347329394184195 + */ + private String no; + /** + * 订单类型 + * + * 枚举 {@link TradeOrderTypeEnum} + */ + private Integer type; + /** + * 订单来源 + * + * 枚举 {@link TerminalEnum} + */ + private Integer terminal; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 用户 IP + */ + private String userIp; + /** + * 用户备注 + */ + private String userRemark; + /** + * 订单状态 + * + * 枚举 {@link TradeOrderStatusEnum} + */ + private Integer status; + /** + * 购买的商品数量 + */ + private Integer productCount; + /** + * 订单完成时间 + */ + private LocalDateTime finishTime; + /** + * 订单取消时间 + */ + private LocalDateTime cancelTime; + /** + * 取消类型 + * + * 枚举 {@link TradeOrderCancelTypeEnum} + */ + private Integer cancelType; + /** + * 商家备注 + */ + private String remark; + /** + * 是否评价 + * + * true - 已评价 + * false - 未评价 + */ + private Boolean commentStatus; + + /** + * 推广人编号 + * + * 关联 {@link BrokerageUserDO#getId()} 字段,即 {@link MemberUserRespDTO#getId()} 字段 + */ + private Long brokerageUserId; + + // ========== 价格 + 支付基本信息 ========== + + // 价格文档 - 淘宝:https://open.taobao.com/docV3.htm?docId=108471&docType=1 + // 价格文档 - 京东到家:https://openo2o.jddj.com/api/getApiDetail/182/4d1494c5e7ac4679bfdaaed950c5bc7f.htm + // 价格文档 - 有赞:https://doc.youzanyun.com/detail/API/0/906 + + /** + * 支付订单编号 + * + * 对接 pay-module-biz 支付服务的支付订单编号,即 PayOrderDO 的 id 编号 + */ + private Long payOrderId; + /** + * 是否已支付 + * + * true - 已经支付过 + * false - 没有支付过 + */ + private Boolean payStatus; + /** + * 付款时间 + */ + private LocalDateTime payTime; + /** + * 支付渠道 + * + * 对应 PayChannelEnum 枚举 + */ + private String payChannelCode; + + /** + * 商品原价,单位:分 + * + * totalPrice = {@link TradeOrderItemDO#getPrice()} * {@link TradeOrderItemDO#getCount()} 求和 + * + * 对应 taobao 的 trade.total_fee 字段 + */ + private Integer totalPrice; + /** + * 优惠金额,单位:分 + * + * 对应 taobao 的 order.discount_fee 字段 + */ + private Integer discountPrice; + /** + * 运费金额,单位:分 + */ + private Integer deliveryPrice; + /** + * 订单调价,单位:分 + * + * 正数,加价;负数,减价 + */ + private Integer adjustPrice; + /** + * 应付金额(总),单位:分 + * + * = {@link #totalPrice} + * - {@link #couponPrice} + * - {@link #pointPrice} + * - {@link #discountPrice} + * + {@link #deliveryPrice} + * + {@link #adjustPrice} + * - {@link #vipPrice} + */ + private Integer payPrice; + + // ========== 收件 + 物流基本信息 ========== + /** + * 配送方式 + * + * 枚举 {@link DeliveryTypeEnum} + */ + private Integer deliveryType; + /** + * 发货物流公司编号 + * + * 如果无需发货,则 logisticsId 设置为 0。原因是,不想再添加额外字段 + * + * 关联 {@link DeliveryExpressDO#getId()} + */ + private Long logisticsId; + /** + * 发货物流单号 + * + * 如果无需发货,则 logisticsNo 设置 ""。原因是,不想再添加额外字段 + */ + private String logisticsNo; + /** + * 发货时间 + */ + private LocalDateTime deliveryTime; + + /** + * 收货时间 + */ + private LocalDateTime receiveTime; + /** + * 收件人名称 + */ + private String receiverName; + /** + * 收件人手机 + */ + private String receiverMobile; + /** + * 收件人地区编号 + */ + private Integer receiverAreaId; + /** + * 收件人详细地址 + */ + private String receiverDetailAddress; + + /** + * 自提门店编号 + * + * 关联 {@link DeliveryPickUpStoreDO#getId()} + */ + private Long pickUpStoreId; + /** + * 自提核销码 + */ + private String pickUpVerifyCode; + + // ========== 售后基本信息 ========== + /** + * 售后状态 + * + * 枚举 {@link TradeOrderRefundStatusEnum} + */ + private Integer refundStatus; + /** + * 退款金额,单位:分 + * + * 注意,退款并不会影响 {@link #payPrice} 实际支付金额 + * 也就说,一个订单最终产生多少金额的收入 = payPrice - refundPrice + */ + private Integer refundPrice; + + // ========== 营销基本信息 ========== + /** + * 优惠劵编号 + */ + private Long couponId; + /** + * 优惠劵减免金额,单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 + */ + private Integer couponPrice; + /** + * 使用的积分 + */ + private Integer usePoint; + /** + * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 + */ + private Integer pointPrice; + /** + * 赠送的积分 + */ + private Integer givePoint; + /** + * 退还的使用的积分 + */ + private Integer refundPoint; + /** + * VIP 减免金额,单位:分 + */ + private Integer vipPrice; + + /** + * 秒杀活动编号 + * + * 关联 SeckillActivityDO 的 id 字段 + */ + private Long seckillActivityId; + + /** + * 砍价活动编号 + * + * 关联 BargainActivityDO 的 id 字段 + */ + private Long bargainActivityId; + /** + * 砍价记录编号 + * + * 关联 BargainRecordDO 的 id 字段 + */ + private Long bargainRecordId; + + /** + * 拼团活动编号 + * + * 关联 CombinationActivityDO 的 id 字段 + */ + private Long combinationActivityId; + /** + * 拼团团长编号 + * + * 关联 CombinationRecordDO 的 headId 字段 + */ + private Long combinationHeadId; + /** + * 拼团记录编号 + * + * 关联 CombinationRecordDO 的 id 字段 + */ + private Long combinationRecordId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java new file mode 100644 index 0000000..10b07ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -0,0 +1,229 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.order; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + * 交易订单项 DO + * + * @author 芋道源码 + */ +@TableName(value = "trade_order_item", autoResultMap = true) +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class TradeOrderItemDO extends BaseDO { + + // ========== 订单项基本信息 ========== + /** + * 编号 + */ + private Long id; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 订单编号 + * + * 关联 {@link TradeOrderDO#getId()} + */ + private Long orderId; + /** + * 购物车项编号 + * + * 关联 {@link CartDO#getId()} + */ + private Long cartId; + + // ========== 商品基本信息; 冗余较多字段,减少关联查询 ========== + /** + * 商品 SPU 编号 + * + * 关联 ProductSkuDO 的 spuId 编号 + */ + private Long spuId; + /** + * 商品 SPU 名称 + * + * 冗余 ProductSkuDO 的 spuName 编号 + */ + private String spuName; + /** + * 商品 SKU 编号 + * + * 关联 ProductSkuDO 的 id 编号 + */ + private Long skuId; + /** + * 属性数组,JSON 格式 + * + * 冗余 ProductSkuDO 的 properties 字段 + */ + @TableField(typeHandler = PropertyTypeHandler.class) + private List properties; + /** + * 商品图片 + */ + private String picUrl; + /** + * 购买数量 + */ + private Integer count; + /** + * 是否评价 + * + * true - 已评价 + * false - 未评价 + */ + private Boolean commentStatus; + + // ========== 价格 + 支付基本信息 ========== + + /** + * 商品原价(单),单位:分 + * + * 对应 ProductSkuDO 的 price 字段 + * 对应 taobao 的 order.price 字段 + */ + private Integer price; + /** + * 优惠金额(总),单位:分 + * + * 对应 taobao 的 order.discount_fee 字段 + */ + private Integer discountPrice; + /** + * 运费金额(总),单位:分 + */ + private Integer deliveryPrice; + /** + * 订单调价(总),单位:分 + * + * 正数,加价;负数,减价 + */ + private Integer adjustPrice; + /** + * 应付金额(总),单位:分 + * + * = {@link #price} * {@link #count} + * - {@link #couponPrice} + * - {@link #pointPrice} + * - {@link #discountPrice} + * + {@link #deliveryPrice} + * + {@link #adjustPrice} + * - {@link #vipPrice} + */ + private Integer payPrice; + + // ========== 营销基本信息 ========== + + /** + * 优惠劵减免金额,单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 + */ + private Integer couponPrice; + /** + * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 + */ + private Integer pointPrice; + /** + * 使用的积分 + * + * 目的:用于后续取消或者售后订单时,需要归还赠送 + */ + private Integer usePoint; + /** + * 赠送的积分 + * + * 目的:用于后续取消或者售后订单时,需要扣减赠送 + */ + private Integer givePoint; + /** + * VIP 减免金额,单位:分 + */ + private Integer vipPrice; + + // ========== 售后基本信息 ========== + + /** + * 售后单编号 + * + * 关联 {@link AfterSaleDO#getId()} 字段 + */ + private Long afterSaleId; + /** + * 售后状态 + * + * 枚举 {@link TradeOrderItemAfterSaleStatusEnum} + */ + private Integer afterSaleStatus; + + /** + * 商品属性 + */ + @Data + public static class Property implements Serializable { + + /** + * 属性编号 + * + * 关联 ProductPropertyDO 的 id 编号 + */ + private Long propertyId; + /** + * 属性名字 + * + * 关联 ProductPropertyDO 的 name 字段 + */ + private String propertyName; + + /** + * 属性值编号 + * + * 关联 ProductPropertyValueDO 的 id 编号 + */ + private Long valueId; + /** + * 属性值名字 + * + * 关联 ProductPropertyValueDO 的 name 字段 + */ + private String valueName; + + } + + // TODO @芋艿:可以找一些新的思路 + public static class PropertyTypeHandler extends AbstractJsonTypeHandler> { + + @Override + protected List parse(String json) { + return JsonUtils.parseArray(json, Property.class); + } + + @Override + protected String toJson(List obj) { + return JsonUtils.toJsonString(obj); + } + + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java new file mode 100644 index 0000000..36022c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.order; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 订单日志 DO + * + * @author 陈賝 + */ +@TableName("trade_order_log") +@KeySequence("trade_order_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TradeOrderLogDO extends BaseDO { + + /** + * 用户类型 - 系统 + * + * 例如说:Job 自动过期订单时,通过系统自动操作 + */ + public static final Integer USER_TYPE_SYSTEM = 0; + /** + * 用户编号 - 系统 + */ + public static final Long USER_ID_SYSTEM = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 AdminUserDO 的 id 字段、或者 MemberUserDO 的 id 字段 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 订单号 + * + * 关联 {@link TradeOrderDO#getId()} + */ + private Long orderId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + private Integer afterStatus; + + /** + * 操作类型 + * + * {@link TradeOrderOperateTypeEnum} + */ + private Integer operateType; + /** + * 订单日志信息 + */ + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleLogMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleLogMapper.java new file mode 100644 index 0000000..c0ec91c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleLogMapper.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface AfterSaleLogMapper extends BaseMapperX { + + default List selectListByAfterSaleId(Long afterSaleId) { + return selectList(AfterSaleLogDO::getAfterSaleId, afterSaleId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java new file mode 100644 index 0000000..68a09a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; + +@Mapper +public interface AfterSaleMapper extends BaseMapperX { + + default PageResult selectPage(AfterSalePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(AfterSaleDO::getNo, reqVO.getNo()) + .eqIfPresent(AfterSaleDO::getStatus, reqVO.getStatus()) + .eqIfPresent(AfterSaleDO::getType, reqVO.getType()) + .eqIfPresent(AfterSaleDO::getWay, reqVO.getWay()) + .likeIfPresent(AfterSaleDO::getOrderNo, reqVO.getOrderNo()) + .likeIfPresent(AfterSaleDO::getSpuName, reqVO.getSpuName()) + .betweenIfPresent(AfterSaleDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(AfterSaleDO::getId)); + } + + default PageResult selectPage(Long userId, PageParam pageParam) { + return selectPage(pageParam, new LambdaQueryWrapperX() + .eqIfPresent(AfterSaleDO::getUserId, userId) + .orderByDesc(AfterSaleDO::getId)); + } + + default int updateByIdAndStatus(Long id, Integer status, AfterSaleDO update) { + return update(update, new LambdaUpdateWrapper() + .eq(AfterSaleDO::getId, id).eq(AfterSaleDO::getStatus, status)); + } + + default AfterSaleDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(AfterSaleDO::getId, id, + AfterSaleDO::getUserId, userId); + } + + default Long selectCountByUserIdAndStatus(Long userId, Collection statuses) { + return selectCount(new LambdaQueryWrapperX() + .eq(AfterSaleDO::getUserId, userId) + .in(AfterSaleDO::getStatus, statuses)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java new file mode 100644 index 0000000..388f927 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageRecordMapper.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage; + +import cn.hutool.core.bean.BeanUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByPriceRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.github.yulichang.toolkit.MPJWrappers; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 佣金记录 Mapper + * + * @author owen + */ +@Mapper +public interface BrokerageRecordMapper extends BaseMapperX { + + default PageResult selectPage(BrokerageRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId()) + .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType()) + .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus()) + .eqIfPresent(BrokerageRecordDO::getSourceUserLevel, reqVO.getSourceUserLevel()) + .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BrokerageRecordDO::getId)); + } + + default List selectListByStatusAndUnfreezeTimeLt(Integer status, LocalDateTime unfreezeTime) { + return selectList(new LambdaQueryWrapper() + .eq(BrokerageRecordDO::getStatus, status) + .lt(BrokerageRecordDO::getUnfreezeTime, unfreezeTime)); + } + + default int updateByIdAndStatus(Integer id, Integer status, BrokerageRecordDO updateObj) { + return update(updateObj, new LambdaQueryWrapper() + .eq(BrokerageRecordDO::getId, id) + .eq(BrokerageRecordDO::getStatus, status)); + } + + default BrokerageRecordDO selectByBizTypeAndBizIdAndUserId(Integer bizType, String bizId, Long userId) { + return selectOne(BrokerageRecordDO::getBizType, bizType, + BrokerageRecordDO::getBizId, bizId, + BrokerageRecordDO::getUserId, userId); + } + + default List selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(Collection userIds, + Integer bizType, + Integer status) { + List> list = selectMaps(MPJWrappers.lambdaJoin(BrokerageRecordDO.class) + .select(BrokerageRecordDO::getUserId) + .selectCount(BrokerageRecordDO::getId, UserBrokerageSummaryRespBO::getCount) + .selectSum(BrokerageRecordDO::getPrice) + .in(BrokerageRecordDO::getUserId, userIds) + .eq(BrokerageRecordDO::getBizId, bizType) + .eq(BrokerageRecordDO::getStatus, status) + .groupBy(BrokerageRecordDO::getUserId)); // 按照 userId 聚合 + return BeanUtil.copyToList(list, UserBrokerageSummaryRespBO.class); + // selectJoinList有BUG,会与租户插件冲突:解析SQL时,发生异常 https://gitee.com/best_handsome/mybatis-plus-join/issues/I84GYW +// return selectJoinList(UserBrokerageSummaryBO.class, MPJWrappers.lambdaJoin(BrokerageRecordDO.class) +// .select(BrokerageRecordDO::getUserId) +// .selectCount(BrokerageRecordDO::getId, UserBrokerageSummaryBO::getCount) +// .selectSum(BrokerageRecordDO::getPrice) +// .in(BrokerageRecordDO::getUserId, userIds) +// .eq(BrokerageRecordDO::getBizId, bizType) +// .eq(BrokerageRecordDO::getStatus, status) +// .groupBy(BrokerageRecordDO::getUserId)); + } + + @Select("SELECT SUM(price) FROM trade_brokerage_record " + + "WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status} " + + "AND unfreeze_time BETWEEN #{beginTime} AND #{endTime} AND deleted = FALSE") + Integer selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(@Param("userId") Long userId, + @Param("bizType") Integer bizType, + @Param("status") Integer status, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + // TODO @芋艿:收敛掉 @Select 注解操作,统一成 MyBatis-Plus 的方式,或者 xml + @Select("SELECT user_id AS id, SUM(price) AS brokeragePrice FROM trade_brokerage_record " + + "WHERE biz_type = #{bizType} AND status = #{status} AND deleted = FALSE " + + "AND unfreeze_time BETWEEN #{beginTime} AND #{endTime} " + + "GROUP BY user_id " + + "ORDER BY brokeragePrice DESC") + IPage selectSummaryPricePageGroupByUserId(IPage page, + @Param("bizType") Integer bizType, + @Param("status") Integer status, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + @Select("SELECT COUNT(1) FROM trade_brokerage_record " + + "WHERE biz_type = #{bizType} AND status = #{status} AND deleted = FALSE " + + "AND unfreeze_time BETWEEN #{beginTime} AND #{endTime} " + + "GROUP BY user_id HAVING SUM(price) > #{brokeragePrice}") + Integer selectCountByPriceGt(@Param("brokeragePrice") Integer brokeragePrice, + @Param("bizType") Integer bizType, + @Param("status") Integer status, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java new file mode 100644 index 0000000..6c24cac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java @@ -0,0 +1,167 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.SortingField; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * 分销用户 Mapper + * + * @author owen + */ +@Mapper +public interface BrokerageUserMapper extends BaseMapperX { + + default PageResult selectPage(BrokerageUserPageReqVO reqVO, List ids) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .inIfPresent(BrokerageUserDO::getId, ids) + .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled()) + .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime()) + .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime()) + .orderByDesc(BrokerageUserDO::getId)); + } + + /** + * 更新用户可用佣金(增加) + * + * @param id 用户编号 + * @param incrCount 增加佣金(正数) + */ + default void updatePriceIncr(Long id, Integer incrCount) { + Assert.isTrue(incrCount > 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" brokerage_price = brokerage_price + " + incrCount) + .eq(BrokerageUserDO::getId, id); + update(null, lambdaUpdateWrapper); + } + + /** + * 更新用户可用佣金(减少) + * 注意:理论上佣金可能已经提现,这时会扣出负数,确保平台不会造成损失 + * + * @param id 用户编号 + * @param incrCount 增加佣金(负数) + * @return 更新行数 + */ + default int updatePriceDecr(Long id, Integer incrCount) { + Assert.isTrue(incrCount < 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" brokerage_price = brokerage_price + " + incrCount) // 负数,所以使用 + 号 + .eq(BrokerageUserDO::getId, id); + return update(null, lambdaUpdateWrapper); + } + + /** + * 更新用户冻结佣金(增加) + * + * @param id 用户编号 + * @param incrCount 增加冻结佣金(正数) + */ + default void updateFrozenPriceIncr(Long id, Integer incrCount) { + Assert.isTrue(incrCount > 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" frozen_price = frozen_price + " + incrCount) + .eq(BrokerageUserDO::getId, id); + update(null, lambdaUpdateWrapper); + } + + /** + * 更新用户冻结佣金(减少) + * 注意:理论上冻结佣金可能已经解冻,这时会扣出负数,确保平台不会造成损失 + * + * @param id 用户编号 + * @param incrCount 减少冻结佣金(负数) + */ + default void updateFrozenPriceDecr(Long id, Integer incrCount) { + Assert.isTrue(incrCount < 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" frozen_price = frozen_price + " + incrCount) // 负数,所以使用 + 号 + .eq(BrokerageUserDO::getId, id); + update(null, lambdaUpdateWrapper); + } + + /** + * 更新用户冻结佣金(减少), 更新用户佣金(增加) + * + * @param id 用户编号 + * @param incrCount 减少冻结佣金(负数) + * @return 更新条数 + */ + default int updateFrozenPriceDecrAndPriceIncr(Long id, Integer incrCount) { + Assert.isTrue(incrCount < 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" frozen_price = frozen_price + " + incrCount + // 负数,所以使用 + 号 + ", brokerage_price = brokerage_price + " + -incrCount) // 负数,所以使用 - 号 + .eq(BrokerageUserDO::getId, id) + .ge(BrokerageUserDO::getFrozenPrice, -incrCount); // cas 逻辑 + return update(null, lambdaUpdateWrapper); + } + + default void updateBindUserIdAndBindUserTimeToNull(Long id) { + update(null, new LambdaUpdateWrapper() + .eq(BrokerageUserDO::getId, id) + .set(BrokerageUserDO::getBindUserId, null).set(BrokerageUserDO::getBindUserTime, null)); + } + + default void updateEnabledFalseAndBrokerageTimeToNull(Long id) { + update(null, new LambdaUpdateWrapper() + .eq(BrokerageUserDO::getId, id) + .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null)); + } + + @Select("SELECT bind_user_id AS id, COUNT(1) AS brokerageUserCount FROM trade_brokerage_user " + + "WHERE bind_user_id IS NOT NULL AND deleted = FALSE " + + "AND bind_user_time BETWEEN #{beginTime} AND #{endTime} " + + "GROUP BY bind_user_id " + + "ORDER BY brokerageUserCount DESC") + IPage selectCountPageGroupByBindUserId(Page page, + @Param("beginTime") LocalDateTime beginTime, + @Param("endTime") LocalDateTime endTime); + + /** + * 下级分销统计(分页) + * + * @param bizType 业务类型 + * @param status 状态 + * @param ids 用户编号列表 + * @param sortingField 排序字段 + * @return 下级分销统计分页列表 + */ + IPage selectSummaryPageByUserId(Page page, + @Param("bizType") Integer bizType, + @Param("status") Integer status, + @Param("ids") Collection ids, + @Param("sortingField") SortingField sortingField); + + /** + * 获得被 bindUserIds 推广的用户编号数组 + * + * @param bindUserIds 推广员编号数组 + * @return 用户编号数组 + */ + default List selectIdListByBindUserIdIn(Collection bindUserIds) { + return Convert.toList(Long.class, + selectObjs(new LambdaQueryWrapperX() + .select(Collections.singletonList(BrokerageUserDO::getId)) // 只查询 id 字段,加速返回速度 + .in(BrokerageUserDO::getBindUserId, bindUserIds))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java new file mode 100644 index 0000000..9e2cf68 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.brokerage; + +import cn.hutool.core.bean.BeanUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 佣金提现 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BrokerageWithdrawMapper extends BaseMapperX { + + default PageResult selectPage(BrokerageWithdrawPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId()) + .eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType()) + .likeIfPresent(BrokerageWithdrawDO::getName, reqVO.getName()) + .eqIfPresent(BrokerageWithdrawDO::getAccountNo, reqVO.getAccountNo()) + .likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName()) + .eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId)); + } + + default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .eq(BrokerageWithdrawDO::getId, id) + .eq(BrokerageWithdrawDO::getStatus, status)); + } + + default List selectCountAndSumPriceByUserIdAndStatus(Collection userIds, Integer status) { + List> list = selectMaps(new MPJLambdaWrapper() + .select(BrokerageWithdrawDO::getUserId) + .selectCount(BrokerageWithdrawDO::getId, BrokerageWithdrawSummaryRespBO::getCount) + .selectSum(BrokerageWithdrawDO::getPrice) + .in(BrokerageWithdrawDO::getUserId, userIds) + .eq(BrokerageWithdrawDO::getStatus, status) + .groupBy(BrokerageWithdrawDO::getUserId)); + return BeanUtil.copyToList(list, BrokerageWithdrawSummaryRespBO.class); + // selectJoinList有BUG,会与租户插件冲突:解析SQL时,发生异常 https://gitee.com/best_handsome/mybatis-plus-join/issues/I84GYW +// return selectJoinList(UserWithdrawSummaryBO.class, new MPJLambdaWrapper() +// .select(BrokerageWithdrawDO::getUserId) +// .selectCount(BrokerageWithdrawDO::getId, UserWithdrawSummaryBO::getCount) +// .selectSum(BrokerageWithdrawDO::getPrice) +// .in(BrokerageWithdrawDO::getUserId, userIds) +// .eq(BrokerageWithdrawDO::getStatus, status) +// .groupBy(BrokerageWithdrawDO::getUserId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/CartMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/CartMapper.java new file mode 100644 index 0000000..b672651 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/CartMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Mapper +public interface CartMapper extends BaseMapperX { + + default CartDO selectByUserIdAndSkuId(Long userId, Long skuId) { + return selectOne(CartDO::getUserId, userId, + CartDO::getSkuId, skuId); + } + + default Integer selectSumByUserId(Long userId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("user_id", userId) + .eq("selected", true)); // 只计算选中的 + // 获得数量 + return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + + default CartDO selectById(Long id, Long userId) { + return selectOne(CartDO::getId, id, + CartDO::getUserId, userId); + } + + default List selectListByIds(Collection ids, Long userId) { + return selectList(new LambdaQueryWrapper() + .in(CartDO::getId, ids) + .eq(CartDO::getUserId, userId)); + } + + default List selectListByUserId(Long userId) { + return selectList(new LambdaQueryWrapper() + .eq(CartDO::getUserId, userId)); + } + + default List selectListByUserId(Long userId, Set ids) { + return selectList(new LambdaQueryWrapper() + .eq(CartDO::getUserId, userId) + .in(CartDO::getId, ids)); + } + + default void updateByIds(Collection ids, Long userId, CartDO updateObj) { + update(updateObj, new LambdaQueryWrapper() + .in(CartDO::getId, ids) + .eq(CartDO::getUserId, userId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/config/TradeConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/config/TradeConfigMapper.java new file mode 100644 index 0000000..18a3f4d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/config/TradeConfigMapper.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.config; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 交易中心配置 Mapper + * + * @author owen + */ +@Mapper +public interface TradeConfigMapper extends BaseMapperX { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressMapper.java new file mode 100644 index 0000000..59e7cf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressMapper.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface DeliveryExpressMapper extends BaseMapperX { + + default PageResult selectPage(DeliveryExpressPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DeliveryExpressDO::getCode, reqVO.getCode()) + .likeIfPresent(DeliveryExpressDO::getName, reqVO.getName()) + .eqIfPresent(DeliveryExpressDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DeliveryExpressDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(DeliveryExpressDO::getSort)); + } + + default List selectList(DeliveryExpressExportReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(DeliveryExpressDO::getCode, reqVO.getCode()) + .likeIfPresent(DeliveryExpressDO::getName, reqVO.getName()) + .eqIfPresent(DeliveryExpressDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DeliveryExpressDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(DeliveryExpressDO::getSort)); + } + + default DeliveryExpressDO selectByCode(String code) { + return selectOne(new LambdaQueryWrapper() + .eq(DeliveryExpressDO::getCode, code)); + } + + default List selectListByStatus(Integer status) { + return selectList(DeliveryExpressDO::getStatus, status); + } + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateChargeMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateChargeMapper.java new file mode 100644 index 0000000..a2403f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateChargeMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DeliveryExpressTemplateChargeMapper extends BaseMapperX { + + default List selectListByTemplateId(Long templateId){ + return selectList(new LambdaQueryWrapper() + .eq(DeliveryExpressTemplateChargeDO::getTemplateId, templateId)); + } + + default int deleteByTemplateId(Long templateId){ + return delete(new LambdaQueryWrapper() + .eq(DeliveryExpressTemplateChargeDO::getTemplateId, templateId)); + } + + default List selectByTemplateIds(Collection templateIds) { + return selectList(DeliveryExpressTemplateChargeDO::getTemplateId, templateIds); + } + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateFreeMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateFreeMapper.java new file mode 100644 index 0000000..b64a3c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateFreeMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DeliveryExpressTemplateFreeMapper extends BaseMapperX { + + default List selectListByTemplateId(Long templateId) { + return selectList(new LambdaQueryWrapper() + .eq(DeliveryExpressTemplateFreeDO::getTemplateId, templateId)); + } + + default int deleteByTemplateId(Long templateId) { + return delete(new LambdaQueryWrapper() + .eq(DeliveryExpressTemplateFreeDO::getTemplateId, templateId)); + } + + default List selectListByTemplateIds(Collection templateIds) { + return selectList(DeliveryExpressTemplateFreeDO::getTemplateId, templateIds); + } +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateMapper.java new file mode 100644 index 0000000..c933468 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DeliveryExpressTemplateMapper extends BaseMapperX { + + default PageResult selectPage(DeliveryExpressTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DeliveryExpressTemplateDO::getName, reqVO.getName()) + .eqIfPresent(DeliveryExpressTemplateDO::getChargeMode, reqVO.getChargeMode()) + .betweenIfPresent(DeliveryExpressTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(DeliveryExpressTemplateDO::getSort)); + } + + default DeliveryExpressTemplateDO selectByName(String name) { + return selectOne(DeliveryExpressTemplateDO::getName,name); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreMapper.java new file mode 100644 index 0000000..b26b1c0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStorePageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface DeliveryPickUpStoreMapper extends BaseMapperX { + + default PageResult selectPage(DeliveryPickUpStorePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DeliveryPickUpStoreDO::getName, reqVO.getName()) + .eqIfPresent(DeliveryPickUpStoreDO::getPhone, reqVO.getPhone()) + .eqIfPresent(DeliveryPickUpStoreDO::getAreaId, reqVO.getAreaId()) + .eqIfPresent(DeliveryPickUpStoreDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DeliveryPickUpStoreDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DeliveryPickUpStoreDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(DeliveryPickUpStoreDO::getStatus, status); + } + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreStaffMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreStaffMapper.java new file mode 100644 index 0000000..06cc14e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryPickUpStoreStaffMapper.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.delivery; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreStaffDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface DeliveryPickUpStoreStaffMapper extends BaseMapperX { + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java new file mode 100644 index 0000000..b701b7f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.order; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Mapper +public interface TradeOrderItemMapper extends BaseMapperX { + + default int updateAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, + Long afterSaleId) { + return update(new TradeOrderItemDO().setAfterSaleStatus(newAfterSaleStatus).setAfterSaleId(afterSaleId), + new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus))); + } + + default List selectListByOrderId(Long orderId) { + return selectList(TradeOrderItemDO::getOrderId, orderId); + } + + default List selectListByOrderId(Collection orderIds) { + return selectList(TradeOrderItemDO::getOrderId, orderIds); + } + + default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) { + return selectOne(new LambdaQueryWrapperX() + .eq(TradeOrderItemDO::getId, orderItemId) + .eq(TradeOrderItemDO::getUserId, loginUserId)); + } + + default List selectListByOrderIdAndCommentStatus(Long orderId, Boolean commentStatus) { + return selectList(new LambdaQueryWrapperX() + .eq(TradeOrderItemDO::getOrderId, orderId) + .eq(TradeOrderItemDO::getCommentStatus, commentStatus)); + } + + default int selectProductSumByOrderId(@Param("orderIds") Set orderIds) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .in("order_id", orderIds)); // 只计算选中的 + // 获得数量 + return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderLogMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderLogMapper.java new file mode 100644 index 0000000..7788030 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderLogMapper.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.order; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface TradeOrderLogMapper extends BaseMapperX { + + default List selectListByOrderId(Long orderId) { + return selectList(TradeOrderLogDO::getOrderId, orderId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java new file mode 100644 index 0000000..21fc038 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java @@ -0,0 +1,127 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.order; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Mapper +public interface TradeOrderMapper extends BaseMapperX { + + default int updateByIdAndStatus(Long id, Integer status, TradeOrderDO update) { + return update(update, new LambdaUpdateWrapper() + .eq(TradeOrderDO::getId, id).eq(TradeOrderDO::getStatus, status)); + } + + default TradeOrderDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(TradeOrderDO::getId, id, TradeOrderDO::getUserId, userId); + } + + default PageResult selectPage(TradeOrderPageReqVO reqVO, Set userIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId()) + .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType()) + .inIfPresent(TradeOrderDO::getUserId, userIds) + .eqIfPresent(TradeOrderDO::getType, reqVO.getType()) + .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus()) + .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode()) + .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal()) + .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId()) + .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds()) + .likeIfPresent(TradeOrderDO::getPickUpVerifyCode, reqVO.getPickUpVerifyCode()) + .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(TradeOrderDO::getId)); + } + + // TODO @疯狂:如果用 map 返回,要不这里直接用 TradeOrderSummaryRespVO 返回?也算合理,就当 sql 查询出这么个玩意~~ + default List> selectOrderSummaryGroupByRefundStatus(TradeOrderPageReqVO reqVO, Set userIds) { + return selectMaps(new MPJLambdaWrapperX() + .selectAs(TradeOrderDO::getRefundStatus, TradeOrderDO::getRefundStatus) // 售后状态 + .selectCount(TradeOrderDO::getId, "count") // 售后状态对应的数量 + .selectSum(TradeOrderDO::getPayPrice, "price") // 售后状态对应的支付金额 + .likeIfPresent(TradeOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(TradeOrderDO::getUserId, reqVO.getUserId()) + .eqIfPresent(TradeOrderDO::getDeliveryType, reqVO.getDeliveryType()) + .inIfPresent(TradeOrderDO::getUserId, userIds) + .eqIfPresent(TradeOrderDO::getType, reqVO.getType()) + .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus()) + .eqIfPresent(TradeOrderDO::getPayChannelCode, reqVO.getPayChannelCode()) + .eqIfPresent(TradeOrderDO::getTerminal, reqVO.getTerminal()) + .eqIfPresent(TradeOrderDO::getLogisticsId, reqVO.getLogisticsId()) + .inIfPresent(TradeOrderDO::getPickUpStoreId, reqVO.getPickUpStoreIds()) + .likeIfPresent(TradeOrderDO::getPickUpVerifyCode, reqVO.getPickUpVerifyCode()) + .betweenIfPresent(TradeOrderDO::getCreateTime, reqVO.getCreateTime()) + .groupBy(TradeOrderDO::getRefundStatus)); // 按售后状态分组 + } + + default PageResult selectPage(AppTradeOrderPageReqVO reqVO, Long userId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(TradeOrderDO::getUserId, userId) + .eqIfPresent(TradeOrderDO::getStatus, reqVO.getStatus()) + .eqIfPresent(TradeOrderDO::getCommentStatus, reqVO.getCommentStatus()) + .orderByDesc(TradeOrderDO::getId)); // TODO 芋艿:未来不同的 status,不同的排序 + } + + default Long selectCountByUserIdAndStatus(Long userId, Integer status, Boolean commentStatus) { + return selectCount(new LambdaQueryWrapperX() + .eq(TradeOrderDO::getUserId, userId) + .eqIfPresent(TradeOrderDO::getStatus, status) + .eqIfPresent(TradeOrderDO::getCommentStatus, commentStatus)); + } + + default TradeOrderDO selectOrderByIdAndUserId(Long orderId, Long loginUserId) { + return selectOne(new LambdaQueryWrapperX() + .eq(TradeOrderDO::getId, orderId) + .eq(TradeOrderDO::getUserId, loginUserId)); + } + + default List selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime createTime) { + return selectList(new LambdaUpdateWrapper() + .eq(TradeOrderDO::getStatus, status) + .lt(TradeOrderDO::getCreateTime, createTime)); + } + + default List selectListByStatusAndDeliveryTimeLt(Integer status, LocalDateTime deliveryTime) { + return selectList(new LambdaUpdateWrapper() + .eq(TradeOrderDO::getStatus, status) + .lt(TradeOrderDO::getDeliveryTime, deliveryTime)); + } + + default List selectListByStatusAndReceiveTimeLt(Integer status, LocalDateTime receive, + Boolean commentStatus) { + return selectList(new LambdaUpdateWrapper() + .eq(TradeOrderDO::getStatus, status) + .lt(TradeOrderDO::getReceiveTime, receive) + .eq(TradeOrderDO::getCommentStatus, commentStatus)); + } + + default List selectListByUserIdAndSeckillActivityId(Long userId, Long seckillActivityId) { + return selectList(new LambdaUpdateWrapper<>(TradeOrderDO.class) + .eq(TradeOrderDO::getUserId, userId) + .eq(TradeOrderDO::getSeckillActivityId, seckillActivityId)); + } + + default TradeOrderDO selectOneByPickUpVerifyCode(String pickUpVerifyCode) { + return selectOne(TradeOrderDO::getPickUpVerifyCode, pickUpVerifyCode); + } + + default TradeOrderDO selectByUserIdAndCombinationActivityIdAndStatus(Long userId, Long combinationActivityId, Integer status) { + return selectOne(new LambdaQueryWrapperX() + .eq(TradeOrderDO::getUserId, userId) + .eq(TradeOrderDO::getStatus, status) + .eq(TradeOrderDO::getCombinationActivityId, combinationActivityId) + ); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/package-info.java new file mode 100644 index 0000000..37e0ba7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 占位 + */ +package cn.iocoder.yudao.module.trade.dal.mysql; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/RedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..eff48e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/RedisKeyConstants.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.trade.dal.redis; + +/** + * 交易 Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 交易序号的缓存 + * + * KEY 格式:trade_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String TRADE_NO = "trade_no:"; + + /** + * 交易序号的缓存 + * + * KEY 格式:express_track:{code-logisticsNo-receiverMobile} + * VALUE 数据格式 String, 物流信息集合 + */ + String EXPRESS_TRACK = "express_track"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeNoRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeNoRedisDAO.java new file mode 100644 index 0000000..8b76f19 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeNoRedisDAO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.dal.redis.no; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.trade.dal.redis.RedisKeyConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + +/** + * 订单序号的 Redis DAO + * + * @author HUIHUI + */ +@Repository +public class TradeNoRedisDAO { + + public static final String TRADE_ORDER_NO_PREFIX = "o"; + + public static final String AFTER_SALE_NO_PREFIX = "r"; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号 + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); + String key = RedisKeyConstants.TRADE_NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofMinutes(1L)); + return noPrefix + no; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/config/AfterSaleLogConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/config/AfterSaleLogConfiguration.java new file mode 100644 index 0000000..1c26137 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/config/AfterSaleLogConfiguration.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.framework.aftersale.config; + +import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +// TODO @chenchen:改成 aftersale 好点哈; +/** + * trade 模块的 afterSaleLog 组件的 Configuration + * + * @author 陈賝 + * @since 2023/6/18 11:09 + */ +@Configuration(proxyBeanMethods = false) +public class AfterSaleLogConfiguration { + + @Bean + public AfterSaleLogAspect afterSaleLogAspect() { + return new AfterSaleLogAspect(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/annotations/AfterSaleLog.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/annotations/AfterSaleLog.java new file mode 100644 index 0000000..bc41bf9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/annotations/AfterSaleLog.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations; + +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; +import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect; + +import java.lang.annotation.*; + +/** + * 售后日志的注解 + * + * 写在方法上时,会自动记录售后日志 + * + * @author 陈賝 + * @since 2023/6/8 17:04 + * @see AfterSaleLogAspect + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AfterSaleLog { + + /** + * 操作类型 + */ + AfterSaleOperateTypeEnum operateType(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java new file mode 100644 index 0000000..f7b3f7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.module.trade.framework.aftersale.core.aop; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService; +import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static java.util.Collections.emptyMap; + +/** + * 售后订单的操作记录的 AOP 切面 + * + * @author 陈賝 + * @since 2023/6/13 13:54 + */ +@Slf4j +@Aspect +public class AfterSaleLogAspect { + + /** + * 用户编号 + * + * 目前的使用场景:支付回调时,需要强制设置下用户编号 + */ + private static final ThreadLocal USER_ID = new ThreadLocal<>(); + /** + * 用户类型 + */ + private static final ThreadLocal USER_TYPE = new ThreadLocal<>(); + /** + * 订单编号 + */ + private static final ThreadLocal AFTER_SALE_ID = new ThreadLocal<>(); + /** + * 操作前的状态 + */ + private static final ThreadLocal BEFORE_STATUS = new ThreadLocal<>(); + /** + * 操作后的状态 + */ + private static final ThreadLocal AFTER_STATUS = new ThreadLocal<>(); + /** + * 拓展参数 Map,用于格式化操作内容 + */ + private static final ThreadLocal> EXTS = new ThreadLocal<>(); + + @Resource + private AfterSaleLogService afterSaleLogService; + + @AfterReturning(pointcut = "@annotation(afterSaleLog)") + public void doAfterReturning(JoinPoint joinPoint, AfterSaleLog afterSaleLog) { + try { + // 1.1 操作用户 + Integer userType = getUserType(); + Long userId = getUserId(); + // 1.2 售后信息 + Long afterSaleId = AFTER_SALE_ID.get(); + if (afterSaleId == null) { // 如果未设置,只有注解,说明不需要记录日志 + return; + } + Integer beforeStatus = BEFORE_STATUS.get(); + Integer afterStatus = AFTER_STATUS.get(); + Map exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap()); + String content = StrUtil.format(afterSaleLog.operateType().getContent(), exts); + + // 2. 记录日志 + AfterSaleLogCreateReqBO createBO = new AfterSaleLogCreateReqBO() + .setUserId(userId).setUserType(userType) + .setAfterSaleId(afterSaleId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus) + .setOperateType(afterSaleLog.operateType().getType()).setContent(content); + afterSaleLogService.createAfterSaleLog(createBO); + } catch (Exception exception) { + log.error("[doAfterReturning][afterSaleLog({}) 日志记录错误]", toJsonString(afterSaleLog), exception); + } finally { + clear(); + } + } + + /** + * 获得用户类型 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserType()} 系统 + * + * @return 用户类型 + */ + private static Integer getUserType() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM); + } + + /** + * 获得用户编号 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserId()} 系统 + * + * @return 用户类型 + */ + private static Long getUserId() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM); + } + + public static void setAfterSale(Long id, Integer beforeStatus, Integer afterStatus, Map exts) { + AFTER_SALE_ID.set(id); + BEFORE_STATUS.set(beforeStatus); + AFTER_STATUS.set(afterStatus); + EXTS.set(exts); + } + + public static void setUserInfo(Long userId, Integer userType) { + USER_ID.set(userId); + USER_TYPE.set(userType); + } + + private static void clear() { + USER_ID.remove(); + USER_TYPE.remove(); + AFTER_SALE_ID.remove(); + BEFORE_STATUS.remove(); + AFTER_STATUS.remove(); + EXTS.remove(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/utils/AfterSaleLogUtils.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/utils/AfterSaleLogUtils.java new file mode 100644 index 0000000..3f9fc5d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/utils/AfterSaleLogUtils.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.framework.aftersale.core.utils; + + +import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect; + +import java.util.Map; + +/** + * 操作日志工具类 + * 目前主要的作用,是提供给业务代码,记录操作明细和拓展字段 + * + * @author 芋道源码 + */ +public class AfterSaleLogUtils { + + public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus) { + setAfterSaleInfo(id, beforeStatus, afterStatus, null); + } + + public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus, + Map exts) { + AfterSaleLogAspect.setAfterSale(id, beforeStatus, afterStatus, exts); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/ExpressClientConfig.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/ExpressClientConfig.java new file mode 100644 index 0000000..2799c3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/ExpressClientConfig.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.config; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.ExpressClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + * 快递客户端端配置类: + * + * 1. 快递客户端工厂 {@link ExpressClientFactory} + * 2. 默认的快递客户端实现 {@link ExpressClient} + * + * @author jason + */ +@Configuration(proxyBeanMethods = false) +public class ExpressClientConfig { + + @Bean + public ExpressClientFactory expressClientFactory(TradeExpressProperties tradeExpressProperties, + RestTemplate restTemplate) { + return new ExpressClientFactoryImpl(tradeExpressProperties, restTemplate); + } + + @Bean + public ExpressClient defaultExpressClient(ExpressClientFactory expressClientFactory) { + return expressClientFactory.getDefaultExpressClient(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/TradeExpressProperties.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/TradeExpressProperties.java new file mode 100644 index 0000000..73efef9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/config/TradeExpressProperties.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.config; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.enums.ExpressClientEnum; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; + +// TODO @芋艿:未来要不要放数据库中?考虑 saas 多租户时,不同租户使用不同的配置? +/** + * 交易运费快递的配置项 + * + * @author jason + */ +@Component +@ConfigurationProperties(prefix = "yudao.trade.express") +@Data +@Validated +public class TradeExpressProperties { + + /** + * 快递客户端 + * + * 默认不提供,需要提醒用户配置一个快递服务商。 + */ + private ExpressClientEnum client = ExpressClientEnum.NOT_PROVIDE; + + /** + * 快递鸟配置 + */ + @Valid + private KdNiaoConfig kdNiao; + /** + * 快递 100 配置 + */ + @Valid + private Kd100Config kd100; + + /** + * 快递鸟配置项目 + */ + @Data + public static class KdNiaoConfig { + + /** + * 快递鸟用户 ID + */ + @NotEmpty(message = "快递鸟用户 ID 配置项不能为空") + private String businessId; + /** + * 快递鸟 API Key + */ + @NotEmpty(message = "快递鸟 Api Key 配置项不能为空") + private String apiKey; + + } + + /** + * 快递 100 配置项 + */ + @Data + public static class Kd100Config { + + /** + * 快递 100 授权码 + */ + @NotEmpty(message = "快递 100 授权码配置项不能为空") + private String customer; + /** + * 快递 100 授权 key + */ + @NotEmpty(message = "快递 100 授权 Key 配置项不能为空") + private String key; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClient.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClient.java new file mode 100644 index 0000000..76b361c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClient.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; + +import java.util.List; + +/** + * 快递客户端接口 + * + * @author jason + */ +public interface ExpressClient { + + /** + * 快递实时查询 + * + * @param reqDTO 查询请求参数 + */ + // TODO @jason:返回字段可以参考 https://doc.youzanyun.com/detail/API/0/5 响应的 data + List getExpressTrackList(ExpressTrackQueryReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClientFactory.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClientFactory.java new file mode 100644 index 0000000..5e45709 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/ExpressClientFactory.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.enums.ExpressClientEnum; + +/** + * 快递客户端工厂接口:用于创建和缓存快递客户端 + * + * @author jason + */ +public interface ExpressClientFactory { + + /** + * 获取默认的快递客户端 + */ + ExpressClient getDefaultExpressClient(); + + /** + * 通过枚举获取快递客户端,如果不存在,就创建一个对应快递客户端 + * + * @param clientEnum 快递客户端枚举 + */ + ExpressClient getOrCreateExpressClient(ExpressClientEnum clientEnum); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/convert/ExpressQueryConvert.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/convert/ExpressQueryConvert.java new file mode 100644 index 0000000..b68e119 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/convert/ExpressQueryConvert.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.convert; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100.Kd100ExpressQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100.Kd100ExpressQueryRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao.KdNiaoExpressQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao.KdNiaoExpressQueryRespDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface ExpressQueryConvert { + + ExpressQueryConvert INSTANCE = Mappers.getMapper(ExpressQueryConvert.class); + + List convertList(List list); + @Mapping(source = "acceptTime", target = "time") + @Mapping(source = "acceptStation", target = "content") + ExpressTrackRespDTO convert(KdNiaoExpressQueryRespDTO.ExpressTrack track); + + List convertList2(List list); + @Mapping(source = "context", target = "content") + ExpressTrackRespDTO convert(Kd100ExpressQueryRespDTO.ExpressTrack track); + + KdNiaoExpressQueryReqDTO convert(ExpressTrackQueryReqDTO dto); + + Kd100ExpressQueryReqDTO convert2(ExpressTrackQueryReqDTO dto); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackQueryReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackQueryReqDTO.java new file mode 100644 index 0000000..34ad012 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackQueryReqDTO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto; + +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import lombok.Data; + +/** + * 快递轨迹的查询 Req DTO + * + * @author jason + */ +@Data +public class ExpressTrackQueryReqDTO { + + /** + * 快递公司编码 + * + * 对应 {@link DeliveryExpressDO#getCode()} + */ + private String expressCode; + + /** + * 发货快递单号 + */ + private String logisticsNo; + + /** + * 收、寄件人的电话号码 + */ + private String phone; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackRespDTO.java new file mode 100644 index 0000000..bc99e1c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/ExpressTrackRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 快递查询的轨迹 Resp DTO + * + * @author jason + */ +@Data +public class ExpressTrackRespDTO { + + /** + * 发生时间 + */ + private LocalDateTime time; + + /** + * 快递状态 + */ + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryReqDTO.java new file mode 100644 index 0000000..7befc84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 快递 100 快递查询 Req DTO + * + * @author jason + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Kd100ExpressQueryReqDTO { + + /** + * 快递公司编码 + */ + @JsonProperty("com") + private String expressCode; + + /** + * 快递单号 + */ + @JsonProperty("num") + private String logisticsNo; + + /** + * 收、寄件人的电话号码 + */ + private String phone; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java new file mode 100644 index 0000000..9d33cac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 快递 100 实时快递查询 Resp DTO + * + * 参见 快递 100 文档 + * + * @author jason + */ +@Data +public class Kd100ExpressQueryRespDTO { + + /** + * 快递公司编码 + */ + @JsonProperty("com") + private String expressCompanyCode; + /** + * 快递单号 + */ + @JsonProperty("nu") + private String logisticsNo; + /** + * 快递单当前状态 + */ + private String state; + + /** + * 查询结果 + * + * 失败返回 "false" + */ + private String result; + /** + * 查询结果失败时的错误信息 + */ + private String message; + + /** + * 轨迹数组 + */ + @JsonProperty("data") + private List tracks; + + @Data + public static class ExpressTrack { + + /** + * 轨迹发生时间 + */ + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime time; + + /** + * 轨迹描述 + */ + private String context; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryReqDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryReqDTO.java new file mode 100644 index 0000000..bcb6e33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryReqDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 快递鸟快递查询 Req DTO + * + * @author jason + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class KdNiaoExpressQueryReqDTO { + + /** + * 快递公司编码 + */ + @JsonProperty("ShipperCode") + private String expressCode; + /** + * 快递单号 + */ + @JsonProperty("LogisticCode") + private String logisticsNo; + /** + * 订单编号 + */ + @JsonProperty("OrderCode") + private String orderNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java new file mode 100644 index 0000000..04a7c14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 快递鸟快递查询 Resp DTO + * + * 参见 快递鸟接口文档 + * + * @author jason + */ +@Data +public class KdNiaoExpressQueryRespDTO { + + /** + * 快递公司编码 + */ + @JsonProperty("ShipperCode") + private String shipperCode; + + /** + * 快递单号 + */ + @JsonProperty("LogisticCode") + private String logisticsNo; + + /** + * 订单编号 + */ + @JsonProperty("OrderCode") + private String orderNo; + + /** + * 用户 ID + */ + @JsonProperty("EBusinessID") + private String businessId; + + /** + * 普通物流状态 + * + * 0 - 暂无轨迹信息 + * 1 - 已揽收 + * 2 - 在途中 + * 3 - 签收 + * 4 - 问题件 + * 5 - 转寄 + * 6 - 清关 + */ + @JsonProperty("State") + private String state; + + /** + * 成功与否 + */ + @JsonProperty("Success") + private Boolean success; + /** + * 失败原因 + */ + @JsonProperty("Reason") + private String reason; + + /** + * 轨迹数组 + */ + @JsonProperty("Traces") + private List tracks; + + @Data + public static class ExpressTrack { + + /** + * 发生时间 + */ + @JsonProperty("AcceptTime") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime acceptTime; + + /** + * 轨迹描述 + */ + @JsonProperty("AcceptStation") + private String acceptStation; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/ExpressClientFactoryImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/ExpressClientFactoryImpl.java new file mode 100644 index 0000000..d4432b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/ExpressClientFactoryImpl.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressProperties; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kd100.Kd100ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kdniao.KdNiaoExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.enums.ExpressClientEnum; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory; +import lombok.AllArgsConstructor; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 快递客户端工厂实现类 + * + * @author jason + */ +@AllArgsConstructor +public class ExpressClientFactoryImpl implements ExpressClientFactory { + + private final Map clientMap = new ConcurrentHashMap<>(8); + + private final TradeExpressProperties tradeExpressProperties; + private final RestTemplate restTemplate; + + @Override + public ExpressClient getDefaultExpressClient() { + ExpressClient defaultClient = getOrCreateExpressClient(tradeExpressProperties.getClient()); + Assert.notNull("默认的快递客户端不能为空"); + return defaultClient; + } + + @Override + public ExpressClient getOrCreateExpressClient(ExpressClientEnum clientEnum) { + return clientMap.computeIfAbsent(clientEnum, + client -> createExpressClient(client, tradeExpressProperties)); + } + + private ExpressClient createExpressClient(ExpressClientEnum queryProviderEnum, + TradeExpressProperties tradeExpressProperties) { + switch (queryProviderEnum) { + case NOT_PROVIDE: + return new NoProvideExpressClient(); + case KD_NIAO: + return new KdNiaoExpressClient(restTemplate, tradeExpressProperties.getKdNiao()); + case KD_100: + return new Kd100ExpressClient(restTemplate, tradeExpressProperties.getKd100()); + } + return null; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/NoProvideExpressClient.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/NoProvideExpressClient.java new file mode 100644 index 0000000..7289710 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/NoProvideExpressClient.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl; + +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_CLIENT_NOT_PROVIDE; + +/** + * 未实现的快递客户端,用来提醒用户需要接入快递服务商, + * + * @author jason + */ +public class NoProvideExpressClient implements ExpressClient { + + @Override + public List getExpressTrackList(ExpressTrackQueryReqDTO reqDTO) { + throw exception(EXPRESS_CLIENT_NOT_PROVIDE); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kd100/Kd100ExpressClient.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kd100/Kd100ExpressClient.java new file mode 100644 index 0000000..f04abde --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kd100/Kd100ExpressClient.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kd100; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressProperties; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100.Kd100ExpressQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100.Kd100ExpressQueryRespDTO; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_ERROR; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_FAILED; +import static cn.iocoder.yudao.module.trade.framework.delivery.core.client.convert.ExpressQueryConvert.INSTANCE; + +/** + * 快递 100 客户端 + * + * @author jason + */ +@Slf4j +@AllArgsConstructor +public class Kd100ExpressClient implements ExpressClient { + + private static final String REAL_TIME_QUERY_URL = "https://poll.kuaidi100.com/poll/query.do"; + + private final RestTemplate restTemplate; + private final TradeExpressProperties.Kd100Config config; + + /** + * 查询快递轨迹 + * + * @see 接口文档 + * + * @param reqDTO 查询请求参数 + * @return 快递轨迹 + */ + @Override + public List getExpressTrackList(ExpressTrackQueryReqDTO reqDTO) { + // 发起请求 + Kd100ExpressQueryReqDTO requestDTO = INSTANCE.convert2(reqDTO) + .setExpressCode(reqDTO.getExpressCode().toLowerCase()); + Kd100ExpressQueryRespDTO respDTO = httpRequest(REAL_TIME_QUERY_URL, requestDTO, + Kd100ExpressQueryRespDTO.class); + + // 处理结果 + if (Objects.equals("false", respDTO.getResult())) { + throw exception(EXPRESS_API_QUERY_FAILED, respDTO.getMessage()); + } + if (CollUtil.isEmpty(respDTO.getTracks())) { + return Collections.emptyList(); + } + return INSTANCE.convertList2(respDTO.getTracks()); + } + + /** + * 快递 100 API 请求 + * + * @param url 请求 url + * @param req 对应请求的请求参数 + * @param respClass 对应请求的响应 class + * @param 每个请求的请求结构 Req DTO + * @param 每个请求的响应结构 Resp DTO + */ + private Resp httpRequest(String url, Req req, Class respClass) { + // 请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + // 请求体 + String param = JsonUtils.toJsonString(req); + String sign = generateReqSign(param, config.getKey(), config.getCustomer()); // 签名 + MultiValueMap requestBody = new LinkedMultiValueMap<>(); + requestBody.add("customer", config.getCustomer()); + requestBody.add("sign", sign); + requestBody.add("param", param); + log.debug("[httpRequest][请求参数({})]", requestBody); + + // 发送请求 + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + log.debug("[httpRequest][的响应结果({})]", responseEntity); + // 处理响应 + if (!responseEntity.getStatusCode().is2xxSuccessful()) { + throw exception(EXPRESS_API_QUERY_ERROR); + } + return JsonUtils.parseObject(responseEntity.getBody(), respClass); + } + + private String generateReqSign(String param, String key, String customer) { + String plainText = String.format("%s%s%s", param, key, customer); + return HexUtil.encodeHexStr(DigestUtil.md5(plainText), false); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kdniao/KdNiaoExpressClient.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kdniao/KdNiaoExpressClient.java new file mode 100644 index 0000000..1f11168 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/kdniao/KdNiaoExpressClient.java @@ -0,0 +1,125 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kdniao; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.net.URLEncodeUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressProperties; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClient; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao.KdNiaoExpressQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao.KdNiaoExpressQueryRespDTO; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_FAILED; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_API_QUERY_ERROR; +import static cn.iocoder.yudao.module.trade.framework.delivery.core.client.convert.ExpressQueryConvert.INSTANCE; + +/** + * 快递鸟客户端 + * + * @author jason + */ +@Slf4j +@AllArgsConstructor +public class KdNiaoExpressClient implements ExpressClient { + + private static final String REAL_TIME_QUERY_URL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"; + + /** + * 快递鸟即时查询免费版 RequestType + */ + private static final String REAL_TIME_FREE_REQ_TYPE = "1002"; + + private final RestTemplate restTemplate; + private final TradeExpressProperties.KdNiaoConfig config; + + /** + * 查询快递轨迹【免费版】 + * + * 仅支持 3 家:申通快递、圆通速递、百世快递 + * + * @see 接口文档 + * + * @param reqDTO 查询请求参数 + * @return 快递轨迹 + */ + @Override + public List getExpressTrackList(ExpressTrackQueryReqDTO reqDTO) { + // 发起请求 + KdNiaoExpressQueryReqDTO requestDTO = INSTANCE.convert(reqDTO) + .setExpressCode(reqDTO.getExpressCode().toUpperCase()); + KdNiaoExpressQueryRespDTO respDTO = httpRequest(REAL_TIME_QUERY_URL, REAL_TIME_FREE_REQ_TYPE, + requestDTO, KdNiaoExpressQueryRespDTO.class); + + // 处理结果 + if (respDTO == null || !respDTO.getSuccess()) { + throw exception(EXPRESS_API_QUERY_FAILED, respDTO == null ? "" : respDTO.getReason()); + } + if (CollUtil.isEmpty(respDTO.getTracks())) { + return Collections.emptyList(); + } + return INSTANCE.convertList(respDTO.getTracks()); + } + + /** + * 快递鸟 API 请求 + * + * @param url 请求 url + * @param requestType 对应的请求指令 (快递鸟的 RequestType) + * @param req 对应请求的请求参数 + * @param respClass 对应请求的响应 class + * @param 每个请求的请求结构 Req DTO + * @param 每个请求的响应结构 Resp DTO + */ + private Resp httpRequest(String url, String requestType, Req req, Class respClass) { + // 请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + // 请求体 + String reqData = JsonUtils.toJsonString(req); + String dataSign = generateDataSign(reqData, config.getApiKey()); + MultiValueMap requestBody = new LinkedMultiValueMap<>(); + requestBody.add("RequestData", reqData); + requestBody.add("DataType", "2"); + requestBody.add("EBusinessID", config.getBusinessId()); + requestBody.add("DataSign", dataSign); + requestBody.add("RequestType", requestType); + log.debug("[httpRequest][RequestType({}) 的请求参数({})]", requestType, requestBody); + + // 发送请求 + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + log.debug("[httpRequest][RequestType({}) 的响应结果({})", requestType, responseEntity); + // 处理响应 + if (!responseEntity.getStatusCode().is2xxSuccessful()) { + throw exception(EXPRESS_API_QUERY_ERROR); + } + return JsonUtils.parseObject(responseEntity.getBody(), respClass); + } + + /** + * 快递鸟生成请求签名 + * + * 参见 签名说明 + * + * @param reqData 请求实体 + * @param apiKey api Key + */ + private String generateDataSign(String reqData, String apiKey) { + String plainText = String.format("%s%s", reqData, apiKey); + return URLEncodeUtil.encode(Base64.encode(DigestUtil.md5Hex(plainText))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/enums/ExpressClientEnum.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/enums/ExpressClientEnum.java new file mode 100644 index 0000000..81b9618 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/enums/ExpressClientEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 快递客户端枚举 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum ExpressClientEnum { + + NOT_PROVIDE("not-provide","未提供"), + KD_NIAO("kd-niao", "快递鸟"), + KD_100("kd-100", "快递100"); + + /** + * 快递服务商唯一编码 + */ + private final String code; + /** + * 快递服务商名称 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderConfig.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderConfig.java new file mode 100644 index 0000000..7151692 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderConfig.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.trade.framework.order.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +// TODO @LeeYan9: 可以直接给 TradeOrderProperties 一个 @Component生效哈 +/** + * @author LeeYan9 + * @since 2022-09-15 + */ +@Configuration +@EnableConfigurationProperties(TradeOrderProperties.class) +public class TradeOrderConfig { +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java new file mode 100644 index 0000000..786c000 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.framework.order.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import java.time.Duration; + +/** + * 交易订单的配置项 + * + * @author LeeYan9 + * @since 2022-09-15 + */ +@ConfigurationProperties(prefix = "yudao.trade.order") +@Data +@Validated +public class TradeOrderProperties { + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + + /** + * 支付超时时间 + */ + @NotNull(message = "支付超时时间不能为空") + private Duration payExpireTime; + + /** + * 收货超时时间 + */ + @NotNull(message = "收货超时时间不能为空") + private Duration receiveExpireTime; + + /** + * 评论超时时间 + */ + @NotNull(message = "评论超时时间不能为空") + private Duration commentExpireTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java new file mode 100644 index 0000000..cc023c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.annotations; + +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; +import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; + +/** + * 交易订单的操作日志 AOP 注解 + * + * @author 陈賝 + * @since 2023/7/6 15:37 + * @see TradeOrderLogAspect + */ +@Target({METHOD, ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TradeOrderLog { + + /** + * 操作类型 + */ + TradeOrderOperateTypeEnum operateType(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java new file mode 100644 index 0000000..ccdf91c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.aop; + + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService; +import cn.iocoder.yudao.module.trade.service.order.bo.TradeOrderLogCreateReqBO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static java.util.Collections.emptyMap; + +/** + * 交易订单的操作日志的记录 AOP 切面 + * + * @author 陈賝 + * @since 2023/6/13 13:54 + */ +@Component +@Aspect +@Slf4j +public class TradeOrderLogAspect { + + /** + * 用户编号 + * + * 目前的使用场景:支付回调时,需要强制设置下用户编号 + */ + private static final ThreadLocal USER_ID = new ThreadLocal<>(); + /** + * 用户类型 + */ + private static final ThreadLocal USER_TYPE = new ThreadLocal<>(); + /** + * 订单编号 + */ + private static final ThreadLocal ORDER_ID = new ThreadLocal<>(); + /** + * 操作前的状态 + */ + private static final ThreadLocal BEFORE_STATUS = new ThreadLocal<>(); + /** + * 操作后的状态 + */ + private static final ThreadLocal AFTER_STATUS = new ThreadLocal<>(); + /** + * 拓展参数 Map,用于格式化操作内容 + */ + private static final ThreadLocal> EXTS = new ThreadLocal<>(); + + @Resource + private TradeOrderLogService orderLogService; + + @AfterReturning("@annotation(orderLog)") + public void doAfterReturning(JoinPoint joinPoint, TradeOrderLog orderLog) { + try { + // 1.1 操作用户 + Integer userType = getUserType(); + Long userId = getUserId(); + // 1.2 订单信息 + Long orderId = ORDER_ID.get(); + if (orderId == null) { // 如果未设置,只有注解,说明不需要记录日志 + return; + } + Integer beforeStatus = BEFORE_STATUS.get(); + Integer afterStatus = AFTER_STATUS.get(); + Map exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap()); + String content = StrUtil.format(orderLog.operateType().getContent(), exts); + + // 2. 记录日志 + TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO() + .setUserId(userId).setUserType(userType) + .setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus) + .setOperateType(orderLog.operateType().getType()).setContent(content); + orderLogService.createOrderLog(createBO); + } catch (Exception ex) { + log.error("[doAfterReturning][orderLog({}) 订单日志错误]", toJsonString(orderLog), ex); + } finally { + clear(); + } + } + + /** + * 获得用户类型 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserType()} 系统 + * + * @return 用户类型 + */ + private static Integer getUserType() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM); + } + + /** + * 获得用户编号 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserId()} 系统 + * + * @return 用户类型 + */ + private static Long getUserId() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM); + } + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, Map exts) { + ORDER_ID.set(id); + BEFORE_STATUS.set(beforeStatus); + AFTER_STATUS.set(afterStatus); + EXTS.set(exts); + } + + public static void setUserInfo(Long userId, Integer userType) { + USER_ID.set(userId); + USER_TYPE.set(userType); + } + + private static void clear() { + USER_ID.remove(); + USER_TYPE.remove(); + ORDER_ID.remove(); + BEFORE_STATUS.remove(); + AFTER_STATUS.remove(); + EXTS.remove(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java new file mode 100644 index 0000000..d134b75 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.utils; + +import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect; + +import java.util.Map; + +/** + * 交易订单的操作日志 Utils + * + * @author 芋道源码 + */ +public class TradeOrderLogUtils { + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus) { + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, null); + } + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, + Map exts) { + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts); + } + + public static void setUserInfo(Long userId, Integer userType) { + TradeOrderLogAspect.setUserInfo(userId, userType); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/package-info.java new file mode 100644 index 0000000..68c6711 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 trade 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.trade.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/config/TradeWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/config/TradeWebConfiguration.java new file mode 100644 index 0000000..707eaa8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/config/TradeWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * trade 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class TradeWebConfiguration { + + /** + * trade 模块的 API 分组 + */ + @Bean + public GroupedOpenApi tradeGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("trade"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/package-info.java new file mode 100644 index 0000000..2081798 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * trade 模块的 web 配置 + */ +package cn.iocoder.yudao.module.trade.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/brokerage/BrokerageRecordUnfreezeJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/brokerage/BrokerageRecordUnfreezeJob.java new file mode 100644 index 0000000..9e5bba1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/brokerage/BrokerageRecordUnfreezeJob.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.trade.job.brokerage; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 佣金解冻 Job + * + * @author owen + */ +@Component +public class BrokerageRecordUnfreezeJob implements JobHandler { + + @Resource + private BrokerageRecordService brokerageRecordService; + + @Override + @TenantJob + public String execute(String param) { + int count = brokerageRecordService.unfreezeRecord(); + return StrUtil.format("解冻佣金 {} 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java new file mode 100644 index 0000000..9da98b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.job.order; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 交易订单的自动过期 Job + * + * @author 芋道源码 + */ +@Component +public class TradeOrderAutoCancelJob implements JobHandler { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + + @Override + @TenantJob + public String execute(String param) { + int count = tradeOrderUpdateService.cancelOrderBySystem(); + return String.format("过期订单 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java new file mode 100644 index 0000000..c2090ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.job.order; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 交易订单的自动评论 Job + * + * @author 芋道源码 + */ +@Component +public class TradeOrderAutoCommentJob implements JobHandler { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + + @Override + @TenantJob + public String execute(String param) { + int count = tradeOrderUpdateService.createOrderItemCommentBySystem(); + return String.format("评论订单 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.java new file mode 100644 index 0000000..b378784 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.job.order; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 交易订单的自动收货 Job + * + * @author 芋道源码 + */ +@Component +public class TradeOrderAutoReceiveJob implements JobHandler { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + + @Override + @TenantJob + public String execute(String param) { + int count = tradeOrderUpdateService.receiveOrderBySystem(); + return String.format("自动收货 %s 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/package-info.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/package-info.java new file mode 100644 index 0000000..eba4aa7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/package-info.java @@ -0,0 +1,8 @@ +/** + * trade 模块,product 模块,主要实现商品相关功能 + * 例如:品牌、商品分类、spu、sku等功能。 + * + * 1. Controller URL:以 /product/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 product_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.trade; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogService.java new file mode 100644 index 0000000..2620ca0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogService.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + + +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO; + +import java.util.List; + +/** + * 交易售后日志 Service 接口 + * + * @author 陈賝 + * @since 2023/6/12 14:18 + */ +public interface AfterSaleLogService { + + /** + * 创建售后日志 + * + * @param createReqBO 日志记录 + * @author 陈賝 + * @since 2023/6/12 14:18 + */ + void createAfterSaleLog(AfterSaleLogCreateReqBO createReqBO); + + /** + * 获取售后日志 + * + * @param afterSaleId 售后编号 + * @return 售后日志 + */ + List getAfterSaleLogList(Long afterSaleId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogServiceImpl.java new file mode 100644 index 0000000..280af92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleLogServiceImpl.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleLogConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleLogMapper; +import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 交易售后日志 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class AfterSaleLogServiceImpl implements AfterSaleLogService { + + @Resource + private AfterSaleLogMapper afterSaleLogMapper; + + @Override + public void createAfterSaleLog(AfterSaleLogCreateReqBO createReqBO) { + AfterSaleLogDO afterSaleLog = AfterSaleLogConvert.INSTANCE.convert(createReqBO); + afterSaleLogMapper.insert(afterSaleLog); + } + + @Override + public List getAfterSaleLogList(Long afterSaleId) { + return afterSaleLogMapper.selectListByAfterSaleId(afterSaleId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleService.java new file mode 100644 index 0000000..1a0c1e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleService.java @@ -0,0 +1,127 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; + +/** + * 售后订单 Service 接口 + * + * @author 芋道源码 + */ +public interface AfterSaleService { + + /** + * 【管理员】获得售后订单分页 + * + * @param pageReqVO 分页查询 + * @return 售后订单分页 + */ + PageResult getAfterSalePage(AfterSalePageReqVO pageReqVO); + + /** + * 【会员】获得售后订单分页 + * + * @param userId 用户编号 + * @param pageParam 分页参数 + * @return 售后订单分页 + */ + PageResult getAfterSalePage(Long userId, PageParam pageParam); + + /** + * 【会员】获得售后单 + * + * @param userId 用户编号 + * @param id 售后编号 + * @return 售后订单 + */ + AfterSaleDO getAfterSale(Long userId, Long id); + + /** + * 【管理员】获得售后单 + * + * @param id 售后编号 + * @return 售后订单 + */ + AfterSaleDO getAfterSale(Long id); + + /** + * 【会员】创建售后订单 + * + * @param userId 会员用户编号 + * @param createReqVO 创建 Request 信息 + * @return 售后编号 + */ + Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO); + + /** + * 【管理员】同意售后订单 + * + * @param userId 管理员用户编号 + * @param id 售后编号 + */ + void agreeAfterSale(Long userId, Long id); + + /** + * 【管理员】拒绝售后订单 + * + * @param userId 管理员用户编号 + * @param auditReqVO 审批 Request 信息 + */ + void disagreeAfterSale(Long userId, AfterSaleDisagreeReqVO auditReqVO); + + /** + * 【会员】退回货物 + * + * @param userId 会员用户编号 + * @param deliveryReqVO 退货 Request 信息 + */ + void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO deliveryReqVO); + + /** + * 【管理员】确认收货 + * + * @param userId 管理员编号 + * @param id 售后编号 + */ + void receiveAfterSale(Long userId, Long id); + + /** + * 【管理员】拒绝收货 + * + * @param userId 管理员用户编号 + * @param refuseReqVO 拒绝收货 Request 信息 + */ + void refuseAfterSale(Long userId, AfterSaleRefuseReqVO refuseReqVO); + + /** + * 【管理员】确认退款 + * + * @param userId 管理员用户编号 + * @param userIp 管理员用户 IP + * @param id 售后编号 + */ + void refundAfterSale(Long userId, String userIp, Long id); + + /** + * 【会员】取消售后 + * + * @param userId 会员用户编号 + * @param id 售后编号 + */ + void cancelAfterSale(Long userId, Long id); + + /** + * 【会员】获得正在进行中的售后订单数量 + * + * @param userId 用户编号 + * @return 数量 + */ + Long getApplyingAfterSaleCount(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java new file mode 100644 index 0000000..d92db8a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java @@ -0,0 +1,415 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; +import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleMapper; +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog; +import cn.iocoder.yudao.module.trade.framework.aftersale.core.utils.AfterSaleLogUtils; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 售后订单 Service 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@Service +@Validated +public class AfterSaleServiceImpl implements AfterSaleService { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + @Resource + private DeliveryExpressService deliveryExpressService; + + @Resource + private AfterSaleMapper tradeAfterSaleMapper; + @Resource + private TradeNoRedisDAO tradeNoRedisDAO; + + @Resource + private PayRefundApi payRefundApi; + + @Resource + private TradeOrderProperties tradeOrderProperties; + + @Override + public PageResult getAfterSalePage(AfterSalePageReqVO pageReqVO) { + return tradeAfterSaleMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getAfterSalePage(Long userId, PageParam pageParam) { + return tradeAfterSaleMapper.selectPage(userId, pageParam); + } + + @Override + public AfterSaleDO getAfterSale(Long userId, Long id) { + return tradeAfterSaleMapper.selectByIdAndUserId(id, userId); + } + + @Override + public AfterSaleDO getAfterSale(Long id) { + return tradeAfterSaleMapper.selectById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CREATE) + public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) { + // 第一步,前置校验 + TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO); + + // 第二步,存储售后订单 + AfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem); + return afterSale.getId(); + } + + /** + * 校验交易订单项是否可以申请售后 + * + * @param userId 用户编号 + * @param createReqVO 售后创建信息 + * @return 交易订单项 + */ + private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) { + // 校验订单项存在 + TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(userId, createReqVO.getOrderItemId()); + if (orderItem == null) { + throw exception(ORDER_ITEM_NOT_FOUND); + } + // 已申请售后,不允许再发起售后申请 + if (!TradeOrderItemAfterSaleStatusEnum.isNone(orderItem.getAfterSaleStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED); + } + // 申请的退款金额,不能超过商品的价格 + if (createReqVO.getRefundPrice() > orderItem.getPayPrice()) { + throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR); + } + + // 校验订单存在 + TradeOrderDO order = tradeOrderQueryService.getOrder(userId, orderItem.getOrderId()); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // TODO 芋艿:超过一定时间,不允许售后 + // 已取消,无法发起售后 + if (TradeOrderStatusEnum.isCanceled(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED); + } + // 未支付,无法发起售后 + if (!TradeOrderStatusEnum.havePaid(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID); + } + // 如果是【退货退款】的情况,需要额外校验是否发货 + if (createReqVO.getWay().equals(AfterSaleWayEnum.RETURN_AND_REFUND.getWay()) + && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) { + throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED); + } + return orderItem; + } + + private AfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO, + TradeOrderItemDO orderItem) { + // 创建售后单 + AfterSaleDO afterSale = AfterSaleConvert.INSTANCE.convert(createReqVO, orderItem); + afterSale.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.AFTER_SALE_NO_PREFIX)); + afterSale.setStatus(AfterSaleStatusEnum.APPLY.getStatus()); + // 标记是售中还是售后 + TradeOrderDO order = tradeOrderQueryService.getOrder(orderItem.getUserId(), orderItem.getOrderId()); + afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水,方便后续检索 + afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus()) + ? AfterSaleTypeEnum.AFTER_SALE.getType() : AfterSaleTypeEnum.IN_SALE.getType()); + tradeAfterSaleMapper.insert(afterSale); + + // 更新交易订单项的售后状态 + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCreate(orderItem.getId(), afterSale.getId()); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), null, + AfterSaleStatusEnum.APPLY.getStatus()); + + // TODO 发送售后消息 + return afterSale; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_APPLY) + public void agreeAfterSale(Long userId, Long id) { + // 校验售后单存在,并状态未审批 + AfterSaleDO afterSale = validateAfterSaleAuditable(id); + + // 更新售后单的状态 + // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 + // 情况二:退货退款:需要等用户退货后,才能发起退款 + Integer newStatus = afterSale.getWay().equals(AfterSaleWayEnum.REFUND.getWay()) ? + AfterSaleStatusEnum.WAIT_REFUND.getStatus() : AfterSaleStatusEnum.SELLER_AGREE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus); + + // TODO 发送售后消息 + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_APPLY) + public void disagreeAfterSale(Long userId, AfterSaleDisagreeReqVO auditReqVO) { + // 校验售后单存在,并状态未审批 + AfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId()); + + // 更新售后单的状态 + Integer newStatus = AfterSaleStatusEnum.SELLER_DISAGREE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()) + .setAuditReason(auditReqVO.getAuditReason())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus); + + // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); + } + + /** + * 校验售后单是否可审批(同意售后、拒绝售后) + * + * @param id 售后编号 + * @return 售后单 + */ + private AfterSaleDO validateAfterSaleAuditable(Long id) { + AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) { + throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); + } + return afterSale; + } + + private void updateAfterSaleStatus(Long id, Integer status, AfterSaleDO updateObj) { + int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj); + if (updateCount == 0) { + throw exception(AFTER_SALE_UPDATE_STATUS_FAIL); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_DELIVERY) + public void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO deliveryReqVO) { + // 校验售后单存在,并状态未退货 + AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(deliveryReqVO.getId(), userId); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.SELLER_AGREE.getStatus())) { + throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE); + } + DeliveryExpressDO express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId()); + + // 更新售后单的物流信息 + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.SELLER_AGREE.getStatus(), new AfterSaleDO() + .setStatus(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus()) + .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()) + .setDeliveryTime(LocalDateTime.now())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), + AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), + MapUtil.builder().put("deliveryName", express.getName()) + .put("logisticsNo", deliveryReqVO.getLogisticsNo()).build()); + + // TODO 发送售后消息 + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_RECEIVE) + public void receiveAfterSale(Long userId, Long id) { + // 校验售后单存在,并状态为已退货 + AfterSaleDO afterSale = validateAfterSaleReceivable(id); + + // 更新售后单的状态 + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO() + .setStatus(AfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), + AfterSaleStatusEnum.WAIT_REFUND.getStatus()); + + // TODO 发送售后消息 + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_RECEIVE) + public void refuseAfterSale(Long userId, AfterSaleRefuseReqVO refuseReqVO) { + // 校验售后单存在,并状态为已退货 + AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(refuseReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); + } + + // 更新售后单的状态 + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO() + .setStatus(AfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now()) + .setReceiveReason(refuseReqVO.getRefuseMemo())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), + AfterSaleStatusEnum.SELLER_REFUSE.getStatus(), + MapUtil.of("reason", refuseReqVO.getRefuseMemo())); + + // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); + } + + /** + * 校验售后单是否可收货,即处于买家已发货 + * + * @param id 售后编号 + * @return 售后单 + */ + private AfterSaleDO validateAfterSaleReceivable(Long id) { + AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); + } + return afterSale; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_REFUND) + public void refundAfterSale(Long userId, String userIp, Long id) { + // 校验售后单的状态,并状态待退款 + AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.WAIT_REFUND.getStatus())) { + throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND); + } + + // 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起 + createPayRefund(userIp, afterSale); + + // 更新售后单的状态为【已完成】 + updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO() + .setStatus(AfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), + AfterSaleStatusEnum.COMPLETE.getStatus()); + + // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【已完成】 + tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice()); + } + + private void createPayRefund(String userIp, AfterSaleDO afterSale) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + // 创建退款单 + PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties) + .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName())); + Long payRefundId = payRefundApi.createRefund(createReqDTO); + // 更新售后单的退款单号 + tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL) + public void cancelAfterSale(Long userId, Long id) { + // 校验售后单的状态,并状态待退款 + AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(id, userId); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (!ObjectUtils.equalsAny(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus(), + AfterSaleStatusEnum.SELLER_AGREE.getStatus(), + AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { + throw exception(AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY); + } + + // 更新售后单的状态为【已取消】 + updateAfterSaleStatus(afterSale.getId(), afterSale.getStatus(), new AfterSaleDO() + .setStatus(AfterSaleStatusEnum.BUYER_CANCEL.getStatus())); + + // 记录售后日志 + AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), + AfterSaleStatusEnum.BUYER_CANCEL.getStatus()); + + // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId()); + } + + @Override + public Long getApplyingAfterSaleCount(Long userId) { + return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/bo/AfterSaleLogCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/bo/AfterSaleLogCreateReqBO.java new file mode 100644 index 0000000..5793fed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/bo/AfterSaleLogCreateReqBO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.trade.service.aftersale.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 售后日志的创建 Request BO + * + * @author 陈賝 + * @since 2023/6/19 09:54 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AfterSaleLogCreateReqBO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @NotNull(message = "用户类型不能为空") + private Integer userType; + + /** + * 售后编号 + */ + @NotNull(message = "售后编号不能为空") + private Long afterSaleId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + @NotNull(message = "操作后的状态不能为空") + private Integer afterStatus; + + /** + * 操作类型 + */ + @NotNull(message = "操作类型不能为空") + private Integer operateType; + /** + * 操作明细 + */ + @NotEmpty(message = "操作明细不能为空") + private String content; +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java new file mode 100644 index 0000000..1cf1e24 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByPriceRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO; + +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 佣金记录 Service 接口 + * + * @author owen + */ +public interface BrokerageRecordService { + + /** + * 获得佣金记录 + * + * @param id 编号 + * @return 佣金记录 + */ + BrokerageRecordDO getBrokerageRecord(Integer id); + + /** + * 获得佣金记录分页 + * + * @param pageReqVO 分页查询 + * @return 佣金记录分页 + */ + PageResult getBrokerageRecordPage(BrokerageRecordPageReqVO pageReqVO); + + /** + * 增加佣金【多级分佣】 + * + * @param userId 会员编号 + * @param bizType 业务类型 + * @param list 请求参数列表 + */ + void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, @Valid List list); + + /** + * 增加佣金【只针对自己】 + * + * @param userId 会员编号 + * @param bizType 业务类型 + * @param bizId 业务编号 + * @param brokeragePrice 佣金 + * @param title 标题 + */ + void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId, Integer brokeragePrice, String title); + + /** + * 减少佣金【只针对自己】 + * + * @param userId 会员编号 + * @param bizType 业务类型 + * @param bizId 业务编号 + * @param brokeragePrice 佣金 + * @param title 标题 + */ + default void reduceBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId, Integer brokeragePrice, String title) { + addBrokerage(userId, bizType, bizId, -brokeragePrice, title); + } + + /** + * 取消佣金:将佣金记录,状态修改为已失效 + * + * @param userId 会员编号 + * @param bizType 业务类型 + * @param bizId 业务编号 + */ + void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId); + + /** + * 解冻佣金:将待结算的佣金记录,状态修改为已结算 + * + * @return 解冻佣金的数量 + */ + int unfreezeRecord(); + + /** + * 按照 userId,汇总每个用户的佣金 + * + * @param userIds 用户编号 + * @param bizType 业务类型 + * @param status 佣金状态 + * @return 用户佣金汇总 List + */ + List getUserBrokerageSummaryListByUserId(Collection userIds, + Integer bizType, Integer status); + + /** + * 按照 userId,汇总每个用户的佣金 + * + * @param userIds 用户编号 + * @param bizType 业务类型 + * @param status 佣金状态 + * @return 用户佣金汇总 Map + */ + default Map getUserBrokerageSummaryMapByUserId(Collection userIds, + Integer bizType, Integer status) { + return convertMap(getUserBrokerageSummaryListByUserId(userIds, bizType, status), + UserBrokerageSummaryRespBO::getUserId); + } + + /** + * 获得用户佣金合计 + * + * @param userId 用户编号 + * @param bizType 业务类型 + * @param status 状态 + * @param beginTime 开始时间 + * @param endTime 截止时间 + * @return 用户佣金合计 + */ + Integer getSummaryPriceByUserId(Long userId, BrokerageRecordBizTypeEnum bizType, BrokerageRecordStatusEnum status, + LocalDateTime beginTime, LocalDateTime endTime); + + /** + * 获得用户佣金排行分页列表(基于佣金总数) + * + * @param pageReqVO 分页查询 + * @return 排行榜分页 + */ + PageResult getBrokerageUserChildSummaryPageByPrice( + AppBrokerageUserRankPageReqVO pageReqVO); + + /** + * 获取用户的排名(基于佣金总数) + * + * @param userId 用户编号 + * @param times 时间范围 + * @return 用户的排名 + */ + Integer getUserRankByPrice(Long userId, LocalDateTime[] times); + + /** + * 计算商品被购买后,推广员可以得到的佣金 + * + * @param userId 用户编号 + * @param spuId 商品编号 + * @return 用户佣金 + */ + AppBrokerageProductPriceRespVO calculateProductBrokeragePrice(Long userId, Long spuId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java new file mode 100644 index 0000000..8b60c4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java @@ -0,0 +1,368 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.*; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByPriceRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageRecordMapper; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMinValue; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH; + +/** + * 佣金记录 Service 实现类 + * + * @author owen + */ +@Slf4j +@Service +@Validated +public class BrokerageRecordServiceImpl implements BrokerageRecordService { + + @Resource + private BrokerageRecordMapper brokerageRecordMapper; + @Resource + private TradeConfigService tradeConfigService; + @Resource + private BrokerageUserService brokerageUserService; + + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Override + public BrokerageRecordDO getBrokerageRecord(Integer id) { + return brokerageRecordMapper.selectById(id); + } + + @Override + public PageResult getBrokerageRecordPage(BrokerageRecordPageReqVO pageReqVO) { + return brokerageRecordMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, List list) { + TradeConfigDO memberConfig = tradeConfigService.getTradeConfig(); + // 0 未启用分销功能 + if (memberConfig == null || !BooleanUtil.isTrue(memberConfig.getBrokerageEnabled())) { + log.warn("[addBrokerage][增加佣金失败:brokerageEnabled 未配置,userId({})", userId); + return; + } + + // 1.1 获得一级推广人 + BrokerageUserDO firstUser = brokerageUserService.getBindBrokerageUser(userId); + if (firstUser == null || !BooleanUtil.isTrue(firstUser.getBrokerageEnabled())) { + return; + } + // 1.2 计算一级分佣 + addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), + bizType, 1); + + // 2.1 获得二级推广员 + if (firstUser.getBindUserId() == null) { + return; + } + BrokerageUserDO secondUser = brokerageUserService.getBrokerageUser(firstUser.getBindUserId()); + if (secondUser == null || !BooleanUtil.isTrue(secondUser.getBrokerageEnabled())) { + return; + } + // 2.2 计算二级分佣 + addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), + bizType, 2); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) { + BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizIdAndUserId(bizType.getType(), bizId, userId); + if (record == null) { + log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); + return; + } + + // 1. 更新佣金记录为已失效 + BrokerageRecordDO updateObj = new BrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus()); + int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); + if (updateRows == 0) { + log.error("[cancelBrokerage][record({}) 更新为已失效失败]", record.getId()); + return; + } + + // 2. 更新用户的佣金 + if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) { + brokerageUserService.updateUserFrozenPrice(userId, -record.getPrice()); + } else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) { + brokerageUserService.updateUserPrice(userId, -record.getPrice()); + } + } + + /** + * 计算佣金 + * + * @param basePrice 佣金基数 + * @param percent 佣金比例 + * @param fixedPrice 固定佣金 + * @return 佣金 + */ + int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) { + // 1. 优先使用固定佣金 + if (fixedPrice != null && fixedPrice > 0) { + return ObjectUtil.defaultIfNull(fixedPrice, 0); + } + // 2. 根据比例计算佣金 + if (basePrice != null && basePrice > 0 && percent != null && percent > 0) { + return MoneyUtils.calculateRatePriceFloor(basePrice, Double.valueOf(percent)); + } + return 0; + } + + /** + * 增加用户佣金 + * + * @param user 用户 + * @param list 佣金增加参数列表 + * @param brokerageFrozenDays 冻结天数 + * @param brokeragePercent 佣金比例 + * @param bizType 业务类型 + * @param sourceUserLevel 来源用户等级 + */ + private void addBrokerage(BrokerageUserDO user, List list, Integer brokerageFrozenDays, + Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, Integer sourceUserLevel) { + // 1.1 处理冻结时间 + LocalDateTime unfreezeTime = null; + if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { + unfreezeTime = LocalDateTime.now().plusDays(brokerageFrozenDays); + } + // 1.2 计算分佣 + int totalBrokerage = 0; + List records = new ArrayList<>(); + for (BrokerageAddReqBO item : list) { + // 计算金额 + Integer fixedPrice; + if (Objects.equals(sourceUserLevel, 1)) { + fixedPrice = item.getFirstFixedPrice(); + } else if (Objects.equals(sourceUserLevel, 2)) { + fixedPrice = item.getSecondFixedPrice(); + } else { + throw new IllegalArgumentException(StrUtil.format("用户等级({}) 不合法", sourceUserLevel)); + } + int brokeragePrice = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice); + if (brokeragePrice <= 0) { + continue; + } + totalBrokerage += brokeragePrice; + // 创建记录实体 + records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(), + brokerageFrozenDays, brokeragePrice, unfreezeTime, item.getTitle(), + item.getSourceUserId(), sourceUserLevel)); + } + if (CollUtil.isEmpty(records)) { + return; + } + // 1.3 保存佣金记录 + brokerageRecordMapper.insertBatch(records); + + // 2. 更新用户佣金 + if (brokerageFrozenDays != null && brokerageFrozenDays > 0) { // 更新用户冻结佣金 + brokerageUserService.updateUserFrozenPrice(user.getId(), totalBrokerage); + } else { // 更新用户可用佣金 + brokerageUserService.updateUserPrice(user.getId(), totalBrokerage); + } + } + + @Override + public int unfreezeRecord() { + // 1. 查询待结算的佣金记录 + List records = brokerageRecordMapper.selectListByStatusAndUnfreezeTimeLt( + BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(records)) { + return 0; + } + + // 2. 遍历执行 + int count = 0; + for (BrokerageRecordDO record : records) { + try { + boolean success = getSelf().unfreezeRecord(record); + if (success) { + count++; + } + } catch (Exception e) { + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId(), e); + } + } + return count; + } + + /** + * 解冻单条佣金记录 + * + * @param record 佣金记录 + * @return 解冻是否成功 + */ + @Transactional(rollbackFor = Exception.class) + public boolean unfreezeRecord(BrokerageRecordDO record) { + // 更新记录状态 + BrokerageRecordDO updateObj = new BrokerageRecordDO() + .setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus()) + .setUnfreezeTime(LocalDateTime.now()); + int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); + if (updateRows == 0) { + log.error("[unfreezeRecord][record({}) 更新为已结算失败]", record.getId()); + return false; + } + + // 更新用户冻结佣金 + brokerageUserService.updateFrozenPriceDecrAndPriceIncr(record.getUserId(), -record.getPrice()); + log.info("[unfreezeRecord][record({}) 更新为已结算成功]", record.getId()); + return true; + } + + @Override + public List getUserBrokerageSummaryListByUserId(Collection userIds, + Integer bizType, Integer status) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + return brokerageRecordMapper.selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(userIds, bizType, status); + } + + @Override + public Integer getSummaryPriceByUserId(Long userId, BrokerageRecordBizTypeEnum bizType, BrokerageRecordStatusEnum status, + LocalDateTime beginTime, LocalDateTime endTime) { + return brokerageRecordMapper.selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(userId, + bizType.getType(), status.getStatus(), beginTime, endTime); + } + + @Override + public PageResult getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) { + IPage pageResult = brokerageRecordMapper.selectSummaryPricePageGroupByUserId( + MyBatisUtils.buildPage(pageReqVO), + BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), + ArrayUtil.get(pageReqVO.getTimes(), 0), ArrayUtil.get(pageReqVO.getTimes(), 1)); + return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); + } + + @Override + public Integer getUserRankByPrice(Long userId, LocalDateTime[] times) { + // 用户的推广金额 + Integer price = brokerageRecordMapper.selectSummaryPriceByUserIdAndBizTypeAndCreateTimeBetween(userId, + BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), + ArrayUtil.get(times, 0), ArrayUtil.get(times, 1)); + // 排在用户前面的人数 + Integer greaterCount = brokerageRecordMapper.selectCountByPriceGt(price, + BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), + ArrayUtil.get(times, 0), ArrayUtil.get(times, 1)); + // 获得排名 + return ObjUtil.defaultIfNull(greaterCount, 0) + 1; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId, Integer brokeragePrice, String title) { + // 1. 校验佣金余额 + BrokerageUserDO user = brokerageUserService.getBrokerageUser(userId); + int balance = Optional.of(user) + .map(BrokerageUserDO::getBrokeragePrice).orElse(0); + if (balance + brokeragePrice < 0) { + throw exception(BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH, MoneyUtils.fenToYuanStr(balance)); + } + + // 2. 更新佣金余额 + boolean success = brokerageUserService.updateUserPrice(userId, brokeragePrice); + if (!success) { + // 失败时,则抛出异常。只会出现扣减佣金时,余额不足的情况 + throw exception(BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH, MoneyUtils.fenToYuanStr(balance)); + } + + // 3. 新增记录 + BrokerageRecordDO record = BrokerageRecordConvert.INSTANCE.convert(user, bizType, bizId, 0, brokeragePrice, + null, title, null, null); + brokerageRecordMapper.insert(record); + } + + @Override + public AppBrokerageProductPriceRespVO calculateProductBrokeragePrice(Long userId, Long spuId) { + // 1. 构建默认的返回值 + AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO().setEnabled(false) + .setBrokerageMinPrice(0).setBrokerageMaxPrice(0); + + // 2.1 校验分销功能是否开启 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) { + return respVO; + } + // 2.2 校验用户是否有分销资格 + respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId())); + if (BooleanUtil.isFalse(respVO.getEnabled())) { + return respVO; + } + // 2.3 校验商品是否存在 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId); + if (spu == null) { + return respVO; + } + + // 3.1 商品单独分佣模式 + Integer fixedMinPrice = 0; + Integer fixedMaxPrice = 0; + Integer spuMinPrice = 0; + Integer spuMaxPrice = 0; + List skuList = productSkuApi.getSkuListBySpuId(ListUtil.of(spuId)); + if (BooleanUtil.isTrue(spu.getSubCommissionType())) { + fixedMinPrice = getMinValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); + fixedMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice); + // 3.2 全局分佣模式(根据商品价格比例计算) + } else { + spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice); + spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice); + } + respVO.setBrokerageMinPrice(calculatePrice(spuMinPrice, tradeConfig.getBrokerageFirstPercent(), fixedMinPrice)); + respVO.setBrokerageMaxPrice(calculatePrice(spuMaxPrice, tradeConfig.getBrokerageFirstPercent(), fixedMaxPrice)); + return respVO; + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private BrokerageRecordServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java new file mode 100644 index 0000000..e5b7e7a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; + +import javax.validation.constraints.NotNull; +import java.util.Collection; +import java.util.List; + +/** + * 分销用户 Service 接口 + * + * @author owen + */ +public interface BrokerageUserService { + + /** + * 获得分销用户 + * + * @param id 编号 + * @return 分销用户 + */ + BrokerageUserDO getBrokerageUser(Long id); + + /** + * 获得分销用户列表 + * + * @param ids 编号 + * @return 分销用户列表 + */ + List getBrokerageUserList(Collection ids); + + /** + * 获得分销用户分页 + * + * @param pageReqVO 分页查询 + * @return 分销用户分页 + */ + PageResult getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO); + + /** + * 修改推广员编号 + * + * @param id 用户编号 + * @param bindUserId 推广员编号 + */ + void updateBrokerageUserId(Long id, Long bindUserId); + + /** + * 修改推广资格 + * + * @param id 用户编号 + * @param enabled 推广资格 + */ + void updateBrokerageUserEnabled(Long id, Boolean enabled); + + /** + * 获得用户的推广人 + * + * @param id 用户编号 + * @return 用户的推广人 + */ + BrokerageUserDO getBindBrokerageUser(Long id); + + /** + * 更新用户佣金 + * + * @param id 用户编号 + * @param price 用户可用佣金 + * @return 更新结果 + */ + boolean updateUserPrice(Long id, Integer price); + + /** + * 更新用户冻结佣金 + * + * @param id 用户编号 + * @param frozenPrice 用户冻结佣金 + */ + void updateUserFrozenPrice(Long id, Integer frozenPrice); + + /** + * 更新用户冻结佣金(减少),更新用户佣金(增加) + * + * @param id 用户编号 + * @param frozenPrice 减少冻结佣金(负数) + */ + void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice); + + /** + * 获得推广用户数量 + * + * @param bindUserId 绑定的推广员编号 + * @param level 推广用户等级 + * @return 推广用户数量 + */ + Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level); + + /** + * 【会员】绑定推广员 + * + * @param userId 用户编号 + * @param bindUserId 推广员编号 + * @return 是否绑定 + */ + boolean bindBrokerageUser(@NotNull Long userId, @NotNull Long bindUserId); + + /** + * 获取用户是否有分销资格 + * + * @param userId 用户编号 + * @return 是否有分销资格 + */ + Boolean getUserBrokerageEnabled(Long userId); + + /** + * 获得推广人排行 + * + * @param pageReqVO 分页查询 + * @return 推广人排行 + */ + PageResult getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO); + + /** + * 获得下级分销统计分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 下级分销统计分页 + */ + PageResult getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java new file mode 100644 index 0000000..ff958a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java @@ -0,0 +1,356 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageUserConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMapByFilter; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 分销用户 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class BrokerageUserServiceImpl implements BrokerageUserService { + + @Resource + private BrokerageUserMapper brokerageUserMapper; + + @Resource + private TradeConfigService tradeConfigService; + + @Resource + private MemberUserApi memberUserApi; + + @Override + public BrokerageUserDO getBrokerageUser(Long id) { + return brokerageUserMapper.selectById(id); + } + + @Override + public List getBrokerageUserList(Collection ids) { + return brokerageUserMapper.selectBatchIds(ids); + } + + @Override + public PageResult getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) { + List childIds = getChildUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel()); + // 有”绑定用户编号“查询条件时,没有查到下级会员,直接返回空 + if (pageReqVO.getBindUserId() != null && CollUtil.isEmpty(childIds)) { + return PageResult.empty(); + } + return brokerageUserMapper.selectPage(pageReqVO, childIds); + } + + @Override + public void updateBrokerageUserId(Long id, Long bindUserId) { + // 校验存在 + BrokerageUserDO brokerageUser = validateBrokerageUserExists(id); + // 绑定关系未发生变化 + if (Objects.equals(brokerageUser.getBindUserId(), bindUserId)) { + return; + } + + // 情况一:清除推广员 + if (bindUserId == null) { + // 清除推广员 + brokerageUserMapper.updateBindUserIdAndBindUserTimeToNull(id); + return; + } + + // 情况二:修改推广员 + validateCanBindUser(brokerageUser, bindUserId); + brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(id))); + } + + @Override + public void updateBrokerageUserEnabled(Long id, Boolean enabled) { + // 校验存在 + validateBrokerageUserExists(id); + if (BooleanUtil.isTrue(enabled)) { + // 开通推广资格 + brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) + .setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now())); + } else { + // 取消推广资格 + brokerageUserMapper.updateEnabledFalseAndBrokerageTimeToNull(id); + } + } + + private BrokerageUserDO validateBrokerageUserExists(Long id) { + BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(id); + if (brokerageUserDO == null) { + throw exception(BROKERAGE_USER_NOT_EXISTS); + } + + return brokerageUserDO; + } + + @Override + public BrokerageUserDO getBindBrokerageUser(Long id) { + return Optional.ofNullable(id) + .map(this::getBrokerageUser) + .map(BrokerageUserDO::getBindUserId) + .map(this::getBrokerageUser) + .orElse(null); + } + + @Override + public boolean updateUserPrice(Long id, Integer price) { + if (price > 0) { + brokerageUserMapper.updatePriceIncr(id, price); + } else if (price < 0) { + return brokerageUserMapper.updatePriceDecr(id, price) > 0; + } + return true; + } + + @Override + public void updateUserFrozenPrice(Long id, Integer frozenPrice) { + if (frozenPrice > 0) { + brokerageUserMapper.updateFrozenPriceIncr(id, frozenPrice); + } else if (frozenPrice < 0) { + brokerageUserMapper.updateFrozenPriceDecr(id, frozenPrice); + } + } + + @Override + public void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice) { + Assert.isTrue(frozenPrice < 0); + int updateRows = brokerageUserMapper.updateFrozenPriceDecrAndPriceIncr(id, frozenPrice); + if (updateRows == 0) { + throw exception(BROKERAGE_USER_FROZEN_PRICE_NOT_ENOUGH); + } + } + + @Override + public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) { + List childIds = getChildUserIdsByLevel(bindUserId, level); + return (long) CollUtil.size(childIds); + } + + @Override + public boolean bindBrokerageUser(Long userId, Long bindUserId) { + // 1. 获得分销用户 + boolean isNewBrokerageUser = false; + BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); + if (brokerageUser == null) { // 分销用户不存在的情况:1. 新注册;2. 旧数据;3. 分销功能关闭后又打开 + isNewBrokerageUser = true; + brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0); + } + + // 2.1 校验是否能绑定用户 + boolean validated = isUserCanBind(brokerageUser); + if (!validated) { + return false; + } + // 2.3 校验能否绑定 + validateCanBindUser(brokerageUser, bindUserId); + // 2.3 绑定用户 + if (isNewBrokerageUser) { + Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); + if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格 + brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now()); + } + brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()); + brokerageUserMapper.insert(fillBindUserData(bindUserId, brokerageUser)); + } else { + brokerageUserMapper.updateById(fillBindUserData(bindUserId, new BrokerageUserDO().setId(userId))); + } + return true; + } + + /** + * 补全绑定用户的字段 + * + * @param bindUserId 绑定的用户编号 + * @param brokerageUser update 对象 + * @return 补全后的 update 对象 + */ + private BrokerageUserDO fillBindUserData(Long bindUserId, BrokerageUserDO brokerageUser) { + return brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()); + } + + @Override + public Boolean getUserBrokerageEnabled(Long userId) { + // 全局分销功能是否开启 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) { + return false; + } + + // 用户是否有分销资格 + return Optional.ofNullable(getBrokerageUser(userId)) + .map(BrokerageUserDO::getBrokerageEnabled) + .orElse(false); + } + + @Override + public PageResult getBrokerageUserRankPageByUserCount(AppBrokerageUserRankPageReqVO pageReqVO) { + IPage pageResult = brokerageUserMapper.selectCountPageGroupByBindUserId(MyBatisUtils.buildPage(pageReqVO), + ArrayUtil.get(pageReqVO.getTimes(), 0), ArrayUtil.get(pageReqVO.getTimes(), 1)); + return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); + } + + @Override + public PageResult getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId) { + // 1.1 查询下级用户编号列表 + List childIds = getChildUserIdsByLevel(userId, pageReqVO.getLevel()); + if (CollUtil.isEmpty(childIds)) { + return PageResult.empty(); + } + // 1.2 根据昵称过滤下级用户 + List users = memberUserApi.getUserList(childIds); + Map userMap = convertMapByFilter(users, + user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()), + MemberUserRespDTO::getId); + if (CollUtil.isEmpty(userMap)) { + return PageResult.empty(); + } + + // 2. 分页查询 + IPage pageResult = brokerageUserMapper.selectSummaryPageByUserId( + MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(), + BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), userMap.keySet(), pageReqVO.getSortingField() + ); + + // 3. 拼接数据并返回 + BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap); + return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); + } + + private boolean isUserCanBind(BrokerageUserDO user) { + // 校验分销功能是否启用 + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { + return false; + } + + // 校验分佣模式:仅可后台手动设置推广员 + if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) { + throw exception(BROKERAGE_BIND_CONDITION_ADMIN); + } + + // 校验分销关系绑定模式 + if (BrokerageBindModeEnum.REGISTER.getMode().equals(tradeConfig.getBrokerageBindMode())) { + // 判断是否为新用户:注册时间在 30 秒内的,都算新用户 + if (!isNewRegisterUser(user.getId())) { + throw exception(BROKERAGE_BIND_MODE_REGISTER); // 只有在注册时可以绑定 + } + } else if (BrokerageBindModeEnum.ANYTIME.getMode().equals(tradeConfig.getBrokerageBindMode())) { + if (user.getBindUserId() != null) { + throw exception(BROKERAGE_BIND_OVERRIDE); // 已绑定了推广人 + } + } + return true; + } + + /** + * 判断是否为新用户 + *

+ * 标准:注册时间在 30 秒内的,都算新用户 + *

+ * 疑问:为什么通过这样的方式实现? + * 回答:因为注册在 member 模块,希望它和 trade 模块解耦,所以只能用这种约定的逻辑。 + * + * @param userId 用户编号 + * @return 是否新用户 + */ + private boolean isNewRegisterUser(Long userId) { + MemberUserRespDTO user = memberUserApi.getUser(userId); + return user != null && LocalDateTimeUtils.afterNow(user.getCreateTime().plusSeconds(30)); + } + + private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) { + // 校验要绑定的用户有无推广资格 + BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId); + if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) { + throw exception(BROKERAGE_BIND_USER_NOT_ENABLED); + } + + // 校验绑定自己 + if (Objects.equals(user.getId(), bindUserId)) { + throw exception(BROKERAGE_BIND_SELF); + } + + // 下级不能绑定自己的上级 + for (int i = 0; i <= Short.MAX_VALUE; i++) { + if (Objects.equals(bindUser.getBindUserId(), user.getId())) { + throw exception(BROKERAGE_BIND_LOOP); + } + bindUser = getBrokerageUser(bindUser.getBindUserId()); + // 找到根节点,结束循环 + if (bindUser == null || bindUser.getBindUserId() == null) { + break; + } + } + } + + /** + * 根据绑定用户编号,获得下级用户编号列表 + * + * @param bindUserId 绑定用户编号 + * @param level 下级用户的层级。 + * 如果 level 为空,则查询 1+2 两个层级 + * @return 下级用户编号列表 + */ + private List getChildUserIdsByLevel(Long bindUserId, Integer level) { + if (bindUserId == null) { + return Collections.emptyList(); + } + // 先查第 1 级 + List bindUserIds = brokerageUserMapper.selectIdListByBindUserIdIn(Collections.singleton(bindUserId)); + if (CollUtil.isEmpty(bindUserIds)) { + return Collections.emptyList(); + } + + // 情况一:level 为空,查询所有级别 + if (level == null) { + // 再查第 2 级,并合并结果 + bindUserIds.addAll(brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds)); + return bindUserIds; + } + // 情况二:level 为 1,只查询第 1 级 + if (level == 1) { + return bindUserIds; + } + // 情况三:level 为 1,只查询第 2 级 + if (level == 2) { + return brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds); + } + throw exception(BROKERAGE_USER_LEVEL_NOT_SUPPORT); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java new file mode 100644 index 0000000..04ea9c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 佣金提现 Service 接口 + * + * @author 芋道源码 + */ +public interface BrokerageWithdrawService { + + /** + * 【管理员】审核佣金提现 + * + * @param id 佣金编号 + * @param status 审核状态 + * @param auditReason 驳回原因 + */ + void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason); + + /** + * 获得佣金提现 + * + * @param id 编号 + * @return 佣金提现 + */ + BrokerageWithdrawDO getBrokerageWithdraw(Integer id); + + /** + * 获得佣金提现分页 + * + * @param pageReqVO 分页查询 + * @return 佣金提现分页 + */ + PageResult getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO); + + /** + * 【会员】创建佣金提现 + * + * @param userId 会员用户编号 + * @param createReqVO 创建信息 + * @return 佣金提现编号 + */ + Long createBrokerageWithdraw(Long userId, AppBrokerageWithdrawCreateReqVO createReqVO); + + /** + * 按照 userId,汇总每个用户的提现 + * + * @param userIds 用户编号 + * @param status 提现状态 + * @return 用户提现汇总 List + */ + List getWithdrawSummaryListByUserId(Collection userIds, + BrokerageWithdrawStatusEnum status); + + /** + * 按照 userId,汇总每个用户的提现 + * + * @param userIds 用户编号 + * @param status 提现状态 + * @return 用户提现汇总 Map + */ + default Map getWithdrawSummaryMapByUserId(Set userIds, + BrokerageWithdrawStatusEnum status) { + return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java new file mode 100644 index 0000000..b6b4034 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java @@ -0,0 +1,181 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; +import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageWithdrawMapper; +import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 佣金提现 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { + + @Resource + private BrokerageWithdrawMapper brokerageWithdrawMapper; + + @Resource + private BrokerageRecordService brokerageRecordService; + @Resource + private TradeConfigService tradeConfigService; + + @Resource + private NotifyMessageSendApi notifyMessageSendApi; + + @Resource + private Validator validator; + + @Override + @Transactional(rollbackFor = Exception.class) + public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason) { + // 1.1 校验存在 + BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); + // 1.2 校验状态为审核中 + if (ObjectUtil.notEqual(BrokerageWithdrawStatusEnum.AUDITING.getStatus(), withdraw.getStatus())) { + throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING); + } + + // 2. 更新 + int rows = brokerageWithdrawMapper.updateByIdAndStatus(id, BrokerageWithdrawStatusEnum.AUDITING.getStatus(), + new BrokerageWithdrawDO().setStatus(status.getStatus()).setAuditReason(auditReason).setAuditTime(LocalDateTime.now())); + if (rows == 0) { + throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING); + } + + String templateCode; + if (BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.equals(status)) { + templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE; + // 3.1 通过时佣金转余额 + if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) { + // todo 疯狂: + } + // TODO 疯狂:调用转账接口 + } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) { + templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT; + // 3.2 驳回时需要退还用户佣金 + brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT, + String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle()); + } else { + throw new IllegalArgumentException("不支持的提现状态:" + status); + } + + // 4. 通知用户 + Map templateParams = MapUtil.builder() + .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime())) + .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice())) + .put("reason", withdraw.getAuditReason()) + .build(); + notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO() + .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams)); + } + + private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) { + BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id); + if (withdraw == null) { + throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS); + } + return withdraw; + } + + @Override + public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) { + return brokerageWithdrawMapper.selectById(id); + } + + @Override + public PageResult getBrokerageWithdrawPage(BrokerageWithdrawPageReqVO pageReqVO) { + return brokerageWithdrawMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createBrokerageWithdraw(Long userId, AppBrokerageWithdrawCreateReqVO createReqVO) { + // 1.1 校验提现金额 + TradeConfigDO tradeConfig = validateWithdrawPrice(createReqVO.getPrice()); + // 1.2 校验提现参数 + createReqVO.validate(validator); + + // 2.1 计算手续费 + Integer feePrice = calculateFeePrice(createReqVO.getPrice(), tradeConfig.getBrokerageWithdrawFeePercent()); + // 2.2 创建佣金提现记录 + BrokerageWithdrawDO withdraw = BrokerageWithdrawConvert.INSTANCE.convert(createReqVO, userId, feePrice); + brokerageWithdrawMapper.insert(withdraw); + + // 3. 创建用户佣金记录 + // 注意,佣金是否充足,reduceBrokerage 已经进行校验 + brokerageRecordService.reduceBrokerage(userId, BrokerageRecordBizTypeEnum.WITHDRAW, String.valueOf(withdraw.getId()), + createReqVO.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW.getTitle()); + return withdraw.getId(); + } + + @Override + public List getWithdrawSummaryListByUserId(Collection userIds, + BrokerageWithdrawStatusEnum status) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); + } + + /** + * 计算提现手续费 + * + * @param withdrawPrice 提现金额 + * @param percent 手续费百分比 + * @return 提现手续费 + */ + Integer calculateFeePrice(Integer withdrawPrice, Integer percent) { + Integer feePrice = 0; + if (percent != null && percent > 0) { + feePrice = MoneyUtils.calculateRatePrice(withdrawPrice, Double.valueOf(percent)); + } + return feePrice; + } + + /** + * 校验提现金额要求 + * + * @param withdrawPrice 提现金额 + * @return 分销配置 + */ + TradeConfigDO validateWithdrawPrice(Integer withdrawPrice) { + TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); + if (tradeConfig.getBrokerageWithdrawMinPrice() != null && withdrawPrice < tradeConfig.getBrokerageWithdrawMinPrice()) { + throw exception(BROKERAGE_WITHDRAW_MIN_PRICE, MoneyUtils.fenToYuanStr(tradeConfig.getBrokerageWithdrawMinPrice())); + } + return tradeConfig; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java new file mode 100644 index 0000000..1b5de54 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.trade.service.brokerage.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 佣金 增加 Request BO + * + * @author owen + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BrokerageAddReqBO { + + /** + * 业务编号 + */ + @NotBlank(message = "业务编号不能为空") + private String bizId; + /** + * 佣金基数 + */ + @NotNull(message = "佣金基数不能为空") + private Integer basePrice; + /** + * 一级佣金(固定) + */ + @NotNull(message = "一级佣金(固定)不能为空") + private Integer firstFixedPrice; + /** + * 二级佣金(固定) + */ + private Integer secondFixedPrice; + + /** + * 来源用户编号 + */ + @NotNull(message = "来源用户编号不能为空") + private Long sourceUserId; + + /** + * 佣金记录标题 + */ + @NotEmpty(message = "佣金记录标题不能为空") + private String title; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageWithdrawSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageWithdrawSummaryRespBO.java new file mode 100644 index 0000000..1c3a3c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageWithdrawSummaryRespBO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.trade.service.brokerage.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 佣金提现合计 BO + * + * @author owen + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BrokerageWithdrawSummaryRespBO { + + /** + * 用户编号 + */ + private Long userId; + + /** + * 提现次数 + */ + private Integer count; + /** + * 提现金额 + */ + private Integer price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryRespBO.java new file mode 100644 index 0000000..3e677b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryRespBO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.trade.service.brokerage.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 用户佣金合计 BO + * + * @author owen + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserBrokerageSummaryRespBO { + + /** + * 用户编号 + */ + private Long userId; + /** + * 推广数量 + */ + private Integer count; + /** + * 佣金总额 + */ + private Integer price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartService.java new file mode 100644 index 0000000..6130614 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartService.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.trade.service.cart; + +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.*; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 购物车 Service 接口 + * + * @author 芋道源码 + */ +public interface CartService { + + /** + * 添加商品到购物车 + * + * @param userId 用户编号 + * @param addReqVO 添加信息 + * @return 购物项的编号 + */ + Long addCart(Long userId, @Valid AppCartAddReqVO addReqVO); + + /** + * 更新购物车商品数量 + * + * @param userId 用户编号 + * @param updateCountReqVO 更新信息 + */ + void updateCartCount(Long userId, AppCartUpdateCountReqVO updateCountReqVO); + + /** + * 更新购物车选中状态 + * + * @param userId 用户编号 + * @param updateSelectedReqVO 更新信息 + */ + void updateCartSelected(Long userId, @Valid AppCartUpdateSelectedReqVO updateSelectedReqVO); + + /** + * 重置购物车商品 + * + * 使用场景:在一个购物车项对应的商品失效(例如说 SPU 被下架),可以重新选择对应的 SKU + * + * @param userId 用户编号 + * @param updateReqVO 重置信息 + */ + void resetCart(Long userId, AppCartResetReqVO updateReqVO); + + /** + * 删除购物车商品 + * + * @param userId 用户编号 + * @param ids 购物项的编号 + */ + void deleteCart(Long userId, Collection ids); + + /** + * 查询用户在购物车中的商品数量 + * + * @param userId 用户编号 + * @return 商品数量 + */ + Integer getCartCount(Long userId); + + /** + * 查询用户的购物车列表 + * + * @param userId 用户编号 + * @return 购物车列表 + */ + AppCartListRespVO getCartList(Long userId); + + /** + * 查询用户的购物车列表 + * + * @param userId 用户编号 + * @param ids 购物项的编号 + * @return 购物车列表 + */ + List getCartList(Long userId, Set ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartServiceImpl.java new file mode 100644 index 0000000..261f2b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/CartServiceImpl.java @@ -0,0 +1,196 @@ +package cn.iocoder.yudao.module.trade.service.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.*; +import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import cn.iocoder.yudao.module.trade.dal.mysql.cart.CartMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_NOT_FOUND; +import static java.util.Collections.emptyList; + +/** + * 购物车 Service 实现类 + * + * // TODO 芋艿:未来优化:购物车的价格计算,支持营销信息;目前不支持的原因,前端界面需要前端 pr 支持下;例如说:会员价格; + * + * @author 芋道源码 + */ +@Service +@Validated +public class CartServiceImpl implements CartService { + + @Resource + private CartMapper cartMapper; + + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Override + public Long addCart(Long userId, AppCartAddReqVO addReqVO) { + // 查询 TradeCartDO + CartDO cart = cartMapper.selectByUserIdAndSkuId(userId, addReqVO.getSkuId()); + // 校验 SKU + Integer count = addReqVO.getCount(); + ProductSkuRespDTO sku = checkProductSku(addReqVO.getSkuId(), count); + + // 情况一:存在,则进行数量更新 + if (cart != null) { + cartMapper.updateById(new CartDO().setId(cart.getId()).setSelected(true) + .setCount(cart.getCount() + count)); + return cart.getId(); + // 情况二:不存在,则进行插入 + } else { + cart = new CartDO().setUserId(userId).setSelected(true) + .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count); + cartMapper.insert(cart); + } + return cart.getId(); + } + + @Override + public void updateCartCount(Long userId, AppCartUpdateCountReqVO updateReqVO) { + // 校验 TradeCartDO 存在 + CartDO cart = cartMapper.selectById(updateReqVO.getId(), userId); + if (cart == null) { + throw exception(CARD_ITEM_NOT_FOUND); + } + // 校验商品 SKU + checkProductSku(cart.getSkuId(), updateReqVO.getCount()); + + // 更新数量 + cartMapper.updateById(new CartDO().setId(cart.getId()) + .setCount(updateReqVO.getCount())); + } + + @Override + public void updateCartSelected(Long userId, AppCartUpdateSelectedReqVO updateSelectedReqVO) { + cartMapper.updateByIds(updateSelectedReqVO.getIds(), userId, + new CartDO().setSelected(updateSelectedReqVO.getSelected())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void resetCart(Long userId, AppCartResetReqVO resetReqVO) { + // 第一步:删除原本的购物项 + CartDO oldCart = cartMapper.selectById(resetReqVO.getId(), userId); + if (oldCart == null) { + throw exception(CARD_ITEM_NOT_FOUND); + } + cartMapper.deleteById(oldCart.getId()); + + // 第二步:添加新的购物项 + CartDO newCart = cartMapper.selectByUserIdAndSkuId(userId, resetReqVO.getSkuId()); + if (newCart != null) { + updateCartCount(userId, new AppCartUpdateCountReqVO() + .setId(newCart.getId()).setCount(resetReqVO.getCount())); + } else { + addCart(userId, new AppCartAddReqVO().setSkuId(resetReqVO.getSkuId()) + .setCount(resetReqVO.getCount())); + } + } + + /** + * 购物车删除商品 + * + * @param userId 用户编号 + * @param ids 商品 SKU 编号的数组 + */ + @Override + public void deleteCart(Long userId, Collection ids) { + // 查询 TradeCartDO 列表 + List carts = cartMapper.selectListByIds(ids, userId); + if (CollUtil.isEmpty(carts)) { + return; + } + + // 批量标记删除 + cartMapper.deleteBatchIds(ids); + } + + @Override + public Integer getCartCount(Long userId) { + // TODO 芋艿:需要算上 selected + return cartMapper.selectSumByUserId(userId); + } + + @Override + public AppCartListRespVO getCartList(Long userId) { + // 获得购物车的商品 + List carts = cartMapper.selectListByUserId(userId); + carts.sort(Comparator.comparing(CartDO::getId).reversed()); + // 如果未空,则返回空结果 + if (CollUtil.isEmpty(carts)) { + return new AppCartListRespVO().setValidList(emptyList()) + .setInvalidList(emptyList()); + } + + // 查询 SPU、SKU 列表 + List spus = productSpuApi.getSpuList(convertSet(carts, CartDO::getSpuId)); + List skus = productSkuApi.getSkuList(convertSet(carts, CartDO::getSkuId)); + + // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 + // 为什么不是 SKU 被删除呢?因为 SKU 被删除时,还可以通过 SPU 选择其它 SKU + deleteCartIfSpuDeleted(carts, spus); + + // 拼接数据 + return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); + } + + @Override + public List getCartList(Long userId, Set ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return cartMapper.selectListByUserId(userId, ids); + } + + private void deleteCartIfSpuDeleted(List carts, List spus) { + // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 + carts.removeIf(cart -> { + if (spus.stream().noneMatch(spu -> spu.getId().equals(cart.getSpuId()))) { + cartMapper.deleteById(cart.getId()); + return true; + } + return false; + }); + } + + /** + * 校验商品 SKU 是否合法 + * 1. 是否存在 + * 2. 是否下架 + * 3. 库存不足 + * + * @param skuId 商品 SKU 编号 + * @param count 商品数量 + * @return 商品 SKU + */ + private ProductSkuRespDTO checkProductSku(Long skuId, Integer count) { + ProductSkuRespDTO sku = productSkuApi.getSku(skuId); + if (sku == null) { + throw exception(SKU_NOT_EXISTS); + } + if (count > sku.getStock()) { + throw exception(SKU_STOCK_NOT_ENOUGH); + } + return sku; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigService.java new file mode 100644 index 0000000..1edb4f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigService.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.trade.service.config; + +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; + +import javax.validation.Valid; + +/** + * 交易中心配置 Service 接口 + * + * @author owen + */ +public interface TradeConfigService { + + /** + * 更新交易中心配置 + * + * @param updateReqVO 更新信息 + */ + void saveTradeConfig(@Valid TradeConfigSaveReqVO updateReqVO); + + /** + * 获得交易中心配置 + * + * @return 交易中心配置 + */ + TradeConfigDO getTradeConfig(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigServiceImpl.java new file mode 100644 index 0000000..c859cde --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/config/TradeConfigServiceImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.service.config; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO; +import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.dal.mysql.config.TradeConfigMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 交易中心配置 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class TradeConfigServiceImpl implements TradeConfigService { + + @Resource + private TradeConfigMapper tradeConfigMapper; + + @Override + public void saveTradeConfig(TradeConfigSaveReqVO saveReqVO) { + // 存在,则进行更新 + TradeConfigDO dbConfig = getTradeConfig(); + if (dbConfig != null) { + tradeConfigMapper.updateById(TradeConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId())); + return; + } + // 不存在,则进行插入 + tradeConfigMapper.insert(TradeConfigConvert.INSTANCE.convert(saveReqVO)); + } + + @Override + public TradeConfigDO getTradeConfig() { + List list = tradeConfigMapper.selectList(); + return CollectionUtils.getFirst(list); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressService.java new file mode 100644 index 0000000..c504b30 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 快递公司 Service 接口 + * + * @author jason + */ +public interface DeliveryExpressService { + + /** + * 创建快递公司 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDeliveryExpress(@Valid DeliveryExpressCreateReqVO createReqVO); + + /** + * 更新快递公司 + * + * @param updateReqVO 更新信息 + */ + void updateDeliveryExpress(@Valid DeliveryExpressUpdateReqVO updateReqVO); + + /** + * 删除快递公司 + * + * @param id 编号 + */ + void deleteDeliveryExpress(Long id); + + /** + * 获得快递公司 + * + * @param id 编号 + * @return 快递公司 + */ + DeliveryExpressDO getDeliveryExpress(Long id); + + /** + * 校验快递公司是否合法 + * + * @param id 编号 + * @return 快递公司 + */ + DeliveryExpressDO validateDeliveryExpress(Long id); + + /** + * 获得快递公司分页 + * + * @param pageReqVO 分页查询 + * @return 快递公司分页 + */ + PageResult getDeliveryExpressPage(DeliveryExpressPageReqVO pageReqVO); + + /** + * 获得快递公司列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 快递公司列表 + */ + List getDeliveryExpressList(DeliveryExpressExportReqVO exportReqVO); + + /** + * 获取指定状态的快递公司列表 + * + * @param status 状态 + * @return 快递公司列表 + */ + List getDeliveryExpressListByStatus(Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressServiceImpl.java new file mode 100644 index 0000000..ec787af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressServiceImpl.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 快递公司 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class DeliveryExpressServiceImpl implements DeliveryExpressService { + + @Resource + private DeliveryExpressMapper deliveryExpressMapper; + + @Override + public Long createDeliveryExpress(DeliveryExpressCreateReqVO createReqVO) { + //校验编码是否唯一 + validateExpressCodeUnique(createReqVO.getCode(), null); + // 插入 + DeliveryExpressDO deliveryExpress = DeliveryExpressConvert.INSTANCE.convert(createReqVO); + deliveryExpressMapper.insert(deliveryExpress); + // 返回 + return deliveryExpress.getId(); + } + + @Override + public void updateDeliveryExpress(DeliveryExpressUpdateReqVO updateReqVO) { + // 校验存在 + validateDeliveryExpressExists(updateReqVO.getId()); + //校验编码是否唯一 + validateExpressCodeUnique(updateReqVO.getCode(), updateReqVO.getId()); + // 更新 + DeliveryExpressDO updateObj = DeliveryExpressConvert.INSTANCE.convert(updateReqVO); + deliveryExpressMapper.updateById(updateObj); + } + + @Override + public void deleteDeliveryExpress(Long id) { + // 校验存在 + validateDeliveryExpressExists(id); + // 删除 + deliveryExpressMapper.deleteById(id); + } + + private void validateExpressCodeUnique(String code, Long id) { + DeliveryExpressDO express = deliveryExpressMapper.selectByCode(code); + if (express == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的快递公司 + if (id == null) { + throw exception(EXPRESS_CODE_DUPLICATE); + } + if (!express.getId().equals(id)) { + throw exception(EXPRESS_CODE_DUPLICATE); + } + } + private void validateDeliveryExpressExists(Long id) { + if (deliveryExpressMapper.selectById(id) == null) { + throw exception(EXPRESS_NOT_EXISTS); + } + } + + @Override + public DeliveryExpressDO getDeliveryExpress(Long id) { + return deliveryExpressMapper.selectById(id); + } + + @Override + public DeliveryExpressDO validateDeliveryExpress(Long id) { + DeliveryExpressDO deliveryExpress = deliveryExpressMapper.selectById(id); + if (deliveryExpress == null) { + throw exception(EXPRESS_NOT_EXISTS); + } + if (deliveryExpress.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(EXPRESS_STATUS_NOT_ENABLE); + } + return deliveryExpress; + } + + @Override + public PageResult getDeliveryExpressPage(DeliveryExpressPageReqVO pageReqVO) { + return deliveryExpressMapper.selectPage(pageReqVO); + } + + @Override + public List getDeliveryExpressList(DeliveryExpressExportReqVO exportReqVO) { + return deliveryExpressMapper.selectList(exportReqVO); + } + + @Override + public List getDeliveryExpressListByStatus(Integer status) { + return deliveryExpressMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java new file mode 100644 index 0000000..c455701 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 快递运费模板 Service 接口 + * + * @author jason + */ +public interface DeliveryExpressTemplateService { + + /** + * 创建快递运费模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDeliveryExpressTemplate(@Valid DeliveryExpressTemplateCreateReqVO createReqVO); + + /** + * 更新快递运费模板 + * + * @param updateReqVO 更新信息 + */ + void updateDeliveryExpressTemplate(@Valid DeliveryExpressTemplateUpdateReqVO updateReqVO); + + /** + * 删除快递运费模板 + * + * @param id 编号 + */ + void deleteDeliveryExpressTemplate(Long id); + + /** + * 获得快递运费模板 + * + * @param id 编号 + * @return 快递运费模板详情 + */ + DeliveryExpressTemplateDetailRespVO getDeliveryExpressTemplate(Long id); + + /** + * 获得快递运费模板列表 + * + * @param ids 编号 + * @return 快递运费模板列表 + */ + List getDeliveryExpressTemplateList(Collection ids); + + /** + * 获得快递运费模板列表 + * + * @return 快递运费模板列表 + */ + List getDeliveryExpressTemplateList(); + + /** + * 获得快递运费模板分页 + * + * @param pageReqVO 分页查询 + * @return 快递运费模板分页 + */ + PageResult getDeliveryExpressTemplatePage(DeliveryExpressTemplatePageReqVO pageReqVO); + + /** + * 校验快递运费模板 + * + * 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常 + * + * @param templateId 模板编号 + * @return 快递运费模板 + */ + DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); + + /** + * 基于运费模板编号数组和收件人地址区域编号,获取匹配运费模板 + * + * @param ids 编号列表 + * @param areaId 区域编号 + * @return Map (templateId -> 运费模板设置) + */ + Map getExpressTemplateMapByIdsAndArea(Collection ids, Integer areaId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java new file mode 100644 index 0000000..92e6d91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java @@ -0,0 +1,218 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper; +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; + +/** + * 快递运费模板 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTemplateService { + + @Resource + private DeliveryExpressTemplateMapper expressTemplateMapper; + @Resource + private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper; + @Resource + private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createDeliveryExpressTemplate(DeliveryExpressTemplateCreateReqVO createReqVO) { + // 校验模板名是否唯一 + validateTemplateNameUnique(createReqVO.getName(), null); + + // 插入 + DeliveryExpressTemplateDO template = INSTANCE.convert(createReqVO); + expressTemplateMapper.insert(template); + // 插入运费模板计费表 + if (CollUtil.isNotEmpty(createReqVO.getCharges())) { + expressTemplateChargeMapper.insertBatch( + INSTANCE.convertTemplateChargeList(template.getId(), createReqVO.getChargeMode(), createReqVO.getCharges()) + ); + } + // 插入运费模板包邮表 + if (CollUtil.isNotEmpty(createReqVO.getFrees())) { + expressTemplateFreeMapper.insertBatch( + INSTANCE.convertTemplateFreeList(template.getId(), createReqVO.getFrees()) + ); + } + return template.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDeliveryExpressTemplate(DeliveryExpressTemplateUpdateReqVO updateReqVO) { + // 校验存在 + validateDeliveryExpressTemplateExists(updateReqVO.getId()); + // 校验模板名是否唯一 + validateTemplateNameUnique(updateReqVO.getName(), updateReqVO.getId()); + + // 更新运费从表 + updateExpressTemplateCharge(updateReqVO.getId(), updateReqVO.getChargeMode(), updateReqVO.getCharges()); + // 更新包邮从表 + updateExpressTemplateFree(updateReqVO.getId(), updateReqVO.getFrees()); + // 更新模板主表 + DeliveryExpressTemplateDO updateObj = INSTANCE.convert(updateReqVO); + expressTemplateMapper.updateById(updateObj); + } + + private void updateExpressTemplateFree(Long templateId, List frees) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = expressTemplateFreeMapper.selectListByTemplateId(templateId); + List newList = INSTANCE.convertTemplateFreeList(templateId, frees); + List> diffList = CollectionUtils.diffList(oldList, newList, + (oldVal, newVal) -> ObjectUtil.equal(oldVal.getId(), newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + expressTemplateFreeMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + expressTemplateFreeMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + expressTemplateFreeMapper.deleteBatchIds(convertList(diffList.get(2), DeliveryExpressTemplateFreeDO::getId)); + } + } + + private void updateExpressTemplateCharge(Long templateId, Integer chargeMode, List charges) { + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = expressTemplateChargeMapper.selectListByTemplateId(templateId); + List newList = INSTANCE.convertTemplateChargeList(templateId, chargeMode, charges); + List> diffList = diffList(oldList, newList, (oldVal, newVal) -> { + boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId()); + if (same) { + newVal.setChargeMode(chargeMode); // 更新下收费模式 + } + return same; + }); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(0))) { + expressTemplateChargeMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + expressTemplateChargeMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + expressTemplateChargeMapper.deleteBatchIds(convertList(diffList.get(2), DeliveryExpressTemplateChargeDO::getId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDeliveryExpressTemplate(Long id) { + // 校验存在 + validateDeliveryExpressTemplateExists(id); + + // 删除主表 + expressTemplateMapper.deleteById(id); + // 删除运费从表 + expressTemplateChargeMapper.deleteByTemplateId(id); + // 删除包邮从表 + expressTemplateFreeMapper.deleteByTemplateId(id); + } + + /** + * 校验运费模板名是否唯一 + * + * @param name 模板名称 + * @param id 运费模板编号,可以为 null + */ + private void validateTemplateNameUnique(String name, Long id) { + DeliveryExpressTemplateDO template = expressTemplateMapper.selectByName(name); + if (template == null) { + return; + } + // 如果 id 为空 + if (id == null) { + throw exception(EXPRESS_TEMPLATE_NAME_DUPLICATE); + } + if (!template.getId().equals(id)) { + throw exception(EXPRESS_TEMPLATE_NAME_DUPLICATE); + } + } + + private void validateDeliveryExpressTemplateExists(Long id) { + if (expressTemplateMapper.selectById(id) == null) { + throw exception(EXPRESS_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public DeliveryExpressTemplateDetailRespVO getDeliveryExpressTemplate(Long id) { + List chargeList = expressTemplateChargeMapper.selectListByTemplateId(id); + List freeList = expressTemplateFreeMapper.selectListByTemplateId(id); + DeliveryExpressTemplateDO template = expressTemplateMapper.selectById(id); + return INSTANCE.convert(template, chargeList, freeList); + } + + @Override + public List getDeliveryExpressTemplateList(Collection ids) { + return expressTemplateMapper.selectBatchIds(ids); + } + + @Override + public List getDeliveryExpressTemplateList() { + return expressTemplateMapper.selectList(); + } + + @Override + public PageResult getDeliveryExpressTemplatePage(DeliveryExpressTemplatePageReqVO pageReqVO) { + return expressTemplateMapper.selectPage(pageReqVO); + } + + @Override + public DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId) { + DeliveryExpressTemplateDO template = expressTemplateMapper.selectById(templateId); + if (template == null) { + throw exception(EXPRESS_TEMPLATE_NOT_EXISTS); + } + return template; + } + + @Override + public Map getExpressTemplateMapByIdsAndArea(Collection ids, Integer areaId) { + Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); + // 查询 template 数组 + if (CollUtil.isEmpty(ids)) { + return Collections.emptyMap(); + } + List templateList = expressTemplateMapper.selectBatchIds(ids); + // 查询 templateCharge 数组 + List chargeList = expressTemplateChargeMapper.selectByTemplateIds(ids); + // 查询 templateFree 数组 + List freeList = expressTemplateFreeMapper.selectListByTemplateIds(ids); + + // 组合运费模板配置 RespBO + return INSTANCE.convertMap(areaId, templateList, chargeList, freeList); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreService.java new file mode 100644 index 0000000..8cfdb22 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStorePageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreUpdateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 自提门店 Service 接口 + * + * @author jason + */ +public interface DeliveryPickUpStoreService { + + /** + * 创建自提门店 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDeliveryPickUpStore(@Valid DeliveryPickUpStoreCreateReqVO createReqVO); + + /** + * 更新自提门店 + * + * @param updateReqVO 更新信息 + */ + void updateDeliveryPickUpStore(@Valid DeliveryPickUpStoreUpdateReqVO updateReqVO); + + /** + * 删除自提门店 + * + * @param id 编号 + */ + void deleteDeliveryPickUpStore(Long id); + + /** + * 获得自提门店 + * + * @param id 编号 + * @return 自提门店 + */ + DeliveryPickUpStoreDO getDeliveryPickUpStore(Long id); + + /** + * 获得自提门店列表 + * + * @param ids 编号 + * @return 自提门店列表 + */ + List getDeliveryPickUpStoreList(Collection ids); + + /** + * 获得自提门店分页 + * + * @param pageReqVO 分页查询 + * @return 自提门店分页 + */ + PageResult getDeliveryPickUpStorePage(DeliveryPickUpStorePageReqVO pageReqVO); + + /** + * 获得指定状态的自提门店列表 + * + * @param status 状态 + * @return 自提门店列表 + */ + List getDeliveryPickUpStoreListByStatus(Integer status); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreServiceImpl.java new file mode 100644 index 0000000..4e31839 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryPickUpStoreServiceImpl.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.trade.service.delivery; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStorePageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.DeliveryPickUpStoreUpdateReqVO; +import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryPickUpStoreConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryPickUpStoreMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PICK_UP_STORE_NOT_EXISTS; + +/** + * 自提门店 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class DeliveryPickUpStoreServiceImpl implements DeliveryPickUpStoreService { + + @Resource + private DeliveryPickUpStoreMapper deliveryPickUpStoreMapper; + + @Override + public Long createDeliveryPickUpStore(DeliveryPickUpStoreCreateReqVO createReqVO) { + // 插入 + DeliveryPickUpStoreDO deliveryPickUpStore = DeliveryPickUpStoreConvert.INSTANCE.convert(createReqVO); + deliveryPickUpStoreMapper.insert(deliveryPickUpStore); + // 返回 + return deliveryPickUpStore.getId(); + } + + @Override + public void updateDeliveryPickUpStore(DeliveryPickUpStoreUpdateReqVO updateReqVO) { + // 校验存在 + validateDeliveryPickUpStoreExists(updateReqVO.getId()); + // 更新 + DeliveryPickUpStoreDO updateObj = DeliveryPickUpStoreConvert.INSTANCE.convert(updateReqVO); + deliveryPickUpStoreMapper.updateById(updateObj); + } + + @Override + public void deleteDeliveryPickUpStore(Long id) { + // 校验存在 + validateDeliveryPickUpStoreExists(id); + // 删除 + deliveryPickUpStoreMapper.deleteById(id); + } + + private void validateDeliveryPickUpStoreExists(Long id) { + if (deliveryPickUpStoreMapper.selectById(id) == null) { + throw exception(PICK_UP_STORE_NOT_EXISTS); + } + } + + @Override + public DeliveryPickUpStoreDO getDeliveryPickUpStore(Long id) { + return deliveryPickUpStoreMapper.selectById(id); + } + + @Override + public List getDeliveryPickUpStoreList(Collection ids) { + return deliveryPickUpStoreMapper.selectBatchIds(ids); + } + + @Override + public PageResult getDeliveryPickUpStorePage(DeliveryPickUpStorePageReqVO pageReqVO) { + return deliveryPickUpStoreMapper.selectPage(pageReqVO); + } + + @Override + public List getDeliveryPickUpStoreListByStatus(Integer status) { + return deliveryPickUpStoreMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateRespBO.java new file mode 100644 index 0000000..db0af04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateRespBO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.trade.service.delivery.bo; + +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; +import lombok.Data; + +/** + * 运费模板配置 Resp BO + * + * @author jason + */ +@Data +public class DeliveryExpressTemplateRespBO { + + /** + * 配送计费方式 + * + * 枚举 {@link DeliveryExpressChargeModeEnum} + */ + private Integer chargeMode; + + /** + * 运费模板快递运费设置 + */ + private Charge charge; + + /** + * 运费模板包邮设置 + */ + private Free free; + + /** + * 快递运费模板费用配置 BO + * + * @author jason + */ + @Data + public static class Charge { + + /** + * 首件数量(件数,重量,或体积) + */ + private Double startCount; + /** + * 起步价,单位:分 + */ + private Integer startPrice; + /** + * 续件数量(件, 重量,或体积) + */ + private Double extraCount; + /** + * 额外价,单位:分 + */ + private Integer extraPrice; + } + + /** + * 快递运费模板包邮配置 BO + * + * @author jason + */ + @Data + public static class Free { + + /** + * 包邮金额,单位:分 + * + * 订单总金额 > 包邮金额时,才免运费 + */ + private Integer freePrice; + + /** + * 包邮件数 + * + * 订单总件数 > 包邮件数时,才免运费 + */ + private Integer freeCount; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageService.java new file mode 100644 index 0000000..dce5faf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageService.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.trade.service.message; + +import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; + +/** + * Trade 消息 service 接口 + * + * @author HUIHUI + */ +public interface TradeMessageService { + + /** + * 订单发货时发送通知 + * + * @param reqBO 发送消息 + */ + void sendMessageWhenDeliveryOrder(TradeOrderMessageWhenDeliveryOrderReqBO reqBO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java new file mode 100644 index 0000000..b9cdf94 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.trade.service.message; + +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; +import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants; +import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * Trade 消息 service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class TradeMessageServiceImpl implements TradeMessageService { + + @Resource + private NotifyMessageSendApi notifyMessageSendApi; + + @Override + public void sendMessageWhenDeliveryOrder(TradeOrderMessageWhenDeliveryOrderReqBO reqBO) { + if (true) { + return; + } + // 1、构造消息 + Map msgMap = new HashMap<>(2); + msgMap.put("orderId", reqBO.getOrderId()); + msgMap.put("deliveryMessage", reqBO.getMessage()); + // TODO 芋艿:看下模版 + // 2、发送站内信 + notifyMessageSendApi.sendSingleMessageToMember( + new NotifySendSingleToUserReqDTO() + .setUserId(reqBO.getUserId()) + .setTemplateCode(MessageTemplateConstants.ORDER_DELIVERY) + .setTemplateParams(msgMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/bo/TradeOrderMessageWhenDeliveryOrderReqBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/bo/TradeOrderMessageWhenDeliveryOrderReqBO.java new file mode 100644 index 0000000..7fe9873 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/bo/TradeOrderMessageWhenDeliveryOrderReqBO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.trade.service.message.bo; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 订单发货时通知创建 Req BO + * + * @author HUIHUI + */ +@Data +public class TradeOrderMessageWhenDeliveryOrderReqBO { + + /** + * 订单编号 + */ + @NotNull(message = "订单编号不能为空") + private Long orderId; + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 消息 + */ + @NotEmpty(message = "发送消息不能为空") + private String message; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java new file mode 100644 index 0000000..a08f013 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.service.order.bo.TradeOrderLogCreateReqBO; +import org.springframework.scheduling.annotation.Async; + +import java.util.List; + +/** + * 交易下单日志 Service 接口 + * + * @author 陈賝 + * @since 2023/7/6 15:44 + */ +public interface TradeOrderLogService { + + /** + * 创建交易下单日志 + * + * @param logDTO 日志记录 + * @author 陈賝 + * @since 2023/7/6 15:45 + */ + @Async + void createOrderLog(TradeOrderLogCreateReqBO logDTO); + + /** + * 获得交易订单日志列表 + * + * @param orderId 订单编号 + * @return 交易订单日志列表 + */ + List getOrderLogListByOrderId(Long orderId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java new file mode 100644 index 0000000..7c79c9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderLogConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderLogMapper; +import cn.iocoder.yudao.module.trade.service.order.bo.TradeOrderLogCreateReqBO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 交易下单日志 Service 实现类 + * + * @author 陈賝 + * @since 2023/7/6 15:44 + */ +@Service +public class TradeOrderLogServiceImpl implements TradeOrderLogService { + + @Resource + private TradeOrderLogMapper tradeOrderLogMapper; + + @Override + public void createOrderLog(TradeOrderLogCreateReqBO createReqBO) { + tradeOrderLogMapper.insert(TradeOrderLogConvert.INSTANCE.convert(createReqBO)); + } + + @Override + public List getOrderLogListByOrderId(Long orderId) { + return tradeOrderLogMapper.selectListByOrderId(orderId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java new file mode 100644 index 0000000..4457922 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; + +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.singleton; + +/** + * 交易订单【读】 Service 接口 + * + * @author 芋道源码 + */ +public interface TradeOrderQueryService { + + // =================== Order =================== + + /** + * 获得指定编号的交易订单 + * + * @param id 交易订单编号 + * @return 交易订单 + */ + TradeOrderDO getOrder(Long id); + + /** + * 获得指定用户,指定的交易订单 + * + * @param userId 用户编号 + * @param id 交易订单编号 + * @return 交易订单 + */ + TradeOrderDO getOrder(Long userId, Long id); + + /** + * 获得指定用户,指定活动,指定状态的交易订单 + * + * @param userId 用户编号 + * @param combinationActivityId 活动编号 + * @param status 订单状态 + * @return 交易订单 + */ + TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status); + + /** + * 获得订单列表 + * + * @param ids 订单编号数组 + * @return 订单列表 + */ + List getOrderList(Collection ids); + + /** + * 【管理员】获得交易订单分页 + * + * @param reqVO 分页请求 + * @return 交易订单 + */ + PageResult getOrderPage(TradeOrderPageReqVO reqVO); + + /** + * 获得订单统计 + * + * @param reqVO 请求参数 + * @return 订单统计 + */ + TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO); + + /** + * 【会员】获得交易订单分页 + * + * @param userId 用户编号 + * @param reqVO 分页请求 + * @return 交易订单 + */ + PageResult getOrderPage(Long userId, AppTradeOrderPageReqVO reqVO); + + /** + * 【会员】获得交易订单数量 + * + * @param userId 用户编号 + * @param status 订单状态。如果为空,则不进行筛选 + * @param commonStatus 评价状态。如果为空,则不进行筛选 + * @return 订单数量 + */ + Long getOrderCount(Long userId, Integer status, Boolean commonStatus); + + /** + * 【前台】获得订单的物流轨迹 + * + * @param id 订单编号 + * @param userId 用户编号 + * @return 物流轨迹数组 + */ + List getExpressTrackList(Long id, Long userId); + + /** + * 【后台】获得订单的物流轨迹 + * + * @param id 订单编号 + * @return 物流轨迹数组 + */ + List getExpressTrackList(Long id); + + /** + * 【会员】在指定秒杀活动下,用户购买的商品数量 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @return 秒杀商品数量 + */ + int getSeckillProductCount(Long userId, Long activityId); + + // =================== Order Item =================== + + /** + * 获得指定用户,指定的交易订单项 + * + * @param userId 用户编号 + * @param itemId 交易订单项编号 + * @return 交易订单项 + */ + TradeOrderItemDO getOrderItem(Long userId, Long itemId); + + /** + * 获得交易订单项 + * + * @param id 交易订单项编号 itemId + * @return 交易订单项 + */ + TradeOrderItemDO getOrderItem(Long id); + + /** + * 根据交易订单编号,查询交易订单项 + * + * @param orderId 交易订单编号 + * @return 交易订单项数组 + */ + default List getOrderItemListByOrderId(Long orderId) { + return getOrderItemListByOrderId(singleton(orderId)); + } + + /** + * 根据交易订单编号数组,查询交易订单项 + * + * @param orderIds 交易订单编号数组 + * @return 交易订单项数组 + */ + List getOrderItemListByOrderId(Collection orderIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java new file mode 100644 index 0000000..0c1f696 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -0,0 +1,260 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderSummaryRespVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; +import cn.iocoder.yudao.module.trade.dal.redis.RedisKeyConstants; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_NOT_EXISTS; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND; + +/** + * 交易订单【读】 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { + + @Resource + private ExpressClientFactory expressClientFactory; + + @Resource + private TradeOrderMapper tradeOrderMapper; + @Resource + private TradeOrderItemMapper tradeOrderItemMapper; + + @Resource + private DeliveryExpressService deliveryExpressService; + + @Resource + private MemberUserApi memberUserApi; + + // =================== Order =================== + + @Override + public TradeOrderDO getOrder(Long id) { + return tradeOrderMapper.selectById(id); + } + + @Override + public TradeOrderDO getOrder(Long userId, Long id) { + TradeOrderDO order = tradeOrderMapper.selectById(id); + if (order != null + && ObjectUtil.notEqual(order.getUserId(), userId)) { + return null; + } + return order; + } + + @Override + public TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status) { + return tradeOrderMapper.selectByUserIdAndCombinationActivityIdAndStatus(userId, combinationActivityId, status); + } + + @Override + public List getOrderList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return tradeOrderMapper.selectBatchIds(ids); + } + + @Override + public PageResult getOrderPage(TradeOrderPageReqVO reqVO) { + // 根据用户查询条件构建用户编号列表 + Set userIds = buildQueryConditionUserIds(reqVO); + if (userIds == null) { // 没查询到用户,说明肯定也没他的订单 + return PageResult.empty(); + } + // 分页查询 + return tradeOrderMapper.selectPage(reqVO, userIds); + } + + private Set buildQueryConditionUserIds(TradeOrderPageReqVO reqVO) { + // 获得 userId 相关的查询 + Set userIds = new HashSet<>(); + if (StrUtil.isNotEmpty(reqVO.getUserMobile())) { + MemberUserRespDTO user = memberUserApi.getUserByMobile(reqVO.getUserMobile()); + if (user == null) { // 没查询到用户,说明肯定也没他的订单 + return null; + } + userIds.add(user.getId()); + } + if (StrUtil.isNotEmpty(reqVO.getUserNickname())) { + List users = memberUserApi.getUserListByNickname(reqVO.getUserNickname()); + if (CollUtil.isEmpty(users)) { // 没查询到用户,说明肯定也没他的订单 + return null; + } + userIds.addAll(convertSet(users, MemberUserRespDTO::getId)); + } + return userIds; + } + + @Override + public TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO) { + // 根据用户查询条件构建用户编号列表 + Set userIds = buildQueryConditionUserIds(reqVO); + if (userIds == null) { // 没查询到用户,说明肯定也没他的订单 + return new TradeOrderSummaryRespVO(); + } + // 查询每个售后状态对应的数量、金额 + List> list = tradeOrderMapper.selectOrderSummaryGroupByRefundStatus(reqVO, null); + + TradeOrderSummaryRespVO vo = new TradeOrderSummaryRespVO().setAfterSaleCount(0L).setAfterSalePrice(0L); + for (Map map : list) { + Long count = MapUtil.getLong(map, "count", 0L); + Long price = MapUtil.getLong(map, "price", 0L); + // 未退款的计入订单,部分退款、全部退款计入售后 + if (TradeOrderRefundStatusEnum.NONE.getStatus().equals(MapUtil.getInt(map, "refundStatus"))) { + vo.setOrderCount(count).setOrderPayPrice(price); + } else { + vo.setAfterSaleCount(vo.getAfterSaleCount() + count).setAfterSalePrice(vo.getAfterSalePrice() + price); + } + } + return vo; + } + + @Override + public PageResult getOrderPage(Long userId, AppTradeOrderPageReqVO reqVO) { + return tradeOrderMapper.selectPage(reqVO, userId); + } + + @Override + public Long getOrderCount(Long userId, Integer status, Boolean commentStatus) { + return tradeOrderMapper.selectCountByUserIdAndStatus(userId, status, commentStatus); + } + + @Override + public List getExpressTrackList(Long id, Long userId) { + // 查询订单 + TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 查询物流 + return getExpressTrackList(order); + } + + @Override + public List getExpressTrackList(Long id) { + // 查询订单 + TradeOrderDO order = tradeOrderMapper.selectById(id); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 查询物流 + return getExpressTrackList(order); + } + + @Override + public int getSeckillProductCount(Long userId, Long activityId) { + // 获得订单列表 + List orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId); + orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单 + if (CollUtil.isEmpty(orders)) { + return 0; + } + // 获得订单项列表 + return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId)); + } + + /** + * 获得订单的物流轨迹 + * + * @param order 订单 + * @return 物流轨迹 + */ + private List getExpressTrackList(TradeOrderDO order) { + if (order.getLogisticsId() == null) { + return Collections.emptyList(); + } + // 查询物流公司 + DeliveryExpressDO express = deliveryExpressService.getDeliveryExpress(order.getLogisticsId()); + if (express == null) { + throw exception(EXPRESS_NOT_EXISTS); + } + // 查询物流轨迹 + return getSelf().getExpressTrackList(express.getCode(), order.getLogisticsNo(), order.getReceiverMobile()); + } + + /** + * 查询物流轨迹 + * + * 缓存的目的:考虑及时性要求不高,但是每次调用需要钱 + * + * @param code 快递公司编码 + * @param logisticsNo 发货快递单号 + * @param receiverMobile 收、寄件人的电话号码 + * @return 物流轨迹 + */ + @Cacheable(cacheNames = RedisKeyConstants.EXPRESS_TRACK, key = "#code + '-' + #logisticsNo + '-' + #receiverMobile", + condition = "#result != null") + public List getExpressTrackList(String code, String logisticsNo, String receiverMobile) { + return expressClientFactory.getDefaultExpressClient().getExpressTrackList( + new ExpressTrackQueryReqDTO().setExpressCode(code).setLogisticsNo(logisticsNo) + .setPhone(receiverMobile)); + } + + + // =================== Order Item =================== + + @Override + public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); + if (orderItem != null + && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { + return null; + } + return orderItem; + } + + @Override + public TradeOrderItemDO getOrderItem(Long id) { + return tradeOrderItemMapper.selectById(id); + } + + @Override + public List getOrderItemListByOrderId(Collection orderIds) { + if (CollUtil.isEmpty(orderIds)) { + return Collections.emptyList(); + } + return tradeOrderItemMapper.selectListByOrderId(orderIds); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private TradeOrderQueryServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java new file mode 100644 index 0000000..9f3c6cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java @@ -0,0 +1,199 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; + +import javax.validation.constraints.NotNull; + +/** + * 交易订单【写】Service 接口 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +public interface TradeOrderUpdateService { + + // =================== Order =================== + + /** + * 获得订单结算信息 + * + * @param userId 登录用户 + * @param settlementReqVO 订单结算请求 + * @return 订单结算结果 + */ + AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO); + + /** + * 【会员】创建交易订单 + * + * @param userId 登录用户 + * @param createReqVO 创建交易订单请求模型 + * @return 交易订单的 + */ + TradeOrderDO createOrder(Long userId, AppTradeOrderCreateReqVO createReqVO); + + /** + * 更新交易订单已支付 + * + * @param id 交易订单编号 + * @param payOrderId 支付订单编号 + */ + void updateOrderPaid(Long id, Long payOrderId); + + /** + * 【管理员】发货交易订单 + * + * @param deliveryReqVO 发货请求 + */ + void deliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO); + + /** + * 【会员】收货交易订单 + * + * @param userId 用户编号 + * @param id 订单编号 + */ + void receiveOrderByMember(Long userId, Long id); + + /** + * 【系统】自动收货交易订单 + * + * @return 收货数量 + */ + int receiveOrderBySystem(); + + /** + * 【会员】取消交易订单 + * + * @param userId 用户编号 + * @param id 订单编号 + */ + void cancelOrderByMember(Long userId, Long id); + + /** + * 【系统】自动取消订单 + * + * @return 取消数量 + */ + int cancelOrderBySystem(); + + /** + * 【会员】删除订单 + * + * @param userId 用户编号 + * @param id 订单编号 + */ + void deleteOrder(Long userId, Long id); + + /** + * 【管理员】交易订单备注 + * + * @param reqVO 请求 + */ + void updateOrderRemark(TradeOrderRemarkReqVO reqVO); + + /** + * 【管理员】调整价格 + * + * @param reqVO 请求 + */ + void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO); + + /** + * 【管理员】调整地址 + * + * @param reqVO 请求 + */ + void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO); + + /** + * 【管理员】核销订单 + * + * @param id 订单编号 + */ + void pickUpOrderByAdmin(Long id); + + /** + * 【管理员】核销订单 + * + * @param pickUpVerifyCode 自提核销码 + */ + void pickUpOrderByAdmin(String pickUpVerifyCode); + + /** + * 【管理员】根据自提核销码,查询订单 + * + * @param pickUpVerifyCode 自提核销码 + */ + TradeOrderDO getByPickUpVerifyCode(String pickUpVerifyCode); + + // =================== Order Item =================== + + /** + * 当售后申请后,更新交易订单项的售后状态 + * + * @param id 交易订单项编号 + * @param afterSaleId 售后单编号 + */ + void updateOrderItemWhenAfterSaleCreate(@NotNull Long id, @NotNull Long afterSaleId); + + /** + * 当售后完成后,更新交易订单项的售后状态 + * + * @param id 交易订单项编号 + * @param refundPrice 退款金额 + */ + void updateOrderItemWhenAfterSaleSuccess(@NotNull Long id, @NotNull Integer refundPrice); + + /** + * 当售后取消(用户取消、管理员驳回、管理员拒绝收货)后,更新交易订单项的售后状态 + * + * @param id 交易订单项编号 + */ + void updateOrderItemWhenAfterSaleCancel(@NotNull Long id); + + /** + * 【会员】创建订单项的评论 + * + * @param userId 用户编号 + * @param createReqVO 创建请求 + * @return 得到评价 id + */ + Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO); + + /** + * 【系统】创建订单项的评论 + * + * @return 被评论的订单数 + */ + int createOrderItemCommentBySystem(); + + /** + * 更新拼团相关信息到订单 + * + * @param orderId 订单编号 + * @param activityId 拼团活动编号 + * @param combinationRecordId 拼团记录编号 + * @param headId 团长编号 + */ + void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId); + + // TODO 芋艿:拼团取消,不调这个接口哈; + /** + * 取消支付订单 + * + * @param userId 用户编号 + * @param orderId 订单编号 + */ + void cancelPaidOrder(Long userId, Long orderId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java new file mode 100644 index 0000000..75323a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -0,0 +1,903 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdatePriceReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.*; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; +import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils; +import cn.iocoder.yudao.module.trade.service.cart.CartService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; +import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; +import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler; +import cn.iocoder.yudao.module.trade.service.price.TradePriceService; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.minusTime; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 交易订单【写】Service 实现类 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +@Service +@Slf4j +public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { + + @Resource + private TradeOrderMapper tradeOrderMapper; + @Resource + private TradeOrderItemMapper tradeOrderItemMapper; + @Resource + private TradeNoRedisDAO tradeNoRedisDAO; + + @Resource + private List tradeOrderHandlers; + + @Resource + private CartService cartService; + @Resource + private TradePriceService tradePriceService; + @Resource + private DeliveryExpressService deliveryExpressService; + @Resource + private TradeMessageService tradeMessageService; + + @Resource + private PayOrderApi payOrderApi; + @Resource + private MemberAddressApi addressApi; + @Resource + private ProductCommentApi productCommentApi; + + @Resource + private TradeOrderProperties tradeOrderProperties; + + // =================== Order =================== + + @Override + public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { + // 1. 获得收货地址 + MemberAddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId()); + if (address != null) { + settlementReqVO.setAddressId(address.getId()); + } + + // 2. 计算价格 + TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, settlementReqVO); + + // 3. 拼接返回 + return TradeOrderConvert.INSTANCE.convert(calculateRespBO, address); + } + + /** + * 获得用户地址 + * + * @param userId 用户编号 + * @param addressId 地址编号 + * @return 地址 + */ + private MemberAddressRespDTO getAddress(Long userId, Long addressId) { + if (addressId != null) { + return addressApi.getAddress(addressId, userId); + } + return addressApi.getDefaultAddress(userId); + } + + /** + * 计算订单价格 + * + * @param userId 用户编号 + * @param settlementReqVO 结算信息 + * @return 订单价格 + */ + private TradePriceCalculateRespBO calculatePrice(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { + // 1. 如果来自购物车,则获得购物车的商品 + List cartList = cartService.getCartList(userId, + convertSet(settlementReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId)); + + // 2. 计算价格 + TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList); + calculateReqBO.getItems().forEach(item -> Assert.isTrue(item.getSelected(), // 防御性编程,保证都是选中的 + "商品({}) 未设置为选中", item.getSkuId())); + return tradePriceService.calculatePrice(calculateReqBO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE) + public TradeOrderDO createOrder(Long userId, AppTradeOrderCreateReqVO createReqVO) { + // 1.1 价格计算 + TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); + // 1.2 构建订单 + TradeOrderDO order = buildTradeOrder(userId, createReqVO, calculateRespBO); + List orderItems = buildTradeOrderItems(order, calculateRespBO); + + // 2. 订单创建前的逻辑 + tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(order, orderItems)); + + // 3. 保存订单 + tradeOrderMapper.insert(order); + orderItems.forEach(orderItem -> orderItem.setOrderId(order.getId())); + tradeOrderItemMapper.insertBatch(orderItems); + + // 4. 订单创建后的逻辑 + afterCreateTradeOrder(order, orderItems, createReqVO); + return order; + } + + private TradeOrderDO buildTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, + TradePriceCalculateRespBO calculateRespBO) { + TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO); + order.setType(calculateRespBO.getType()); + order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX)); + order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); + order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); + order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); + order.setUserIp(getClientIP()).setTerminal(getTerminal()); + // 支付 + 退款信息 + order.setAdjustPrice(0).setPayStatus(false); + order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); + // 物流信息 + order.setDeliveryType(createReqVO.getDeliveryType()); + if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) { + MemberAddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId); + Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时,已经计算 + order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile()) + .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress()); + } else if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.PICK_UP.getType())) { + order.setReceiverName(createReqVO.getReceiverName()).setReceiverMobile(createReqVO.getReceiverMobile()); + order.setPickUpVerifyCode(RandomUtil.randomNumbers(8)); // 随机一个核销码,长度为 8 位 + } + return order; + } + + private List buildTradeOrderItems(TradeOrderDO tradeOrderDO, + TradePriceCalculateRespBO calculateRespBO) { + return TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO); + } + + /** + * 订单创建后,执行后置逻辑 + *

+ * 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等 + * + * @param order 订单 + * @param orderItems 订单项 + * @param createReqVO 创建订单请求 + */ + private void afterCreateTradeOrder(TradeOrderDO order, List orderItems, + AppTradeOrderCreateReqVO createReqVO) { + // 1. 执行订单创建后置处理器 + tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(order, orderItems)); + + // 2. 删除购物车商品 + Set cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); + if (CollUtil.isNotEmpty(cartIds)) { + cartService.deleteCart(order.getUserId(), cartIds); + } + + // 3. 生成预支付 + createPayOrder(order, orderItems); + + // 4. 插入订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus()); + + // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! + } + + private void createPayOrder(TradeOrderDO order, List orderItems) { + // 创建支付单,用于后续的支付 + PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( + order, orderItems, tradeOrderProperties); + Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO); + + // 更新到交易单上 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setPayOrderId(payOrderId)); + order.setPayOrderId(payOrderId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY) + public void updateOrderPaid(Long id, Long payOrderId) { + // 1. 校验并获得交易订单(可支付) + KeyValue orderResult = validateOrderPayable(id, payOrderId); + TradeOrderDO order = orderResult.getKey(); + PayOrderRespDTO payOrder = orderResult.getValue(); + + // 2. 更新 TradeOrderDO 状态为已支付,等待发货 + int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayStatus(true) + .setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode())); + if (updateCount == 0) { + throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + + // 3. 执行 TradeOrderHandler 的后置处理 + List orderItems = tradeOrderItemMapper.selectListByOrderId(id); + tradeOrderHandlers.forEach(handler -> handler.afterPayOrder(order, orderItems)); + + // 4. 记录订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus()); + TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue()); + } + + /** + * 校验交易订单满足被支付的条件 + *

+ * 1. 交易订单未支付 + * 2. 支付单已支付 + * + * @param id 交易订单编号 + * @param payOrderId 支付订单编号 + * @return 交易订单 + */ + private KeyValue validateOrderPayable(Long id, Long payOrderId) { + // 校验订单是否存在 + TradeOrderDO order = validateOrderExists(id); + // 校验订单未支付 + if (!TradeOrderStatusEnum.isUnpaid(order.getStatus()) || order.getPayStatus()) { + log.error("[validateOrderPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]", + id, JsonUtils.toJsonString(order)); + throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + // 校验支付订单匹配 + if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 + log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(order)); + throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); + } + + // 校验支付单是否存在 + PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); + if (payOrder == null) { + log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); + throw exception(ORDER_NOT_FOUND); + } + // 校验支付单已支付 + if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { + log.error("[validateOrderPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS); + } + // 校验支付金额一致 + if (ObjectUtil.notEqual(payOrder.getPrice(), order.getPayPrice())) { + log.error("[validateOrderPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH); + } + // 校验支付订单匹配(二次) + if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) { + log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); + } + return new KeyValue<>(order, payOrder); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_DELIVERY) + public void deliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO) { + // 1.1 校验并获得交易订单(可发货) + TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId()); + // 1.2 校验 deliveryType 是否为快递,是快递才可以发货 + if (ObjectUtil.notEqual(order.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) { + throw exception(ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS); + } + + // 2. 更新订单为已发货 + TradeOrderDO updateOrderObj = new TradeOrderDO(); + // 2.1 快递发货 + DeliveryExpressDO express = null; + if (ObjectUtil.notEqual(deliveryReqVO.getLogisticsId(), TradeOrderDO.LOGISTICS_ID_NULL)) { + express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId()); + updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()); + } else { + // 2.2 无需发货 + updateOrderObj.setLogisticsId(0L).setLogisticsNo(""); + } + // 执行更新 + updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now()); + int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj); + if (updateCount == 0) { + throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED); + } + + // 3. 记录订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(), + MapUtil.builder().put("expressName", express != null ? express.getName() : "无") + .put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "无").build()); + + // 4. 发送站内信 + tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO() + .setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null)); + } + + /** + * 校验交易订单满足被发货的条件 + *

+ * 1. 交易订单未发货 + * + * @param id 交易订单编号 + * @return 交易订单 + */ + private TradeOrderDO validateOrderDeliverable(Long id) { + TradeOrderDO order = validateOrderExists(id); + // 1. 校验订单是否未发货 + if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { + throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE); + } + + // 2. 执行 TradeOrderHandler 前置处理 + tradeOrderHandlers.forEach(handler -> handler.beforeDeliveryOrder(order)); + return order; + } + + @NotNull + private TradeOrderDO validateOrderExists(Long id) { + // 校验订单是否存在 + TradeOrderDO order = tradeOrderMapper.selectById(id); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + return order; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE) + public void receiveOrderByMember(Long userId, Long id) { + // 校验并获得交易订单(可收货) + TradeOrderDO order = validateOrderReceivable(userId, id); + + // 收货订单 + receiveOrder0(order); + } + + @Override + public int receiveOrderBySystem() { + // 1. 查询过期的待支付订单 + LocalDateTime expireTime = minusTime(tradeOrderProperties.getReceiveExpireTime()); + List orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt( + TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行,逐个取消 + int count = 0; + for (TradeOrderDO order : orders) { + try { + getSelf().receiveOrderBySystem(order); + count++; + } catch (Throwable e) { + log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e); + } + } + return count; + } + + /** + * 自动收货单个订单 + * + * @param order 订单 + */ + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE) + public void receiveOrderBySystem(TradeOrderDO order) { + receiveOrder0(order); + } + + /** + * 收货订单的核心实现 + * + * @param order 订单 + */ + private void receiveOrder0(TradeOrderDO order) { + // 更新 TradeOrderDO 状态为已完成 + int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now())); + if (updateCount == 0) { + throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED); + } + + // 插入订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus()); + } + + /** + * 校验交易订单满足可售货的条件 + *

+ * 1. 交易订单待收货 + * + * @param userId 用户编号 + * @param id 交易订单编号 + * @return 交易订单 + */ + private TradeOrderDO validateOrderReceivable(Long userId, Long id) { + // 校验订单是否存在 + TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 校验订单是否是待收货状态 + if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) { + throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED); + } + return order; + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL) + public void cancelOrderByMember(Long userId, Long id) { + // 1.1 校验存在 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 1.2 校验状态 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 2. 取消订单 + cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL); + } + + @Override + public int cancelOrderBySystem() { + // 1. 查询过期的待支付订单 + LocalDateTime expireTime = minusTime(tradeOrderProperties.getPayExpireTime()); + List orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt( + TradeOrderStatusEnum.UNPAID.getStatus(), expireTime); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行,逐个取消 + int count = 0; + for (TradeOrderDO order : orders) { + try { + getSelf().cancelOrderBySystem(order); + count++; + } catch (Throwable e) { + log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getId(), e); + } + } + return count; + } + + /** + * 自动取消单个订单 + * + * @param order 订单 + */ + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL) + public void cancelOrderBySystem(TradeOrderDO order) { + cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT); + } + + /** + * 取消订单的核心实现 + * + * @param order 订单 + * @param cancelType 取消类型 + */ + private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) { + // 1. 更新 TradeOrderDO 状态为已取消 + int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) + .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now())); + if (updateCount == 0) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 2. 执行 TradeOrderHandler 的后置处理 + List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); + tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems)); + + // 3. 增加订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus()); + } + + /** + * 如果金额全部被退款,则取消订单 + * 如果还有未被退款的金额,则无需取消订单 + * + * @param order 订单 + * @param refundPrice 退款金额 + */ + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_CANCEL_AFTER_SALE) + public void cancelOrderByAfterSale(TradeOrderDO order, Integer refundPrice) { + // 1. 更新订单 + if (refundPrice < order.getPayPrice()) { + return; + } + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) + .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); + + // 2. 执行 TradeOrderHandler 的后置处理 + List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); + tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE) + public void deleteOrder(Long userId, Long id) { + // 1.1 校验存在 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 1.2 校验状态 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) { + throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL); + } + // 2. 删除订单 + tradeOrderMapper.deleteById(id); + + // 3. 记录日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + + @Override + public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) { + // 校验并获得交易订单 + validateOrderExists(reqVO.getId()); + + // 更新 + TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(reqVO); + tradeOrderMapper.updateById(order); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_PRICE) + public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) { + // 1.1 校验交易订单 + TradeOrderDO order = validateOrderExists(reqVO.getId()); + if (order.getPayStatus()) { + throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); + } + // 1.2 校验调价金额是否变化 + if (order.getAdjustPrice() > 0) { + throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY); + } + // 1.3 支付价格不能为 0 + int newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice(); + if (newPayPrice <= 0) { + throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR); + } + + // 2. 更新订单 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setAdjustPrice(reqVO.getAdjustPrice() + order.getAdjustPrice()).setPayPrice(newPayPrice)); + + // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊 + List orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); + List dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice()); + List updateItems = new ArrayList<>(); + for (int i = 0; i < orderOrderItems.size(); i++) { + TradeOrderItemDO item = orderOrderItems.get(i); + updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(item.getAdjustPrice() + dividePrices.get(i)) + .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i))); + } + tradeOrderItemMapper.updateBatch(updateItems); + + // 4. 更新支付订单 + payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice); + + // 5. 记录订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(), + MapUtil.builder().put("oldPayPrice", MoneyUtils.fenToYuanStr(order.getPayPrice())) + .put("adjustPrice", MoneyUtils.fenToYuanStr(reqVO.getAdjustPrice())) + .put("newPayPrice", MoneyUtils.fenToYuanStr(newPayPrice)).build()); + } + + @Override + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_ADDRESS) + public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) { + // 校验交易订单 + TradeOrderDO order = validateOrderExists(reqVO.getId()); + // 只有待发货状态,才可以修改订单收货地址; + if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) { + throw exception(ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED); + } + + // 更新 + tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO)); + + // 记录订单日志 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + + @Override + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE) + public void pickUpOrderByAdmin(Long id) { + getSelf().pickUpOrder(tradeOrderMapper.selectById(id)); + } + + @Override + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE) + public void pickUpOrderByAdmin(String pickUpVerifyCode) { + getSelf().pickUpOrder(tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode)); + } + + @Override + public TradeOrderDO getByPickUpVerifyCode(String pickUpVerifyCode) { + return tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode); + } + + @Transactional(rollbackFor = Exception.class) + public void pickUpOrder(TradeOrderDO order) { + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + if (ObjUtil.notEqual(DeliveryTypeEnum.PICK_UP.getType(), order.getDeliveryType())) { + throw exception(ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP); + } + receiveOrder0(order); + } + + // =================== Order Item =================== + + @Override + public void updateOrderItemWhenAfterSaleCreate(Long id, Long afterSaleId) { + // 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), afterSaleId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateOrderItemWhenAfterSaleSuccess(Long id, Integer refundPrice) { + // 1.1 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), null); + // 1.2 执行 TradeOrderHandler 的后置处理 + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id); + TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId()); + tradeOrderHandlers.forEach(handler -> handler.afterCancelOrderItem(order, orderItem)); + + // 2.1 更新订单的退款金额、积分 + Integer orderRefundPrice = order.getRefundPrice() + refundPrice; + Integer orderRefundPoint = order.getRefundPoint() + orderItem.getUsePoint(); + Integer refundStatus = isAllOrderItemAfterSaleSuccess(order.getId()) ? + TradeOrderRefundStatusEnum.ALL.getStatus() // 如果都售后成功,则需要取消订单 + : TradeOrderRefundStatusEnum.PART.getStatus(); + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setRefundStatus(refundStatus) + .setRefundPrice(orderRefundPrice).setRefundPoint(orderRefundPoint)); + // 2.2 如果全部退款,则进行取消订单 + getSelf().cancelOrderByAfterSale(order, orderRefundPrice); + } + + @Override + public void updateOrderItemWhenAfterSaleCancel(Long id) { + // 更新订单项 + updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null); + } + + private void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, + Long afterSaleId) { + // 更新订单项 + int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus, afterSaleId); + if (updateCount <= 0) { + throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL); + } + + } + + /** + * 判断指定订单的所有订单项,是不是都售后成功 + * + * @param id 订单编号 + * @return 是否都售后成功 + */ + private boolean isAllOrderItemAfterSaleSuccess(Long id) { + List orderItems = tradeOrderItemMapper.selectListByOrderId(id); + return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_COMMENT) + public Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO) { + // 1.1 先通过订单项 ID,查询订单项是否存在 + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectByIdAndUserId(createReqVO.getOrderItemId(), userId); + if (orderItem == null) { + throw exception(ORDER_ITEM_NOT_FOUND); + } + // 1.2 校验订单相关状态 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderItem.getOrderId(), userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) { + throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED); + } + if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) { + throw exception(ORDER_COMMENT_STATUS_NOT_FALSE); + } + + // 2. 创建评价 + Long commentId = createOrderItemComment0(orderItem, createReqVO); + + // 3. 如果订单项都评论了,则更新订单评价状态 + List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); + if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) { + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE) + .setFinishTime(LocalDateTime.now())); + // 增加订单日志。注意:只有在所有订单项都评价后,才会增加 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + return commentId; + } + + @Override + public int createOrderItemCommentBySystem() { + // 1. 查询过期的待支付订单 + LocalDateTime expireTime = minusTime(tradeOrderProperties.getCommentExpireTime()); + List orders = tradeOrderMapper.selectListByStatusAndReceiveTimeLt( + TradeOrderStatusEnum.COMPLETED.getStatus(), expireTime, false); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行,逐个取消 + int count = 0; + for (TradeOrderDO order : orders) { + try { + getSelf().createOrderItemCommentBySystemBySystem(order); + count++; + } catch (Throwable e) { + log.error("[createOrderItemCommentBySystem][order({}) 过期订单异常]", order.getId(), e); + } + } + return count; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId) { + tradeOrderMapper.updateById( + new TradeOrderDO().setId(orderId).setCombinationActivityId(activityId) + .setCombinationRecordId(combinationRecordId).setCombinationHeadId(headId)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelPaidOrder(Long userId, Long orderId) { + // TODO 芋艿:这里实现要优化下; + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL); + } + + /** + * 创建单个订单的评论 + * + * @param order 订单 + */ + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_COMMENT) + public void createOrderItemCommentBySystemBySystem(TradeOrderDO order) { + // 1. 查询未评论的订单项 + List orderItems = tradeOrderItemMapper.selectListByOrderIdAndCommentStatus( + order.getId(), Boolean.FALSE); + if (CollUtil.isEmpty(orderItems)) { + return; + } + + // 2. 逐个评论 + for (TradeOrderItemDO orderItem : orderItems) { + // 2.1 创建评价 + AppTradeOrderItemCommentCreateReqVO commentCreateReqVO = new AppTradeOrderItemCommentCreateReqVO() + .setOrderItemId(orderItem.getId()).setAnonymous(false).setContent("") + .setBenefitScores(5).setDescriptionScores(5); + createOrderItemComment0(orderItem, commentCreateReqVO); + + // 2.2 更新订单项评价状态 + tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE)); + } + + // 3. 所有订单项都评论了,则更新订单评价状态 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE) + .setFinishTime(LocalDateTime.now())); + // 增加订单日志。注意:只有在所有订单项都评价后,才会增加 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + + /** + * 创建订单项的评论的核心实现 + * + * @param orderItem 订单项 + * @param createReqVO 评论内容 + * @return 评论编号 + */ + private Long createOrderItemComment0(TradeOrderItemDO orderItem, AppTradeOrderItemCommentCreateReqVO createReqVO) { + // 1. 创建评价 + ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem); + Long commentId = productCommentApi.createComment(productCommentCreateReqDTO); + + // 2. 更新订单项评价状态 + tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE)); + return commentId; + } + + // =================== 营销相关的操作 =================== + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private TradeOrderUpdateServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeOrderLogCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeOrderLogCreateReqBO.java new file mode 100644 index 0000000..e0a9e1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeOrderLogCreateReqBO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.trade.service.order.bo; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 订单日志的创建 Request BO + * + * @author 陈賝 + * @since 2023/7/6 15:27 + */ +@Data +public class TradeOrderLogCreateReqBO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @NotNull(message = "用户类型不能为空") + private Integer userType; + + /** + * 订单编号 + */ + @NotNull(message = "订单编号不能为空") + private Long orderId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + @NotNull(message = "操作后的状态不能为空") + private Integer afterStatus; + + /** + * 操作类型 + */ + @NotNull(message = "操作类型不能为空") + private Integer operateType; + /** + * 操作明细 + */ + @NotEmpty(message = "操作明细不能为空") + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainOrderHandler.java new file mode 100644 index 0000000..9af7be6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainOrderHandler.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi; +import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 砍价订单的 {@link TradeOrderHandler} 实现类 + * + * @author HUIHUI + */ +@Component +public class TradeBargainOrderHandler implements TradeOrderHandler { + + @Resource + private BargainActivityApi bargainActivityApi; + @Resource + private BargainRecordApi bargainRecordApi; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isBargain(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "砍价时,只允许选择一个商品"); + + // 扣减砍价活动的库存 + bargainActivityApi.updateBargainActivityStock(order.getBargainActivityId(), + -orderItems.get(0).getCount()); + } + + @Override + public void afterOrderCreate(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isBargain(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "砍价时,只允许选择一个商品"); + + // 记录砍价记录对应的订单编号 + bargainRecordApi.updateBargainRecordOrderId(order.getBargainRecordId(), order.getId()); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isBargain(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "砍价时,只允许选择一个商品"); + + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + afterCancelOrderItem(order, orderItems.get(0)); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + if (!TradeOrderTypeEnum.isBargain(order.getType())) { + return; + } + // 恢复(增加)砍价活动的库存 + bargainActivityApi.updateBargainActivityStock(order.getBargainActivityId(), orderItem.getCount()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java new file mode 100644 index 0000000..526d470 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService; +import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService; +import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 订单分销的 {@link TradeOrderHandler} 实现类 + * + * @author 芋道源码 + */ +@Component +public class TradeBrokerageOrderHandler implements TradeOrderHandler { + + @Resource + private MemberUserApi memberUserApi; + @Resource + private ProductSpuApi productSpuApi; + @Resource + private ProductSkuApi productSkuApi; + + @Resource + private BrokerageRecordService brokerageRecordService; + @Resource + private BrokerageUserService brokerageUserService; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + // 设置订单推广人 + BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(order.getUserId()); + if (brokerageUser != null && brokerageUser.getBindUserId() != null) { + order.setBrokerageUserId(brokerageUser.getBindUserId()); + } + } + + @Override + public void afterPayOrder(TradeOrderDO order, List orderItems) { + if (order.getBrokerageUserId() == null) { + return; + } + addBrokerage(order.getUserId(), orderItems); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + // 如果是未支付的订单,不会产生分销结果,所以直接 return + if (!order.getPayStatus()) { + return; + } + if (order.getBrokerageUserId() == null) { + return; + } + + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + orderItems.forEach(orderItem -> afterCancelOrderItem(order, orderItem)); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + if (order.getBrokerageUserId() == null) { + return; + } + cancelBrokerage(order.getBrokerageUserId(), orderItem.getId()); + } + + /** + * 创建分销记录 + *

+ * 目前是支付成功后,就会创建分销记录。 + *

+ * 业内还有两种做法,可以根据自己的业务调整: + * 1. 确认收货后,才创建分销记录 + * 2. 支付 or 下单成功时,创建分销记录(冻结),确认收货解冻或者 n 天后解冻 + * + * @param userId 用户编号 + * @param orderItems 订单项 + */ + protected void addBrokerage(Long userId, List orderItems) { + MemberUserRespDTO user = memberUserApi.getUser(userId); + Assert.notNull(user); + ProductSpuRespDTO spu = productSpuApi.getSpu(orderItems.get(0).getSpuId()); + Assert.notNull(spu); + ProductSkuRespDTO sku = productSkuApi.getSku(orderItems.get(0).getSkuId()); + + // 每一个订单项,都会去生成分销记录 + List addList = convertList(orderItems, + item -> TradeOrderConvert.INSTANCE.convert(user, item, spu, sku)); + brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, addList); + } + + protected void cancelBrokerage(Long userId, Long orderItemId) { + brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java new file mode 100644 index 0000000..87d0ec4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_FAIL_EXIST_UNPAID; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS; + +/** + * 拼团订单的 {@link TradeOrderHandler} 实现类 + * + * @author HUIHUI + */ +@Component +public class TradeCombinationOrderHandler implements TradeOrderHandler { + + @Resource + private TradeOrderUpdateService orderUpdateService; + @Resource + private TradeOrderQueryService orderQueryService; + + @Resource + private CombinationRecordApi combinationRecordApi; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + // 如果不是拼团订单则结束 + if (!TradeOrderTypeEnum.isCombination(order.getType())) { + return; + } + Assert.isTrue(orderItems.size() == 1, "拼团时,只允许选择一个商品"); + + // 1. 校验是否满足拼团活动相关限制 + TradeOrderItemDO item = orderItems.get(0); + combinationRecordApi.validateCombinationRecord(order.getUserId(), order.getCombinationActivityId(), + order.getCombinationHeadId(), item.getSkuId(), item.getCount()); + + // 2. 校验该用户是否存在未支付的拼团活动订单,避免一个拼团可以下多个单子了 + TradeOrderDO activityOrder = orderQueryService.getOrderByUserIdAndStatusAndCombination( + order.getUserId(), order.getCombinationActivityId(), TradeOrderStatusEnum.UNPAID.getStatus()); + if (activityOrder != null) { + throw exception(ORDER_CREATE_FAIL_EXIST_UNPAID); + } + } + + @Override + public void afterPayOrder(TradeOrderDO order, List orderItems) { + // 1.如果不是拼团订单则结束 + if (!TradeOrderTypeEnum.isCombination(order.getType())) { + return; + } + Assert.isTrue(orderItems.size() == 1, "拼团时,只允许选择一个商品"); + + // 2. 创建拼团记录 + TradeOrderItemDO item = orderItems.get(0); + CombinationRecordCreateRespDTO combinationRecord = combinationRecordApi.createCombinationRecord( + TradeOrderConvert.INSTANCE.convert(order, item)); + + // 3. 更新拼团相关信息到订单。为什么几个字段都要更新? + // 原因是:如果创建订单时自己是团长的情况下 combinationHeadId 是为 null 的,设置团长编号这个操作时在订单是否后创建拼团记录时才设置的。 + orderUpdateService.updateOrderCombinationInfo(order.getId(), order.getCombinationActivityId(), + combinationRecord.getCombinationRecordId(), combinationRecord.getCombinationHeadId()); + } + + @Override + public void beforeDeliveryOrder(TradeOrderDO order) { + if (!TradeOrderTypeEnum.isCombination(order.getType())) { + return; + } + // 校验订单拼团是否成功 + if (!combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId())) { + throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS); + } + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java new file mode 100644 index 0000000..0f953fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCouponOrderHandler.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 优惠劵的 {@link TradeOrderHandler} 实现类 + * + * @author 芋道源码 + */ +@Component +public class TradeCouponOrderHandler implements TradeOrderHandler { + + @Resource + private CouponApi couponApi; + + @Override + public void afterOrderCreate(TradeOrderDO order, List orderItems) { + if (order.getCouponId() == null || order.getCouponId() <= 0) { + return; + } + // 不在前置扣减的原因,是因为优惠劵要记录使用的订单号 + couponApi.useCoupon(new CouponUseReqDTO().setId(order.getCouponId()).setUserId(order.getUserId()) + .setOrderId(order.getId())); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + if (order.getCouponId() == null || order.getCouponId() <= 0) { + return; + } + // 退回优惠劵 + couponApi.returnUsedCoupon(order.getCouponId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeMemberPointOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeMemberPointOrderHandler.java new file mode 100644 index 0000000..0c1f9d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeMemberPointOrderHandler.java @@ -0,0 +1,120 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; +import cn.iocoder.yudao.module.member.api.point.MemberPointApi; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; + +/** + * 会员积分、等级的 {@link TradeOrderHandler} 实现类 + * + * @author owen + */ +@Component +public class TradeMemberPointOrderHandler implements TradeOrderHandler { + + @Resource + private MemberPointApi memberPointApi; + @Resource + private MemberLevelApi memberLevelApi; + + @Resource + private AfterSaleService afterSaleService; + + @Override + public void afterOrderCreate(TradeOrderDO order, List orderItems) { + // 扣减用户积分(订单抵扣)。不在前置扣减的原因,是因为积分扣减时,需要记录关联业务 + reducePoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_USE, order.getId()); + } + + @Override + public void afterPayOrder(TradeOrderDO order, List orderItems) { + // 增加用户积分(订单赠送) + addPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE, + order.getId()); + + // 增加用户经验 + memberLevelApi.addExperience(order.getUserId(), order.getPayPrice(), + MemberExperienceBizTypeEnum.ORDER_GIVE.getType(), String.valueOf(order.getId())); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + + // 增加(回滚)用户积分(订单抵扣) + Integer usePoint = getSumValue(orderItems, TradeOrderItemDO::getUsePoint, Integer::sum); + addPoint(order.getUserId(), usePoint, MemberPointBizTypeEnum.ORDER_USE_CANCEL, + order.getId()); + + // 如下的返还,需要经过支持,也就是经历 afterPayOrder 流程 + if (!order.getPayStatus()) { + return; + } + // 扣减(回滚)积分(订单赠送) + Integer givePoint = getSumValue(orderItems, TradeOrderItemDO::getGivePoint, Integer::sum); + reducePoint(order.getUserId(), givePoint, MemberPointBizTypeEnum.ORDER_GIVE_CANCEL, + order.getId()); + // 扣减(回滚)用户经验 + int payPrice = order.getPayPrice() - order.getRefundPrice(); + memberLevelApi.addExperience(order.getUserId(), payPrice, + MemberExperienceBizTypeEnum.ORDER_GIVE_CANCEL.getType(), String.valueOf(order.getId())); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + // 扣减(回滚)积分(订单赠送) + reducePoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE_CANCEL_ITEM, + orderItem.getId()); + // 增加(回滚)积分(订单抵扣) + addPoint(order.getUserId(), orderItem.getUsePoint(), MemberPointBizTypeEnum.ORDER_USE_CANCEL_ITEM, + orderItem.getId()); + + // 扣减(回滚)用户经验 + AfterSaleDO afterSale = afterSaleService.getAfterSale(orderItem.getAfterSaleId()); + memberLevelApi.reduceExperience(order.getUserId(), afterSale.getRefundPrice(), + MemberExperienceBizTypeEnum.ORDER_GIVE_CANCEL_ITEM.getType(), String.valueOf(orderItem.getId())); + } + + /** + * 添加用户积分 + *

+ * 目前是支付成功后,就会创建积分记录。 + *

+ * 业内还有两种做法,可以根据自己的业务调整: + * 1. 确认收货后,才创建积分记录 + * 2. 支付 or 下单成功时,创建积分记录(冻结),确认收货解冻或者 n 天后解冻 + * + * @param userId 用户编号 + * @param point 增加积分数量 + * @param bizType 业务编号 + * @param bizId 业务编号 + */ + protected void addPoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) { + if (point != null && point > 0) { + memberPointApi.addPoint(userId, point, bizType.getType(), String.valueOf(bizId)); + } + } + + protected void reducePoint(Long userId, Integer point, MemberPointBizTypeEnum bizType, Long bizId) { + if (point != null && point > 0) { + memberPointApi.reducePoint(userId, point, bizType.getType(), String.valueOf(bizId)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java new file mode 100644 index 0000000..4cc5c69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; + +import java.util.List; + +/** + * 订单活动特殊逻辑处理器 handler 接口 + * 提供订单生命周期钩子接口;订单创建前、订单创建后、订单支付后、订单取消 + * + * @author HUIHUI + */ +public interface TradeOrderHandler { + + /** + * 订单创建前 + * + * @param order 订单 + * @param orderItems 订单项 + */ + default void beforeOrderCreate(TradeOrderDO order, List orderItems) {} + + /** + * 订单创建后 + * + * @param order 订单 + * @param orderItems 订单项 + */ + default void afterOrderCreate(TradeOrderDO order, List orderItems) {} + + /** + * 支付订单后 + * + * @param order 订单 + * @param orderItems 订单项 + */ + default void afterPayOrder(TradeOrderDO order, List orderItems) {} + + /** + * 订单取消后 + * + * @param order 订单 + * @param orderItems 订单项 + */ + default void afterCancelOrder(TradeOrderDO order, List orderItems) {} + + /** + * 订单项取消后 + * + * @param order 订单 + * @param orderItem 订单项 + */ + default void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) {} + + /** + * 订单发货前 + * + * @param order 订单 + */ + default void beforeDeliveryOrder(TradeOrderDO order) {} + + // ========== 公用方法 ========== + + /** + * 过滤“未售后”的订单项列表 + * + * @param orderItems 订单项列表 + * @return 过滤后的订单项列表 + */ + default List filterOrderItemListByNoneAfterSale(List orderItems) { + return CollectionUtils.filterList(orderItems, + item -> TradeOrderItemAfterSaleStatusEnum.isNone(item.getAfterSaleStatus())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeProductSkuOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeProductSkuOrderHandler.java new file mode 100644 index 0000000..d28a643 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeProductSkuOrderHandler.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static java.util.Collections.singletonList; + +/** + * 商品 SKU 库存的 {@link TradeOrderHandler} 实现类 + * + * @author 芋道源码 + */ +@Component +public class TradeProductSkuOrderHandler implements TradeOrderHandler { + + @Resource + private ProductSkuApi productSkuApi; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(singletonList(orderItem))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillOrderHandler.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillOrderHandler.java new file mode 100644 index 0000000..68227df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillOrderHandler.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.trade.service.order.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 秒杀订单的 {@link TradeOrderHandler} 实现类 + * + * @author HUIHUI + */ +@Component +public class TradeSeckillOrderHandler implements TradeOrderHandler { + + @Resource + private SeckillActivityApi seckillActivityApi; + + @Override + public void beforeOrderCreate(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isSeckill(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品"); + + // 扣减秒杀活动的库存 + seckillActivityApi.updateSeckillStockDecr(order.getSeckillActivityId(), + orderItems.get(0).getSkuId(), orderItems.get(0).getCount()); + } + + @Override + public void afterCancelOrder(TradeOrderDO order, List orderItems) { + if (!TradeOrderTypeEnum.isSeckill(order.getType())) { + return; + } + // 明确校验一下 + Assert.isTrue(orderItems.size() == 1, "秒杀时,只允许选择一个商品"); + + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚 + orderItems = filterOrderItemListByNoneAfterSale(orderItems); + if (CollUtil.isEmpty(orderItems)) { + return; + } + afterCancelOrderItem(order, orderItems.get(0)); + } + + @Override + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) { + if (!TradeOrderTypeEnum.isSeckill(order.getType())) { + return; + } + // 恢复秒杀活动的库存 + seckillActivityApi.updateSeckillStockIncr(order.getSeckillActivityId(), + orderItem.getSkuId(), orderItem.getCount()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java new file mode 100644 index 0000000..d12451b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.service.price; + +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; + +import javax.validation.Valid; + +/** + * 价格计算 Service 接口 + * + * @author 芋道源码 + */ +public interface TradePriceService { + + /** + * 价格计算 + * + * @param calculateReqDTO 计算信息 + * @return 计算结果 + */ + TradePriceCalculateRespBO calculatePrice(@Valid TradePriceCalculateReqBO calculateReqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java new file mode 100644 index 0000000..c070af1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.trade.service.price; + +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; + +/** + * 价格计算 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class TradePriceServiceImpl implements TradePriceService { + + @Resource + private ProductSkuApi productSkuApi; + @Resource + private ProductSpuApi productSpuApi; + + @Resource + private List priceCalculators; + + @Override + public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { + // 1.1 获得商品 SKU 数组 + List skuList = checkSkuList(calculateReqBO); + // 1.2 获得商品 SPU 数组 + List spuList = checkSpuList(skuList); + + // 2.1 计算价格 + TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper + .buildCalculateResp(calculateReqBO, spuList, skuList); + priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); + // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 + if (calculateRespBO.getPrice().getPayPrice() <= 0) { + log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", + calculateReqBO, calculateRespBO); + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); + } + return calculateRespBO; + } + + private List checkSkuList(TradePriceCalculateReqBO reqBO) { + // 获得商品 SKU 数组 + Map skuIdCountMap = convertMap(reqBO.getItems(), + TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount); + List skus = productSkuApi.getSkuList(skuIdCountMap.keySet()); + + // 校验商品 SKU + skus.forEach(sku -> { + Integer count = skuIdCountMap.get(sku.getId()); + if (count == null) { + throw exception(SKU_NOT_EXISTS); + } + if (count > sku.getStock()) { + throw exception(SKU_STOCK_NOT_ENOUGH); + } + }); + return skus; + } + + private List checkSpuList(List skuList) { + // 获得商品 SPU 数组 + return productSpuApi.validateSpuList(convertSet(skuList, ProductSkuRespDTO::getSpuId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java new file mode 100644 index 0000000..295dcd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.trade.service.price.bo; + +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 价格计算 Request BO + * + * @author yudao源码 + */ +@Data +public class TradePriceCalculateReqBO { + + /** + * 用户编号 + * + * 对应 MemberUserDO 的 id 编号 + */ + private Long userId; + + /** + * 优惠劵编号 + * + * 对应 CouponDO 的 id 编号 + */ + private Long couponId; + + /** + * 是否使用积分 + */ + @NotNull(message = "是否使用积分不能为空") + private Boolean pointStatus; + + /** + * 配送方式 + * + * 枚举 {@link DeliveryTypeEnum} + */ + private Integer deliveryType; + /** + * 收货地址编号 + * + * 对应 MemberAddressDO 的 id 编号 + */ + private Long addressId; + /** + * 自提门店编号 + * + * 对应 PickUpStoreDO 的 id 编号 + */ + private Long pickUpStoreId; + + /** + * 商品 SKU 数组 + */ + @NotNull(message = "商品数组不能为空") + private List items; + + // ========== 秒杀活动相关字段 ========== + /** + * 秒杀活动编号 + */ + private Long seckillActivityId; + + // ========== 拼团活动相关字段 ========== + /** + * 拼团活动编号 + */ + private Long combinationActivityId; + + /** + * 拼团团长编号 + */ + private Long combinationHeadId; + + // ========== 砍价活动相关字段 ========== + /** + * 砍价记录编号 + */ + private Long bargainRecordId; + + /** + * 商品 SKU + */ + @Data + @Valid + public static class Item { + + /** + * SKU 编号 + */ + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + /** + * SKU 数量 + */ + @NotNull(message = "商品 SKU 数量不能为空") + @Min(value = 0L, message = "商品 SKU 数量必须大于等于 0") + private Integer count; + + /** + * 购物车项的编号 + */ + private Long cartId; + + /** + * 是否选中 + */ + @NotNull(message = "是否选中不能为空") + private Boolean selected; + + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java new file mode 100644 index 0000000..93867f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java @@ -0,0 +1,311 @@ +package cn.iocoder.yudao.module.trade.service.price.bo; + +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import lombok.Data; + +import java.util.List; + +/** + * 价格计算 Response BO + * + * 整体设计,参考 taobao 的技术文档: + * 1. 订单管理 + * 2. 常用订单金额说明 + * + * @author 芋道源码 + */ +@Data +public class TradePriceCalculateRespBO { + + /** + * 订单类型 + * + * 枚举 {@link TradeOrderTypeEnum} + */ + private Integer type; + + /** + * 订单价格 + */ + private Price price; + + /** + * 订单项数组 + */ + private List items; + + /** + * 营销活动数组 + * + * 只对应 {@link Price#items} 商品匹配的活动 + */ + private List promotions; + + /** + * 优惠劵编号 + */ + private Long couponId; + + /** + * 使用的积分 + */ + private Integer usePoint; + + /** + * 使用的积分 + */ + private Integer givePoint; + + /** + * 砍价活动编号 + */ + private Long bargainActivityId; + + /** + * 订单价格 + */ + @Data + public static class Price { + + /** + * 商品原价(总),单位:分 + * + * 基于 {@link OrderItem#getPrice()} * {@link OrderItem#getCount()} 求和 + * + * 对应 taobao 的 trade.total_fee 字段 + */ + private Integer totalPrice; + /** + * 订单优惠(总),单位:分 + * + * 对应 taobao 的 order.discount_fee 字段 + */ + private Integer discountPrice; + /** + * 运费金额,单位:分 + */ + private Integer deliveryPrice; + /** + * 优惠劵减免金额(总),单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 + */ + private Integer couponPrice; + /** + * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 + */ + private Integer pointPrice; + /** + * VIP 减免金额,单位:分 + */ + private Integer vipPrice; + /** + * 最终购买金额(总),单位:分 + * + * = {@link #totalPrice} + * - {@link #couponPrice} + * - {@link #pointPrice} + * - {@link #discountPrice} + * + {@link #deliveryPrice} + * - {@link #vipPrice} + */ + private Integer payPrice; + + } + + /** + * 订单商品 SKU + */ + @Data + public static class OrderItem { + + /** + * SPU 编号 + */ + private Long spuId; + /** + * SKU 编号 + */ + private Long skuId; + /** + * 购买数量 + */ + private Integer count; + /** + * 购物车项的编号 + */ + private Long cartId; + /** + * 是否选中 + */ + private Boolean selected; + + /** + * 商品原价(单),单位:分 + * + * 对应 ProductSkuDO 的 price 字段 + * 对应 taobao 的 order.price 字段 + */ + private Integer price; + /** + * 优惠金额(总),单位:分 + * + * 对应 taobao 的 order.discount_fee 字段 + */ + private Integer discountPrice; + /** + * 运费金额(总),单位:分 + */ + private Integer deliveryPrice; + /** + * 优惠劵减免金额,单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 + */ + private Integer couponPrice; + /** + * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 + */ + private Integer pointPrice; + /** + * 使用的积分 + */ + private Integer usePoint; + /** + * VIP 减免金额,单位:分 + */ + private Integer vipPrice; + /** + * 应付金额(总),单位:分 + * + * = {@link #price} * {@link #count} + * - {@link #couponPrice} + * - {@link #pointPrice} + * - {@link #discountPrice} + * + {@link #deliveryPrice} + * - {@link #vipPrice} + */ + private Integer payPrice; + + // ========== 商品 SPU 信息 ========== + /** + * 商品名 + */ + private String spuName; + /** + * 商品图片 + * + * 优先级:SKU.picUrl > SPU.picUrl + */ + private String picUrl; + /** + * 分类编号 + */ + private Long categoryId; + + /** + * 运费模板 Id + */ + private Long deliveryTemplateId; + + // ========== 商品 SKU 信息 ========== + /** + * 商品重量,单位:kg 千克 + */ + private Double weight; + /** + * 商品体积,单位:m^3 平米 + */ + private Double volume; + + /** + * 商品属性数组 + */ + private List properties; + + /** + * 使用的积分 + */ + private Integer givePoint; + + } + + /** + * 营销明细 + */ + @Data + public static class Promotion { + + /** + * 营销编号 + * + * 例如说:营销活动的编号、优惠劵的编号 + */ + private Long id; + /** + * 营销名字 + */ + private String name; + /** + * 营销类型 + * + * 枚举 {@link PromotionTypeEnum} + */ + private Integer type; + /** + * 计算时的原价(总),单位:分 + */ + private Integer totalPrice; + /** + * 计算时的优惠(总),单位:分 + */ + private Integer discountPrice; + /** + * 匹配的商品 SKU 数组 + */ + private List items; + + // ========== 匹配情况 ========== + + /** + * 是否满足优惠条件 + */ + private Boolean match; + /** + * 满足条件的提示 + * + * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元” + * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元” + */ + private String description; + + } + + /** + * 营销匹配的商品 SKU + */ + @Data + public static class PromotionItem { + + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 计算时的原价(总),单位:分 + */ + private Integer totalPrice; + /** + * 计算时的优惠(总),单位:分 + */ + private Integer discountPrice; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeBargainActivityPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeBargainActivityPriceCalculator.java new file mode 100644 index 0000000..56b8e35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeBargainActivityPriceCalculator.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; +import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +// TODO huihui:单测需要补充 +/** + * 砍价活动的 {@link TradePriceCalculator} 实现类 + * + * @author 芋道源码 + */ +@Component +@Order(TradePriceCalculator.ORDER_BARGAIN_ACTIVITY) +public class TradeBargainActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private BargainRecordApi bargainRecordApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1. 判断订单类型和是否具有拼团记录编号 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.BARGAIN.getType())) { + return; + } + Assert.isTrue(param.getItems().size() == 1, "砍价时,只允许选择一个商品"); + Assert.isTrue(param.getItems().get(0).getCount() == 1, "砍价时,只允许选择一个商品"); + // 2. 校验是否可以参与砍价 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); + BargainValidateJoinRespDTO bargainActivity = bargainRecordApi.validateJoinBargain( + param.getUserId(), param.getBargainRecordId(), orderItem.getSkuId()); + + // 3.1 记录优惠明细 + Integer discountPrice = orderItem.getPayPrice() - bargainActivity.getBargainPrice() * orderItem.getCount(); + // TODO 芋艿:极端情况,优惠金额为负数,需要处理 + TradePriceCalculatorHelper.addPromotion(result, orderItem, + param.getSeckillActivityId(), bargainActivity.getName(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(), + StrUtil.format("砍价活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), + discountPrice); + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + TradePriceCalculatorHelper.recountAllPrice(result); + // 4. 特殊:设置对应的砍价活动编号 + result.setBargainActivityId(bargainActivity.getActivityId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCombinationActivityPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCombinationActivityPriceCalculator.java new file mode 100644 index 0000000..4021bbe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCombinationActivityPriceCalculator.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +// TODO @puhui999:单测可以后补下 + +/** + * 拼团活动的 {@link TradePriceCalculator} 实现类 + * + * @author HUIHUI + */ +@Component +@Order(TradePriceCalculator.ORDER_COMBINATION_ACTIVITY) +public class TradeCombinationActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private CombinationRecordApi combinationRecordApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1. 判断订单类型和是否具有拼团活动编号 + if (param.getCombinationActivityId() == null) { + return; + } + Assert.isTrue(param.getItems().size() == 1, "拼团时,只允许选择一个商品"); + // 2. 校验是否可以参与拼团 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); + CombinationValidateJoinRespDTO combinationActivity = combinationRecordApi.validateJoinCombination( + param.getUserId(), param.getCombinationActivityId(), param.getCombinationHeadId(), + orderItem.getSkuId(), orderItem.getCount()); + + // 3.1 记录优惠明细 + Integer discountPrice = orderItem.getPayPrice() - combinationActivity.getCombinationPrice() * orderItem.getCount(); + TradePriceCalculatorHelper.addPromotion(result, orderItem, + param.getCombinationActivityId(), combinationActivity.getName(), PromotionTypeEnum.COMBINATION_ACTIVITY.getType(), + StrUtil.format("拼团活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), + discountPrice); + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + TradePriceCalculatorHelper.recountAllPrice(result); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java new file mode 100644 index 0000000..b871186 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java @@ -0,0 +1,120 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.function.Predicate; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_MIN_PRICE; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_SPU; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER; + +/** + * 优惠劵的 {@link TradePriceCalculator} 实现类 + * + * @author 芋道源码 + */ +@Component +@Order(TradePriceCalculator.ORDER_COUPON) +public class TradeCouponPriceCalculator implements TradePriceCalculator { + + @Resource + private CouponApi couponApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1.1 校验优惠劵 + if (param.getCouponId() == null) { + return; + } + CouponRespDTO coupon = couponApi.validateCoupon(new CouponValidReqDTO() + .setId(param.getCouponId()).setUserId(param.getUserId())); + Assert.notNull(coupon, "校验通过的优惠劵({}),不能为空", param.getCouponId()); + // 1.2 只有【普通】订单,才允许使用优惠劵 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { + throw exception(PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER); + } + + // 2.1 获得匹配的商品 SKU 数组 + List orderItems = filterMatchCouponOrderItems(result, coupon); + if (CollUtil.isEmpty(orderItems)) { + throw exception(COUPON_NO_MATCH_SPU); + } + // 2.2 计算是否满足优惠劵的使用金额 + Integer totalPayPrice = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); + if (totalPayPrice < coupon.getUsePrice()) { + throw exception(COUPON_NO_MATCH_MIN_PRICE); + } + + // 3.1 计算可以优惠的金额 + Integer couponPrice = getCouponPrice(coupon, totalPayPrice); + Assert.isTrue(couponPrice < totalPayPrice, + "优惠劵({}) 的优惠金额({}),不能大于订单总金额({})", coupon.getId(), couponPrice, totalPayPrice); + // 3.2 计算分摊的优惠金额 + List divideCouponPrices = TradePriceCalculatorHelper.dividePrice(orderItems, couponPrice); + + // 4.1 记录使用的优惠劵 + result.setCouponId(param.getCouponId()); + // 4.2 记录优惠明细 + TradePriceCalculatorHelper.addPromotion(result, orderItems, + param.getCouponId(), coupon.getName(), PromotionTypeEnum.COUPON.getType(), + StrUtil.format("优惠劵:省 {} 元", TradePriceCalculatorHelper.formatPrice(couponPrice)), + divideCouponPrices); + // 4.3 更新 SKU 优惠金额 + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + orderItem.setCouponPrice(divideCouponPrices.get(i)); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + } + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private Integer getCouponPrice(CouponRespDTO coupon, Integer totalPayPrice) { + if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价 + return coupon.getDiscountPrice(); + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折 + int couponPrice = totalPayPrice * coupon.getDiscountPercent() / 100; + return coupon.getDiscountLimitPrice() == null ? couponPrice + : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限 + } + throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon)); + } + + /** + * 获得优惠劵可使用的订单项(商品)列表 + * + * @param result 计算结果 + * @param coupon 优惠劵 + * @return 订单项(商品)列表 + */ + private List filterMatchCouponOrderItems(TradePriceCalculateRespBO result, + CouponRespDTO coupon) { + Predicate matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; + if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { + matchPredicate = matchPredicate // 额外加如下条件 + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getSpuId())); + } else if (PromotionProductScopeEnum.CATEGORY.getScope().equals(coupon.getProductScope())) { + matchPredicate = matchPredicate // 额外加如下条件 + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getCategoryId())); + } + return filterList(result.getItems(), matchPredicate); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java new file mode 100644 index 0000000..94f813e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java @@ -0,0 +1,226 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService; +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; + +/** + * 运费的 {@link TradePriceCalculator} 实现类 + * + * @author jason + */ +@Component +@Order(TradePriceCalculator.ORDER_DELIVERY) +@Slf4j +public class TradeDeliveryPriceCalculator implements TradePriceCalculator { + + @Resource + private MemberAddressApi addressApi; + + @Resource + private DeliveryPickUpStoreService deliveryPickUpStoreService; + @Resource + private DeliveryExpressTemplateService deliveryExpressTemplateService; + @Resource + private TradeConfigService tradeConfigService; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + if (param.getDeliveryType() == null) { + return; + } + if (DeliveryTypeEnum.PICK_UP.getType().equals(param.getDeliveryType())) { + calculateByPickUp(param); + } else if (DeliveryTypeEnum.EXPRESS.getType().equals(param.getDeliveryType())) { + calculateExpress(param, result); + } + } + + private void calculateByPickUp(TradePriceCalculateReqBO param) { + if (param.getPickUpStoreId() == null) { + // 价格计算时,如果为空就不算~最终下单,会校验该字段不允许空 + return; + } + DeliveryPickUpStoreDO pickUpStore = deliveryPickUpStoreService.getDeliveryPickUpStore(param.getPickUpStoreId()); + if (pickUpStore == null || CommonStatusEnum.DISABLE.getStatus().equals(pickUpStore.getStatus())) { + throw exception(PICK_UP_STORE_NOT_EXISTS); + } + } + + // ========= 快递发货 ========== + + private void calculateExpress(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 0. 得到收件地址区域 + if (param.getAddressId() == null) { + // 价格计算时,如果为空就不算~最终下单,会校验该字段不允许空 + return; + } + MemberAddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); + Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); + + // 情况一:全局包邮 + if (isGlobalExpressFree(result)) { + return; + } + + // 情况二:快递模版 + // 2.1 过滤出已选中的商品 SKU + List selectedItem = filterList(result.getItems(), OrderItem::getSelected); + Set deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId); + Map expressTemplateMap = + deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId()); + // 2.2 计算配送费用 + if (CollUtil.isEmpty(expressTemplateMap)) { + log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId()); + throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND); + } + calculateDeliveryPrice(selectedItem, expressTemplateMap, result); + } + + /** + * 是否全局包邮 + * + * @param result 计算结果 + * @return 是否包邮 + */ + private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) { + TradeConfigDO config = tradeConfigService.getTradeConfig(); + return config != null + && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮 + && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格 + } + + private void calculateDeliveryPrice(List selectedSkus, + Map expressTemplateMap, + TradePriceCalculateRespBO result) { + // 按商品运费模板来计算商品的运费:相同的运费模板可能对应多条订单商品 SKU + Map> template2ItemMap = convertMultiMap(selectedSkus, OrderItem::getDeliveryTemplateId); + // 依次计算快递运费 + for (Map.Entry> entry : template2ItemMap.entrySet()) { + Long templateId = entry.getKey(); + List orderItems = entry.getValue(); + DeliveryExpressTemplateRespBO templateBO = expressTemplateMap.get(templateId); + if (templateBO == null) { + log.error("[calculateDeliveryPrice][不能计算快递运费,找不到 templateId({}) 对应的运费模板配置]", templateId); + continue; + } + // 1. 优先判断是否包邮。如果包邮不计算快递运费 + if (isExpressTemplateFree(orderItems, templateBO.getChargeMode(), templateBO.getFree())) { + continue; + } + // 2. 计算快递运费 + calculateExpressFeeByChargeMode(orderItems, templateBO.getChargeMode(), templateBO.getCharge()); + } + TradePriceCalculatorHelper.recountAllPrice(result); + } + + /** + * 按配送方式来计算运费 + * + * @param orderItems SKU 商品项目 + * @param chargeMode 配送计费方式 + * @param templateCharge 快递运费配置 + */ + private void calculateExpressFeeByChargeMode(List orderItems, Integer chargeMode, + DeliveryExpressTemplateRespBO.Charge templateCharge) { + if (templateCharge == null) { + log.error("[calculateExpressFeeByChargeMode][计算快递运费时,找不到 SKU({}) 对应的运费模版]", orderItems); + return; + } + double totalChargeValue = getTotalChargeValue(orderItems, chargeMode); + // 1. 计算 SKU 商品快递费用 + int deliveryPrice; + if (totalChargeValue <= templateCharge.getStartCount()) { + deliveryPrice = templateCharge.getStartPrice(); + } else { + double remainWeight = totalChargeValue - templateCharge.getStartCount(); + // 剩余重量/ 续件 = 续件的次数. 向上取整 + int extraNum = (int) Math.ceil(remainWeight / templateCharge.getExtraCount()); + int extraPrice = templateCharge.getExtraPrice() * extraNum; + deliveryPrice = templateCharge.getStartPrice() + extraPrice; + } + + // 2. 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额 + int remainPrice = deliveryPrice; + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem item = orderItems.get(i); + int partPrice; + double chargeValue = getChargeValue(item, chargeMode); + if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 + partPrice = (int) (deliveryPrice * (chargeValue / totalChargeValue)); + remainPrice -= partPrice; + } else { + partPrice = remainPrice; + } + Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); + // 更新快递运费 + item.setDeliveryPrice(partPrice); + TradePriceCalculatorHelper.recountPayPrice(item); + } + } + + /** + * 检查是否包邮 + * + * @param chargeMode 配送计费方式 + * @param templateFree 包邮配置 + */ + private boolean isExpressTemplateFree(List orderItems, Integer chargeMode, + DeliveryExpressTemplateRespBO.Free templateFree) { + if (templateFree == null) { + return false; + } + double totalChargeValue = getTotalChargeValue(orderItems, chargeMode); + double totalPrice = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); + return totalChargeValue >= templateFree.getFreeCount() && totalPrice >= templateFree.getFreePrice(); + } + + private double getTotalChargeValue(List orderItems, Integer chargeMode) { + double total = 0; + for (OrderItem orderItem : orderItems) { + total += getChargeValue(orderItem, chargeMode); + } + return total; + } + + private double getChargeValue(OrderItem orderItem, Integer chargeMode) { + DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); + switch (chargeModeEnum) { + case COUNT: + return orderItem.getCount(); + case WEIGHT: + return orderItem.getWeight() != null ? orderItem.getWeight() * orderItem.getCount() : 0; + case VOLUME: + return orderItem.getVolume() != null ? orderItem.getVolume() * orderItem.getCount() : 0; + default: + throw new IllegalArgumentException(StrUtil.format("未知的计费模式({})", chargeMode)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java new file mode 100644 index 0000000..a427806 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; + +/** + * 限时折扣的 {@link TradePriceCalculator} 实现类 + * + * @author 芋道源码 + */ +@Component +@Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY) +public class TradeDiscountActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private DiscountActivityApi discountActivityApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 0. 只有【普通】订单,才计算该优惠 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { + return; + } + // 获得 SKU 对应的限时折扣活动 + List discountProducts = discountActivityApi.getMatchDiscountProductList( + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); + if (CollUtil.isEmpty(discountProducts)) { + return; + } + Map discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId); + + // 处理每个 SKU 的限时折扣 + result.getItems().forEach(orderItem -> { + // 1. 获取该 SKU 的优惠信息 + DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId()); + if (discountProduct == null) { + return; + } + // 2. 计算优惠金额 + Integer newPayPrice = calculatePayPrice(discountProduct, orderItem); + Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice; + + // 3.1 记录优惠明细 + if (orderItem.getSelected()) { + // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 + TradePriceCalculatorHelper.addPromotion(result, orderItem, + discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), + StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), + newDiscountPrice); + } + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + }); + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private Integer calculatePayPrice(DiscountProductRespDTO discountProduct, + TradePriceCalculateRespBO.OrderItem orderItem) { + Integer price = orderItem.getPayPrice(); + if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价 + price -= discountProduct.getDiscountPrice() * orderItem.getCount(); + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折 + price = price * discountProduct.getDiscountPercent() / 100; + } else { + throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct)); + } + return price; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java new file mode 100644 index 0000000..8aee001 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; + +/** + * 会员 VIP 折扣的 {@link TradePriceCalculator} 实现类 + * + * @author 芋道源码 + */ +@Component +@Order(TradePriceCalculator.ORDER_MEMBER_LEVEL) +public class TradeMemberLevelPriceCalculator implements TradePriceCalculator { + + @Resource + private MemberLevelApi memberLevelApi; + @Resource + private MemberUserApi memberUserApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 0. 只有【普通】订单,才计算该优惠 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { + return; + } + // 1. 获得用户的会员等级 + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); + if (user.getLevelId() == null || user.getLevelId() <= 0) { + return; + } + MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId()); + if (level == null || level.getDiscountPercent() == null) { + return; + } + + // 2. 计算每个 SKU 的优惠金额 + result.getItems().forEach(orderItem -> { + // 2.1 计算优惠金额 + Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent()); + if (vipPrice <= 0) { + return; + } + + // 2.2 记录优惠明细 + if (orderItem.getSelected()) { + // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 + TradePriceCalculatorHelper.addPromotion(result, orderItem, + level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), + String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), + vipPrice); + } + + // 2.3 更新 SKU 的优惠金额 + orderItem.setVipPrice(vipPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + }); + TradePriceCalculatorHelper.recountAllPrice(result); + } + + /** + * 计算会员 VIP 优惠价格 + * + * @param price 原价 + * @param discountPercent 折扣 + * @return 优惠价格 + */ + public Integer calculateVipPrice(Integer price, Integer discountPercent) { + if (discountPercent == null) { + return 0; + } + Integer newPrice = price * discountPercent / 100; + return price - newPrice; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java new file mode 100644 index 0000000..f3176e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.util.BooleanUtil; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Optional; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; + +/** + * 赠送积分的 {@link TradePriceCalculator} 实现类 + * + * @author owen + */ +@Component +@Order(TradePriceCalculator.ORDER_POINT_GIVE) +@Slf4j +public class TradePointGiveCalculator implements TradePriceCalculator { + + @Resource + private MemberConfigApi memberConfigApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1.1 校验积分功能是否开启 + int givePointPerYuan = Optional.ofNullable(memberConfigApi.getConfig()) + .filter(config -> BooleanUtil.isTrue(config.getPointTradeDeductEnable())) + .map(MemberConfigRespDTO::getPointTradeGivePoint) + .orElse(0); + if (givePointPerYuan <= 0) { + return; + } + // 1.2 校验支付金额 + if (result.getPrice().getPayPrice() <= 0) { + return; + } + + // 2.1 计算赠送积分 + int givePoint = MoneyUtils.calculateRatePriceFloor(result.getPrice().getPayPrice(), (double) givePointPerYuan); + // 2.2 计算分摊的赠送积分 + List orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); + List dividePoints = TradePriceCalculatorHelper.dividePrice(orderItems, givePoint); + + // 3.2 更新 SKU 赠送积分 + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + // 商品可能赠送了积分,所以这里要加上 + orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i)); + } + // 3.3 更新订单赠送积分 + TradePriceCalculatorHelper.recountAllGivePoint(result); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java new file mode 100644 index 0000000..aae6e5f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; + +/** + * 使用积分的 {@link TradePriceCalculator} 实现类 + * + * @author owen + */ +@Component +@Order(TradePriceCalculator.ORDER_POINT_USE) +@Slf4j +public class TradePointUsePriceCalculator implements TradePriceCalculator { + + @Resource + private MemberConfigApi memberConfigApi; + @Resource + private MemberUserApi memberUserApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 默认使用积分为 0 + result.setUsePoint(0); + // 1.1 校验是否使用积分 + if (!BooleanUtil.isTrue(param.getPointStatus())) { + result.setUsePoint(0); + return; + } + // 1.2 校验积分抵扣是否开启 + MemberConfigRespDTO config = memberConfigApi.getConfig(); + if (!isDeductPointEnable(config)) { + return; + } + // 1.3 校验用户积分余额 + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); + if (user.getPoint() == null || user.getPoint() <= 0) { + return; + } + + // 2.1 计算积分优惠金额 + int pointPrice = calculatePointPrice(config, user.getPoint(), result); + // 2.2 计算分摊的积分、抵扣金额 + List orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); + List dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice); + List divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint()); + + // 3.1 记录优惠明细 + TradePriceCalculatorHelper.addPromotion(result, orderItems, + param.getUserId(), "积分抵扣", PromotionTypeEnum.POINT.getType(), + StrUtil.format("积分抵扣:省 {} 元", TradePriceCalculatorHelper.formatPrice(pointPrice)), + dividePointPrices); + // 3.2 更新 SKU 优惠金额 + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + orderItem.setPointPrice(dividePointPrices.get(i)); + orderItem.setUsePoint(divideUsePoints.get(i)); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + } + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private boolean isDeductPointEnable(MemberConfigRespDTO config) { + return config != null && + BooleanUtil.isTrue(config.getPointTradeDeductEnable()) && // 积分功能是否启用 + config.getPointTradeDeductUnitPrice() != null && config.getPointTradeDeductUnitPrice() > 0; // 有没有配置:1 积分抵扣多少分 + } + + private Integer calculatePointPrice(MemberConfigRespDTO config, Integer usePoint, TradePriceCalculateRespBO result) { + // 每个订单最多可以使用的积分数量 + if (config.getPointTradeDeductMaxPrice() != null && config.getPointTradeDeductMaxPrice() > 0) { + usePoint = Math.min(usePoint, config.getPointTradeDeductMaxPrice()); + } + // TODO @疯狂:这里应该是,抵扣到只剩下 0.01; + // 积分优惠金额(分) + int pointPrice = usePoint * config.getPointTradeDeductUnitPrice(); + if (result.getPrice().getPayPrice() <= pointPrice) { + // 禁止 0 元购 + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); + } +// // 允许0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分 +// if (result.getPrice().getPayPrice() < pointPrice) { +// pointPrice = result.getPrice().getPayPrice(); +// // 反推需要扣除的积分 +// usePoint = NumberUtil.toBigDecimal(pointPrice) +// .divide(NumberUtil.toBigDecimal(config.getPointTradeDeductUnitPrice()), 0, RoundingMode.HALF_UP) +// .intValue(); +// } + // 记录使用的积分 + result.setUsePoint(usePoint); + return pointPrice; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java new file mode 100644 index 0000000..1fc7e69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; + +/** + * 价格计算的计算器接口 + * + * 优惠计算顺序: + * 1. 积分抵现、会员价、优惠券、粉丝专享价、满减送哪个优先计算? + * + * @author 芋道源码 + */ +public interface TradePriceCalculator { + + int ORDER_MEMBER_LEVEL = 5; + + int ORDER_SECKILL_ACTIVITY = 8; + int ORDER_BARGAIN_ACTIVITY = 8; + int ORDER_COMBINATION_ACTIVITY = 8; + + int ORDER_DISCOUNT_ACTIVITY = 10; + int ORDER_REWARD_ACTIVITY = 20; + int ORDER_COUPON = 30; + int ORDER_POINT_USE = 40; + /** + * 快递运费的计算 + * + * 放在各种营销活动、优惠劵后面 + */ + int ORDER_DELIVERY = 50; + /** + * 赠送积分,放最后 + * + * 放在 {@link #ORDER_DELIVERY} 后面的原因,是运费也会产生费用,需要赠送对应积分 + */ + int ORDER_POINT_GIVE = 999; + + void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java new file mode 100644 index 0000000..2862012 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java @@ -0,0 +1,341 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; +import static java.util.Collections.singletonList; + +/** + * {@link TradePriceCalculator} 的工具类 + * + * 主要实现对 {@link TradePriceCalculateRespBO} 计算结果的操作 + * + * @author 芋道源码 + */ +public class TradePriceCalculatorHelper { + + public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param, + List spuList, List skuList) { + // 创建 PriceCalculateRespDTO 对象 + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); + result.setType(getOrderType(param)); + result.setPromotions(new ArrayList<>()); + + // 创建它的 OrderItem 属性 + result.setItems(new ArrayList<>(param.getItems().size())); + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map skuMap = convertMap(skuList, ProductSkuRespDTO::getId); + param.getItems().forEach(item -> { + ProductSkuRespDTO sku = skuMap.get(item.getSkuId()); + if (sku == null) { + return; + } + ProductSpuRespDTO spu = spuMap.get(sku.getSpuId()); + if (spu == null) { + return; + } + // 商品项 + TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem(); + result.getItems().add(orderItem); + orderItem.setSpuId(sku.getSpuId()).setSkuId(sku.getId()) + .setCount(item.getCount()).setCartId(item.getCartId()).setSelected(item.getSelected()); + // sku 价格 + orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) + .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0).setVipPrice(0); + // sku 信息 + orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()) + .setWeight(sku.getWeight()).setVolume(sku.getVolume()); + // spu 信息 + orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()) + .setDeliveryTemplateId(spu.getDeliveryTemplateId()) + .setGivePoint(spu.getGiveIntegral()).setUsePoint(0); + if (orderItem.getPicUrl() == null) { + orderItem.setPicUrl(spu.getPicUrl()); + } + }); + + // 创建它的 Price 属性 + result.setPrice(new TradePriceCalculateRespBO.Price()); + recountAllPrice(result); + recountAllGivePoint(result); + return result; + } + + /** + * 计算订单类型 + * + * @param param 计算参数 + * @return 订单类型 + */ + private static Integer getOrderType(TradePriceCalculateReqBO param) { + if (param.getSeckillActivityId() != null) { + return TradeOrderTypeEnum.SECKILL.getType(); + } + if (param.getCombinationActivityId() != null) { + return TradeOrderTypeEnum.COMBINATION.getType(); + } + if (param.getBargainRecordId() != null) { + return TradeOrderTypeEnum.BARGAIN.getType(); + } + return TradeOrderTypeEnum.NORMAL.getType(); + } + + /** + * 基于订单项,重新计算 price 总价 + * + * @param result 计算结果 + */ + public static void recountAllPrice(TradePriceCalculateRespBO result) { + // 先重置 + TradePriceCalculateRespBO.Price price = result.getPrice(); + price.setTotalPrice(0).setDiscountPrice(0).setDeliveryPrice(0) + .setCouponPrice(0).setPointPrice(0).setVipPrice(0).setPayPrice(0); + // 再合计 item + result.getItems().forEach(item -> { + if (!item.getSelected()) { + return; + } + price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount()); + price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice()); + price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice()); + price.setCouponPrice(price.getCouponPrice() + item.getCouponPrice()); + price.setPointPrice(price.getPointPrice() + item.getPointPrice()); + price.setVipPrice(price.getVipPrice() + item.getVipPrice()); + price.setPayPrice(price.getPayPrice() + item.getPayPrice()); + }); + } + + /** + * 基于订单项,重新计算赠送积分 + * + * @param result 计算结果 + */ + public static void recountAllGivePoint(TradePriceCalculateRespBO result) { + result.setGivePoint(getSumValue(result.getItems(), item -> item.getSelected() ? item.getGivePoint() : 0, Integer::sum)); + } + + /** + * 重新计算单个订单项的支付金额 + * + * @param orderItem 订单项 + */ + public static void recountPayPrice(TradePriceCalculateRespBO.OrderItem orderItem) { + orderItem.setPayPrice(orderItem.getPrice() * orderItem.getCount() + - orderItem.getDiscountPrice() + + orderItem.getDeliveryPrice() + - orderItem.getCouponPrice() + - orderItem.getPointPrice() + - orderItem.getVipPrice() + ); + } + + /** + * 重新计算每个订单项的支付金额 + * + * 【目前主要是单测使用】 + * + * @param orderItems 订单项数组 + */ + public static void recountPayPrice(List orderItems) { + orderItems.forEach(orderItem -> { + if (orderItem.getDiscountPrice() == null) { + orderItem.setDiscountPrice(0); + } + if (orderItem.getDeliveryPrice() == null) { + orderItem.setDeliveryPrice(0); + } + if (orderItem.getCouponPrice() == null) { + orderItem.setCouponPrice(0); + } + if (orderItem.getPointPrice() == null) { + orderItem.setPointPrice(0); + } + if (orderItem.getUsePoint() == null) { + orderItem.setUsePoint(0); + } + if (orderItem.getGivePoint() == null) { + orderItem.setGivePoint(0); + } + if (orderItem.getVipPrice() == null) { + orderItem.setVipPrice(0); + } + recountPayPrice(orderItem); + }); + } + + /** + * 计算已选中的订单项,总支付金额 + * + * @param orderItems 订单项数组 + * @return 总支付金额 + */ + public static Integer calculateTotalPayPrice(List orderItems) { + return getSumValue(orderItems, + orderItem -> orderItem.getSelected() ? orderItem.getPayPrice() : 0, // 未选中的情况下,不计算支付金额 + Integer::sum); + } + + /** + * 计算已选中的订单项,总商品数 + * + * @param orderItems 订单项数组 + * @return 总商品数 + */ + public static Integer calculateTotalCount(List orderItems) { + return getSumValue(orderItems, + orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量 + Integer::sum); + } + + /** + * 按照支付金额,返回每个订单项的分摊金额数组 + * + * 实际上 price 不仅仅可以传递的是金额,也可以是积分。因为它的实现逻辑,就是根据 payPrice 做分摊而已 + * + * @param orderItems 订单项数组 + * @param price 金额 + * @return 分摊金额数组,和传入的 orderItems 一一对应 + */ + public static List dividePrice(List orderItems, Integer price) { + Integer total = calculateTotalPayPrice(orderItems); + assert total != null; + // 遍历每一个,进行分摊 + List prices = new ArrayList<>(orderItems.size()); + int remainPrice = price; + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + // 1. 如果是未选中,则分摊为 0 + if (!orderItem.getSelected()) { + prices.add(0); + continue; + } + // 2. 如果选中,则按照百分比,进行分摊 + int partPrice; + if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 + partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); + remainPrice -= partPrice; + } else { + partPrice = remainPrice; + } + Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); + prices.add(partPrice); + } + return prices; + } + + /** + * 计算订单调价价格分摊 + * + * 和 {@link #dividePrice(List, Integer)} 逻辑一致,只是传入的是 TradeOrderItemDO 对象 + * + * @param items 订单项 + * @param price 订单支付金额 + * @return 分摊金额数组,和传入的 orderItems 一一对应 + */ + public static List dividePrice2(List items, Integer price) { + Integer total = getSumValue(items, TradeOrderItemDO::getPayPrice, Integer::sum); + assert total != null; + // 遍历每一个,进行分摊 + List prices = new ArrayList<>(items.size()); + int remainPrice = price; + for (int i = 0; i < items.size(); i++) { + TradeOrderItemDO orderItem = items.get(i); + int partPrice; + if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 + partPrice = (int) (price * (1.0D * orderItem.getPrice() / total)); + remainPrice -= partPrice; + } else { + partPrice = remainPrice; + } + prices.add(partPrice); + } + return prices; + } + + /** + * 添加【匹配】单个 OrderItem 的营销明细 + * + * @param result 价格计算结果 + * @param orderItem 单个订单商品 SKU + * @param id 营销编号 + * @param name 营销名字 + * @param description 满足条件的提示 + * @param type 营销类型 + * @param discountPrice 单个订单商品 SKU 的优惠价格(总) + */ + public static void addPromotion(TradePriceCalculateRespBO result, TradePriceCalculateRespBO.OrderItem orderItem, + Long id, String name, Integer type, String description, Integer discountPrice) { + addPromotion(result, singletonList(orderItem), id, name, type, description, singletonList(discountPrice)); + } + + /** + * 添加【匹配】多个 OrderItem 的营销明细 + * + * @param result 价格计算结果 + * @param orderItems 多个订单商品 SKU + * @param id 营销编号 + * @param name 营销名字 + * @param description 满足条件的提示 + * @param type 营销类型 + * @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应 + */ + public static void addPromotion(TradePriceCalculateRespBO result, List orderItems, + Long id, String name, Integer type, String description, List discountPrices) { + // 创建营销明细 Item + List promotionItems = new ArrayList<>(discountPrices.size()); + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + promotionItems.add(new TradePriceCalculateRespBO.PromotionItem().setSkuId(orderItem.getSkuId()) + .setTotalPrice(orderItem.getPayPrice()).setDiscountPrice(discountPrices.get(i))); + } + // 创建营销明细 + TradePriceCalculateRespBO.Promotion promotion = new TradePriceCalculateRespBO.Promotion() + .setId(id).setName(name).setType(type) + .setTotalPrice(calculateTotalPayPrice(orderItems)) + .setDiscountPrice(getSumValue(discountPrices, value -> value, Integer::sum)) + .setItems(promotionItems).setMatch(true).setDescription(description); + result.getPromotions().add(promotion); + } + + /** + * 添加【不匹配】多个 OrderItem 的营销明细 + * + * @param result 价格计算结果 + * @param orderItems 多个订单商品 SKU + * @param id 营销编号 + * @param name 营销名字 + * @param description 满足条件的提示 + * @param type 营销类型 + */ + public static void addNotMatchPromotion(TradePriceCalculateRespBO result, List orderItems, + Long id, String name, Integer type, String description) { + // 创建营销明细 Item + List promotionItems = CollectionUtils.convertList(orderItems, + orderItem -> new TradePriceCalculateRespBO.PromotionItem().setSkuId(orderItem.getSkuId()) + .setTotalPrice(orderItem.getPayPrice()).setDiscountPrice(0)); + // 创建营销明细 + TradePriceCalculateRespBO.Promotion promotion = new TradePriceCalculateRespBO.Promotion() + .setId(id).setName(name).setType(type) + .setTotalPrice(calculateTotalPayPrice(orderItems)) + .setDiscountPrice(0) + .setItems(promotionItems).setMatch(false).setDescription(description); + result.getPromotions().add(promotion); + } + + public static String formatPrice(Integer price) { + return String.format("%.2f", price / 100d); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java new file mode 100644 index 0000000..d9b44c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java @@ -0,0 +1,142 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; + +/** + * 满减送活动的 {@link TradePriceCalculator} 实现类 + * + * @author 芋道源码 + */ +@Component +@Order(TradePriceCalculator.ORDER_REWARD_ACTIVITY) +public class TradeRewardActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private RewardActivityApi rewardActivityApi; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 0. 只有【普通】订单,才计算该优惠 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { + return; + } + // 获得 SKU 对应的满减送活动 + List rewardActivities = rewardActivityApi.getMatchRewardActivityList( + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId)); + if (CollUtil.isEmpty(rewardActivities)) { + return; + } + + // 处理每个满减送活动 + rewardActivities.forEach(rewardActivity -> calculate(param, result, rewardActivity)); + } + + private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result, + RewardActivityMatchRespDTO rewardActivity) { + // 1.1 获得满减送的订单项(商品)列表 + List orderItems = filterMatchCouponOrderItems(result, rewardActivity); + if (CollUtil.isEmpty(orderItems)) { + return; + } + // 1.2 获得最大匹配的满减送活动的规则 + RewardActivityMatchRespDTO.Rule rule = getMaxMatchRewardActivityRule(rewardActivity, orderItems); + if (rule == null) { + TradePriceCalculatorHelper.addNotMatchPromotion(result, orderItems, + rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), + getRewardActivityNotMeetTip(rewardActivity)); + return; + } + + // 2.1 计算可以优惠的金额 + Integer newDiscountPrice = rule.getDiscountPrice(); + // 2.2 计算分摊的优惠金额 + List divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice); + + // 3.1 记录使用的优惠劵 + result.setCouponId(param.getCouponId()); + // 3.2 记录优惠明细 + TradePriceCalculatorHelper.addPromotion(result, orderItems, + rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), + StrUtil.format("满减送:省 {} 元", formatPrice(rule.getDiscountPrice())), + divideDiscountPrices); + // 3.3 更新 SKU 优惠金额 + for (int i = 0; i < orderItems.size(); i++) { + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + divideDiscountPrices.get(i)); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + } + TradePriceCalculatorHelper.recountAllPrice(result); + } + + /** + * 获得满减送的订单项(商品)列表 + * + * @param result 计算结果 + * @param rewardActivity 满减送活动 + * @return 订单项(商品)列表 + */ + private List filterMatchCouponOrderItems(TradePriceCalculateRespBO result, + RewardActivityMatchRespDTO rewardActivity) { + return filterList(result.getItems(), + orderItem -> CollUtil.contains(rewardActivity.getSpuIds(), orderItem.getSpuId())); + } + + /** + * 获得最大匹配的满减送活动的规则 + * + * @param rewardActivity 满减送活动 + * @param orderItems 商品项 + * @return 匹配的活动规则 + */ + private RewardActivityMatchRespDTO.Rule getMaxMatchRewardActivityRule(RewardActivityMatchRespDTO rewardActivity, + List orderItems) { + // 1. 计算数量和价格 + Integer count = TradePriceCalculatorHelper.calculateTotalCount(orderItems); + Integer price = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); + assert count != null && price != null; + + // 2. 倒序找一个最大优惠的规则 + for (int i = rewardActivity.getRules().size() - 1; i >= 0; i--) { + RewardActivityMatchRespDTO.Rule rule = rewardActivity.getRules().get(i); + if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType()) + && price >= rule.getLimit()) { + return rule; + } + if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType()) + && count >= rule.getLimit()) { + return rule; + } + } + return null; + } + + /** + * 获得满减送活动部匹配时的提示 + * + * @param rewardActivity 满减送活动 + * @return 提示 + */ + private String getRewardActivityNotMeetTip(RewardActivityMatchRespDTO rewardActivity) { + // TODO 芋艿:后面再想想;应该找第一个规则,算下还差多少即可。 + return "TODO"; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java new file mode 100644 index 0000000..bbc85db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; + +// TODO huihui:单测需要补充 +/** + * 秒杀活动的 {@link TradePriceCalculator} 实现类 + * + * @author HUIHUI + */ +@Component +@Order(TradePriceCalculator.ORDER_SECKILL_ACTIVITY) +public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator { + + @Resource + private SeckillActivityApi seckillActivityApi; + + @Resource + private TradeOrderQueryService tradeOrderQueryService; + + @Override + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // 1. 判断订单类型和是否具有秒杀活动编号 + if (param.getSeckillActivityId() == null) { + return; + } + Assert.isTrue(param.getItems().size() == 1, "秒杀时,只允许选择一个商品"); + // 2. 校验是否可以参与秒杀 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); + SeckillValidateJoinRespDTO seckillActivity = validateJoinSeckill( + param.getUserId(), param.getSeckillActivityId(), + orderItem.getSkuId(), orderItem.getCount()); + + // 3.1 记录优惠明细 + Integer discountPrice = orderItem.getPayPrice() - seckillActivity.getSeckillPrice() * orderItem.getCount(); + TradePriceCalculatorHelper.addPromotion(result, orderItem, + param.getSeckillActivityId(), seckillActivity.getName(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(), + StrUtil.format("秒杀活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), + discountPrice); + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private SeckillValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) { + // 1. 校验是否可以参与秒杀 + SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count); + // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 + int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); + if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) { + throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT); + } + return seckillActivity; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml new file mode 100644 index 0000000..066f75d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/Kd100ExpressClientIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/Kd100ExpressClientIntegrationTest.java new file mode 100644 index 0000000..11b027b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/Kd100ExpressClientIntegrationTest.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressProperties; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kd100.Kd100ExpressClient; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +/** + * {@link Kd100ExpressClient} 的集成测试 + * + * @author jason + */ +@Slf4j +public class Kd100ExpressClientIntegrationTest { + + private Kd100ExpressClient client; + + @BeforeEach + public void init() { + RestTemplate restTemplate = new RestTemplateBuilder().build(); + TradeExpressProperties.Kd100Config config = new TradeExpressProperties.Kd100Config() + .setKey("pLXUGAwK5305") + .setCustomer("E77DF18BE109F454A5CD319E44BF5177"); + client = new Kd100ExpressClient(restTemplate, config); + } + + @Test + @Disabled("集成测试,暂时忽略") + public void testGetExpressTrackList() { + ExpressTrackQueryReqDTO reqDTO = new ExpressTrackQueryReqDTO(); + reqDTO.setExpressCode("STO"); + reqDTO.setLogisticsNo("773220402764314"); + List tracks = client.getExpressTrackList(reqDTO); + System.out.println(JsonUtils.toJsonPrettyString(tracks)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/KdNiaoExpressClientIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/KdNiaoExpressClientIntegrationTest.java new file mode 100644 index 0000000..a270c4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/impl/KdNiaoExpressClientIntegrationTest.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.trade.framework.delivery.config.TradeExpressProperties; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; +import cn.iocoder.yudao.module.trade.framework.delivery.core.client.impl.kdniao.KdNiaoExpressClient; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +/** + * {@link KdNiaoExpressClient} 的集成测试 + * + * @author jason + */ +@Slf4j +public class KdNiaoExpressClientIntegrationTest { + + private KdNiaoExpressClient client; + + @BeforeEach + public void init() { + RestTemplate restTemplate = new RestTemplateBuilder().build(); + TradeExpressProperties.KdNiaoConfig config = new TradeExpressProperties.KdNiaoConfig() + .setApiKey("cb022f1e-48f1-4c4a-a723-9001ac9676b8") + .setBusinessId("1809751"); + client = new KdNiaoExpressClient(restTemplate, config); + } + + @Test + @Disabled("集成测试,暂时忽略") + public void testGetExpressTrackList() { + ExpressTrackQueryReqDTO reqDTO = new ExpressTrackQueryReqDTO(); + reqDTO.setExpressCode("STO"); + reqDTO.setLogisticsNo("777168349863987"); + List tracks = client.getExpressTrackList(reqDTO); + System.out.println(JsonUtils.toJsonPrettyString(tracks)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceTest.java new file mode 100644 index 0000000..782ba93 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceTest.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.trade.service.aftersale; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleLogMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleMapper; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum; +import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link AfterSaleService} 的单元测试 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(AfterSaleServiceImpl.class) +public class AfterSaleServiceTest extends BaseDbUnitTest { + + @Resource + private AfterSaleServiceImpl tradeAfterSaleService; + + @Resource + private AfterSaleMapper tradeAfterSaleMapper; + @Resource + private AfterSaleLogMapper tradeAfterSaleLogMapper; + + @MockBean + private TradeOrderUpdateService tradeOrderUpdateService; + @Resource + private TradeOrderQueryService tradeOrderQueryService; + + @MockBean + private PayRefundApi payRefundApi; + + @MockBean + private TradeOrderProperties tradeOrderProperties; + + @Test + public void testCreateAfterSale() { + // 准备参数 + Long userId = 1024L; + AppAfterSaleCreateReqVO createReqVO = new AppAfterSaleCreateReqVO() + .setOrderItemId(1L).setRefundPrice(100).setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay()) + .setApplyReason("退钱").setApplyDescription("快退") + .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); + // mock 方法(交易订单项) + TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> { + o.setOrderId(111L).setUserId(userId).setPayPrice(200); + o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + }); + when(tradeOrderQueryService.getOrderItem(eq(1024L), eq(1L))) + .thenReturn(orderItem); + // mock 方法(交易订单) + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()) + .setNo("202211301234")); + when(tradeOrderQueryService.getOrder(eq(1024L), eq(111L))).thenReturn(order); + + // 调用 + Long afterSaleId = tradeAfterSaleService.createAfterSale(userId, createReqVO); + // 断言(TradeAfterSaleDO) + AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId); + assertNotNull(afterSale.getNo()); + assertEquals(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus()); + assertEquals(afterSale.getType(), AfterSaleTypeEnum.IN_SALE.getType()); + assertPojoEquals(afterSale, createReqVO); + assertEquals(afterSale.getUserId(), 1024L); + assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime"); + assertEquals(afterSale.getOrderNo(), "202211301234"); + assertNull(afterSale.getPayRefundId()); + assertNull(afterSale.getRefundTime()); + assertNull(afterSale.getLogisticsId()); + assertNull(afterSale.getLogisticsNo()); + assertNull(afterSale.getDeliveryTime()); + assertNull(afterSale.getReceiveReason()); + // 断言(TradeAfterSaleLogDO) + AfterSaleLogDO afterSaleLog = tradeAfterSaleLogMapper.selectList().get(0); + assertEquals(afterSaleLog.getUserId(), userId); + assertEquals(afterSaleLog.getUserType(), UserTypeEnum.MEMBER.getValue()); + assertEquals(afterSaleLog.getAfterSaleId(), afterSaleId); + assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime"); + assertEquals(afterSaleLog.getContent(), AfterSaleStatusEnum.APPLY.getContent()); + } + + @Test + public void testGetAfterSalePage() { + // mock 数据 + AfterSaleDO dbAfterSale = randomPojo(AfterSaleDO.class, o -> { // 等会查询到 + o.setNo("202211190847450020500077"); + o.setStatus(AfterSaleStatusEnum.APPLY.getStatus()); + o.setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay()); + o.setType(AfterSaleTypeEnum.IN_SALE.getType()); + o.setOrderNo("202211190847450020500011"); + o.setSpuName("芋艿"); + o.setCreateTime(buildTime(2022, 1, 15)); + }); + tradeAfterSaleMapper.insert(dbAfterSale); + // 测试 no 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setNo("202211190847450020500066"))); + // 测试 status 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setStatus(AfterSaleStatusEnum.SELLER_REFUSE.getStatus()))); + // 测试 way 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setWay(AfterSaleWayEnum.REFUND.getWay()))); + // 测试 type 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(AfterSaleTypeEnum.AFTER_SALE.getType()))); + // 测试 orderNo 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setOrderNo("202211190847450020500022"))); + // 测试 spuName 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setSpuName("土豆"))); + // 测试 createTime 不匹配 + tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setCreateTime(buildTime(2022, 1, 20)))); + // 准备参数 + AfterSalePageReqVO reqVO = new AfterSalePageReqVO(); + reqVO.setNo("20221119084745002050007"); + reqVO.setStatus(AfterSaleStatusEnum.APPLY.getStatus()); + reqVO.setWay(AfterSaleWayEnum.RETURN_AND_REFUND.getWay()); + reqVO.setType(AfterSaleTypeEnum.IN_SALE.getType()); + reqVO.setOrderNo("20221119084745002050001"); + reqVO.setSpuName("芋"); + reqVO.setCreateTime(new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 1, 16)}); + + // 调用 + PageResult pageResult = tradeAfterSaleService.getAfterSalePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbAfterSale, pageResult.getList().get(0)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java new file mode 100644 index 0000000..7adb03a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.hutool.core.util.NumberUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageRecordMapper; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.math.RoundingMode; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.hutool.core.util.RandomUtil.randomInt; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO @芋艿:单测后续看看 +/** + * {@link BrokerageRecordServiceImpl} 的单元测试类 + * + * @author owen + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(BrokerageRecordServiceImpl.class) +public class BrokerageRecordServiceImplTest extends BaseDbUnitTest { + + @Resource + private BrokerageRecordServiceImpl brokerageRecordService; + @Resource + private BrokerageRecordMapper brokerageRecordMapper; + + @MockBean + private TradeConfigService tradeConfigService; + @MockBean + private BrokerageUserService brokerageUserService; + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBrokerageRecordPage() { + // mock 数据 + BrokerageRecordDO dbBrokerageRecord = randomPojo(BrokerageRecordDO.class, o -> { // 等会查询到 + o.setUserId(null); + o.setBizType(null); + o.setStatus(null); + o.setCreateTime(null); + }); + brokerageRecordMapper.insert(dbBrokerageRecord); + // 测试 userId 不匹配 + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(null))); + // 测试 bizType 不匹配 + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setBizType(null))); + // 测试 status 不匹配 + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setStatus(null))); + // 测试 createTime 不匹配 + brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setCreateTime(null))); + // 准备参数 + BrokerageRecordPageReqVO reqVO = new BrokerageRecordPageReqVO(); + reqVO.setUserId(null); + reqVO.setBizType(null); + reqVO.setStatus(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = brokerageRecordService.getBrokerageRecordPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBrokerageRecord, pageResult.getList().get(0)); + } + + @Test + public void testCalculatePrice_useFixedPrice() { + // mock 数据 + Integer payPrice = randomInteger(); + Integer percent = randomInt(1, 101); + Integer fixedPrice = randomInt(); + // 调用 + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); + // 断言 + assertEquals(brokerage, fixedPrice); + } + + @Test + public void testCalculatePrice_usePercent() { + // mock 数据 + Integer payPrice = randomInteger(); + Integer percent = randomInt(1, 101); + Integer fixedPrice = randomEle(new Integer[]{0, null}); + System.out.println("fixedPrice=" + fixedPrice); + // 调用 + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); + // 断言 + assertEquals(brokerage, NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue()); + } + + @Test + public void testCalculatePrice_equalsZero() { + // mock 数据 + Integer payPrice = null; + Integer percent = null; + Integer fixedPrice = null; + // 调用 + int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice); + // 断言 + assertEquals(brokerage, 0); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImplTest.java new file mode 100644 index 0000000..f29722a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImplTest.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.BrokerageUserPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO @芋艿:单测后续看看 +/** + * {@link BrokerageUserServiceImpl} 的单元测试类 + * + * @author owen + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(BrokerageUserServiceImpl.class) +public class BrokerageUserServiceImplTest extends BaseDbUnitTest { + + @Resource + private BrokerageUserServiceImpl brokerageUserService; + + @Resource + private BrokerageUserMapper brokerageUserMapper; + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBrokerageUserPage() { + // mock 数据 + BrokerageUserDO dbBrokerageUser = randomPojo(BrokerageUserDO.class, o -> { // 等会查询到 + o.setBindUserId(null); + o.setBrokerageEnabled(null); + o.setCreateTime(null); + }); + brokerageUserMapper.insert(dbBrokerageUser); + // 测试 brokerageUserId 不匹配 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBindUserId(null))); + // 测试 brokerageEnabled 不匹配 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setBrokerageEnabled(null))); + // 测试 createTime 不匹配 + brokerageUserMapper.insert(cloneIgnoreId(dbBrokerageUser, o -> o.setCreateTime(null))); + // 准备参数 + BrokerageUserPageReqVO reqVO = new BrokerageUserPageReqVO(); + reqVO.setBindUserId(null); + reqVO.setBrokerageEnabled(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = brokerageUserService.getBrokerageUserPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBrokerageUser, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImplTest.java new file mode 100644 index 0000000..ca84267 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImplTest.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.trade.service.brokerage; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; +import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageWithdrawMapper; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import javax.validation.Validator; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO 芋艿:后续 review +/** + * {@link BrokerageWithdrawServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(BrokerageWithdrawServiceImpl.class) +public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { + + @Resource + private BrokerageWithdrawServiceImpl brokerageWithdrawService; + + @Resource + private BrokerageWithdrawMapper brokerageWithdrawMapper; + + @MockBean + private BrokerageRecordService brokerageRecordService; + @MockBean + private BrokerageUserService brokerageUserService; + @MockBean + private TradeConfigService tradeConfigService; + + @MockBean + private NotifyMessageSendApi notifyMessageSendApi; + + @Resource + private Validator validator; + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBrokerageWithdrawPage() { + // mock 数据 + BrokerageWithdrawDO dbBrokerageWithdraw = randomPojo(BrokerageWithdrawDO.class, o -> { // 等会查询到 + o.setUserId(null); + o.setType(null); + o.setName(null); + o.setAccountNo(null); + o.setBankName(null); + o.setStatus(null); + o.setCreateTime(null); + }); + brokerageWithdrawMapper.insert(dbBrokerageWithdraw); + // 测试 userId 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setUserId(null))); + // 测试 type 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setType(null))); + // 测试 name 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setName(null))); + // 测试 accountNo 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAccountNo(null))); + // 测试 bankName 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setBankName(null))); + // 测试 status 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setStatus(null))); + // 测试 auditReason 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditReason(null))); + // 测试 auditTime 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAuditTime(null))); + // 测试 remark 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setRemark(null))); + // 测试 createTime 不匹配 + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setCreateTime(null))); + // 准备参数 + BrokerageWithdrawPageReqVO reqVO = new BrokerageWithdrawPageReqVO(); + reqVO.setUserId(null); + reqVO.setType(null); + reqVO.setName(null); + reqVO.setAccountNo(null); + reqVO.setBankName(null); + reqVO.setStatus(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBrokerageWithdraw, pageResult.getList().get(0)); + } + + @Test + public void testCalculateFeePrice() { + Integer withdrawPrice = 100; + // 测试手续费比例未设置 + Integer percent = null; + assertEquals(brokerageWithdrawService.calculateFeePrice(withdrawPrice, percent), 0); + // 测试手续费给为0 + percent = 0; + assertEquals(brokerageWithdrawService.calculateFeePrice(withdrawPrice, percent), 0); + // 测试手续费 + percent = 1; + assertEquals(brokerageWithdrawService.calculateFeePrice(withdrawPrice, percent), 1); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java new file mode 100644 index 0000000..ca535bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java @@ -0,0 +1,337 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.service.cart.CartServiceImpl; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressServiceImpl; +import cn.iocoder.yudao.module.trade.service.message.TradeMessageServiceImpl; +import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler; +import cn.iocoder.yudao.module.trade.service.price.TradePriceServiceImpl; +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeOrderUpdateServiceImpl} 的单元测试类 + * + * @author LeeYan9 + * @since 2022-09-07 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import({TradeOrderUpdateServiceImpl.class, TradeOrderConfig.class, CartServiceImpl.class, TradePriceServiceImpl.class, + DeliveryExpressServiceImpl.class, TradeMessageServiceImpl.class +}) +public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { + + @Resource + private TradeOrderUpdateServiceImpl tradeOrderUpdateService; + + @Resource + private TradeOrderMapper tradeOrderMapper; + @Resource + private TradeOrderItemMapper tradeOrderItemMapper; + + @MockBean + private MemberUserApi memberUserApi; + @MockBean + private ProductSpuApi productSpuApi; + @MockBean + private ProductSkuApi productSkuApi; + @MockBean + private ProductCommentApi productCommentApi; + // @MockBean +// private PriceApi priceApi; + @MockBean + private PayOrderApi payOrderApi; + @MockBean + private MemberAddressApi addressApi; + @MockBean + private CouponApi couponApi; + + @MockBean + private TradeOrderProperties tradeOrderProperties; + @MockBean + private TradeNoRedisDAO tradeNoRedisDAO; + @MockBean + private TradeOrderHandler tradeOrderHandler; + @MockBean + private TradePriceCalculator tradePriceCalculator; + @MockBean + private NotifyMessageSendApi notifyMessageSendApi; + @MockBean + private DeliveryExpressService deliveryExpressService; + + @BeforeEach + public void setUp() { + when(tradeOrderProperties.getAppId()).thenReturn(888L); + when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1)); + when(tradeNoRedisDAO.generate(anyString())).thenReturn(IdUtil.randomUUID()); + } + +// @Test +// public void testCreateTradeOrder_success() { +// // 准备参数 +// Long userId = 100L; +// String userIp = "127.0.0.1"; +//// AppTradeOrderCreateReqVO reqVO = new AppTradeOrderCreateReqVO() +//// .setAddressId(10L).setCouponId(101L).setRemark("我是备注").setFromCart(true) +//// .setItems(Arrays.asList(new AppTradeOrderCreateReqVO.Item().setSkuId(1L).setCount(3), +//// new AppTradeOrderCreateReqVO.Item().setSkuId(2L).setCount(4))); +// AppTradeOrderCreateReqVO reqVO = null; +// // TODO 芋艿:重新高下 +// // mock 方法(商品 SKU 检查) +// ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L) +// .setPrice(50).setStock(100) +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L)))); +// ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L) +// .setPrice(20).setStock(50)) +// .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L))); +// when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02)); +// // mock 方法(商品 SPU 检查) +// ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L) +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()).setName("商品 1")); +// ProductSpuRespDTO spu02 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(21L) +// .setStatus(ProductSpuStatusEnum.ENABLE.getStatus())); +// when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02)); +// // mock 方法(用户收件地址的校验) +// MemberAddressRespDTO addressRespDTO = new MemberAddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") +// .setMobile("15601691300").setAreaId(3306).setDetailAddress("土豆村"); +// when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO); +// // mock 方法(价格计算) +// PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() +// .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50) +// .setDiscountPrice(20).setPayPrice(130).setOrderPartPrice(7).setOrderDividePrice(35); +// PriceCalculateRespDTO.OrderItem priceOrderItem02 = new PriceCalculateRespDTO.OrderItem() +// .setSpuId(21L).setSkuId(2L).setCount(4).setOriginalPrice(80).setOriginalUnitPrice(20) +// .setDiscountPrice(40).setPayPrice(40).setOrderPartPrice(15).setOrderDividePrice(25); +// PriceCalculateRespDTO.Order priceOrder = new PriceCalculateRespDTO.Order() +// .setTotalPrice(230).setDiscountPrice(0).setCouponPrice(30) +// .setPointPrice(10).setDeliveryPrice(20).setPayPrice(80).setCouponId(101L).setCouponPrice(30) +// .setItems(Arrays.asList(priceOrderItem01, priceOrderItem02)); +// when(priceApi.calculatePrice(argThat(priceCalculateReqDTO -> { +// assertEquals(priceCalculateReqDTO.getUserId(), 100L); +// assertEquals(priceCalculateReqDTO.getCouponId(), 101L); +// assertEquals(priceCalculateReqDTO.getItems().get(0).getSkuId(), 1L); +// assertEquals(priceCalculateReqDTO.getItems().get(0).getCount(), 3); +// assertEquals(priceCalculateReqDTO.getItems().get(1).getSkuId(), 2L); +// assertEquals(priceCalculateReqDTO.getItems().get(1).getCount(), 4); +// return true; +// }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder)); +// // mock 方法(创建支付单) +// when(payOrderApi.createOrder(argThat(createReqDTO -> { +// assertEquals(createReqDTO.getAppId(), 888L); +// assertEquals(createReqDTO.getUserIp(), userIp); +// assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空 +// assertEquals(createReqDTO.getSubject(), "商品 1 等多件"); +// assertNull(createReqDTO.getBody()); +// assertEquals(createReqDTO.getPrice(), 80); +// assertNotNull(createReqDTO.getExpireTime()); +// return true; +// }))).thenReturn(1000L); +// +// // 调用方法 +// TradeOrderDO order = tradeOrderUpdateService.createOrder(userId, userIp, reqVO, null); +// // 断言 TradeOrderDO 订单 +// List tradeOrderDOs = tradeOrderMapper.selectList(); +// assertEquals(tradeOrderDOs.size(), 1); +// TradeOrderDO tradeOrderDO = tradeOrderDOs.get(0); +// assertEquals(tradeOrderDO.getId(), order.getId()); +// assertNotNull(tradeOrderDO.getNo()); +// assertEquals(tradeOrderDO.getType(), TradeOrderTypeEnum.NORMAL.getType()); +// assertEquals(tradeOrderDO.getTerminal(), TerminalEnum.H5.getTerminal()); +// assertEquals(tradeOrderDO.getUserId(), userId); +// assertEquals(tradeOrderDO.getUserIp(), userIp); +// assertEquals(tradeOrderDO.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus()); +// assertEquals(tradeOrderDO.getProductCount(), 7); +// assertNull(tradeOrderDO.getFinishTime()); +// assertNull(tradeOrderDO.getCancelTime()); +// assertNull(tradeOrderDO.getCancelType()); +// assertEquals(tradeOrderDO.getUserRemark(), "我是备注"); +// assertNull(tradeOrderDO.getRemark()); +// assertFalse(tradeOrderDO.getPayStatus()); +// assertNull(tradeOrderDO.getPayTime()); +// assertEquals(tradeOrderDO.getTotalPrice(), 230); +// assertEquals(tradeOrderDO.getDiscountPrice(), 0); +// assertEquals(tradeOrderDO.getAdjustPrice(), 0); +// assertEquals(tradeOrderDO.getPayPrice(), 80); +// assertEquals(tradeOrderDO.getPayOrderId(), 1000L); +// assertNull(tradeOrderDO.getPayChannelCode()); +// assertNull(tradeOrderDO.getLogisticsId()); +// assertNull(tradeOrderDO.getDeliveryTime()); +// assertNull(tradeOrderDO.getReceiveTime()); +// assertEquals(tradeOrderDO.getReceiverName(), "芋艿"); +// assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300"); +// assertEquals(tradeOrderDO.getReceiverAreaId(), 3306); +// assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村"); +// assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus()); +// assertEquals(tradeOrderDO.getRefundPrice(), 0); +// assertEquals(tradeOrderDO.getCouponPrice(), 30); +// assertEquals(tradeOrderDO.getPointPrice(), 10); +// // 断言 TradeOrderItemDO 订单(第 1 个) +// List tradeOrderItemDOs = tradeOrderItemMapper.selectList(); +// assertEquals(tradeOrderItemDOs.size(), 2); +// TradeOrderItemDO tradeOrderItemDO01 = tradeOrderItemDOs.get(0); +// assertNotNull(tradeOrderItemDO01.getId()); +// assertEquals(tradeOrderItemDO01.getUserId(), userId); +// assertEquals(tradeOrderItemDO01.getOrderId(), order.getId()); +// assertEquals(tradeOrderItemDO01.getSpuId(), 11L); +// assertEquals(tradeOrderItemDO01.getSkuId(), 1L); +// assertEquals(tradeOrderItemDO01.getProperties().size(), 1); +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getPropertyId(), 111L); +// assertEquals(tradeOrderItemDO01.getProperties().get(0).getValueId(), 222L); +// //assertEquals(tradeOrderItemDO01.getSpuName(), sku01.getSpuName()); TODO 找不到spuName +// assertEquals(tradeOrderItemDO01.getPicUrl(), sku01.getPicUrl()); +// assertEquals(tradeOrderItemDO01.getCount(), 3); +//// assertEquals(tradeOrderItemDO01.getOriginalPrice(), 150); +// assertEquals(tradeOrderItemDO01.getPrice(), 50); +// assertEquals(tradeOrderItemDO01.getDiscountPrice(), 20); +// assertEquals(tradeOrderItemDO01.getPayPrice(), 130); +// assertEquals(tradeOrderItemDO01.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); +// // 断言 TradeOrderItemDO 订单(第 2 个) +// TradeOrderItemDO tradeOrderItemDO02 = tradeOrderItemDOs.get(1); +// assertNotNull(tradeOrderItemDO02.getId()); +// assertEquals(tradeOrderItemDO02.getUserId(), userId); +// assertEquals(tradeOrderItemDO02.getOrderId(), order.getId()); +// assertEquals(tradeOrderItemDO02.getSpuId(), 21L); +// assertEquals(tradeOrderItemDO02.getSkuId(), 2L); +// assertEquals(tradeOrderItemDO02.getProperties().size(), 1); +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getPropertyId(), 333L); +// assertEquals(tradeOrderItemDO02.getProperties().get(0).getValueId(), 444L); +// //assertEquals(tradeOrderItemDO02.getSpuName(), sku02.getSpuName()); TODO 找不到spuName +// assertEquals(tradeOrderItemDO02.getPicUrl(), sku02.getPicUrl()); +// assertEquals(tradeOrderItemDO02.getCount(), 4); +//// assertEquals(tradeOrderItemDO02.getOriginalPrice(), 80); +// assertEquals(tradeOrderItemDO02.getPrice(), 20); +// assertEquals(tradeOrderItemDO02.getDiscountPrice(), 40); +// assertEquals(tradeOrderItemDO02.getPayPrice(), 40); +// assertEquals(tradeOrderItemDO02.getAfterSaleStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); +// // 校验调用 +// verify(productSkuApi).updateSkuStock(argThat(updateStockReqDTO -> { +// assertEquals(updateStockReqDTO.getItems().size(), 2); +// assertEquals(updateStockReqDTO.getItems().get(0).getId(), 1L); +// assertEquals(updateStockReqDTO.getItems().get(0).getIncrCount(), 3); +// assertEquals(updateStockReqDTO.getItems().get(1).getId(), 2L); +// assertEquals(updateStockReqDTO.getItems().get(1).getIncrCount(), 4); +// return true; +// })); +// verify(couponApi).useCoupon(argThat(reqDTO -> { +// assertEquals(reqDTO.getId(), reqVO.getCouponId()); +// assertEquals(reqDTO.getUserId(), userId); +// assertEquals(reqDTO.getOrderId(), order.getId()); +// return true; +// })); +// } + + @Test + public void testUpdateOrderPaid() { + // mock 数据(TradeOrder) + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> { + o.setId(1L).setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); + o.setPayOrderId(10L).setPayStatus(false).setPayPrice(100).setPayTime(null); + }); + tradeOrderMapper.insert(order); + // 准备参数 + Long id = 1L; + Long payOrderId = 10L; + // mock 方法(支付单) + when(payOrderApi.getOrder(eq(10L))).thenReturn(randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()).setChannelCode("wx_pub") + .setMerchantOrderId("1")).setPrice(100)); + + // 调用 + tradeOrderUpdateService.updateOrderPaid(id, payOrderId); + // 断言 + TradeOrderDO dbOrder = tradeOrderMapper.selectById(id); + assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus()); + assertTrue(dbOrder.getPayStatus()); + assertNotNull(dbOrder.getPayTime()); + assertEquals(dbOrder.getPayChannelCode(), "wx_pub"); + } + + @Test + public void testDeliveryOrder() { + // mock 数据(TradeOrder) + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> { + o.setId(1L).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()); + o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null); + o.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); + o.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType()); + }); + tradeOrderMapper.insert(order); + + DeliveryExpressCreateReqVO expressCreateReqVO = new DeliveryExpressCreateReqVO(); + expressCreateReqVO.setCode("code").setName("Name").setLogo("logo").setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus()); + Long deliveryExpressId = deliveryExpressService.createDeliveryExpress(expressCreateReqVO); + // 准备参数 + TradeOrderDeliveryReqVO deliveryReqVO = new TradeOrderDeliveryReqVO().setId(1L) + .setLogisticsId(deliveryExpressId).setLogisticsNo("100"); + + // mock 方法(支付单) + + // 调用 + tradeOrderUpdateService.deliveryOrder(deliveryReqVO); + // 断言 + TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L); + assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus()); + assertPojoEquals(dbOrder, deliveryReqVO); + assertNotNull(dbOrder.getDeliveryTime()); + } + + @Test + public void testReceiveOrder() { + // mock 数据(TradeOrder) + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> { + o.setId(1L).setUserId(10L).setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()); + o.setReceiveTime(null); + }); + tradeOrderMapper.insert(order); + // 准备参数 + Long id = 1L; + Long userId = 10L; + // mock 方法(支付单) + + // 调用 + tradeOrderUpdateService.receiveOrderByMember(userId, id); + // 断言 + TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L); + assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus()); + assertNotNull(dbOrder.getReceiveTime()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImplTest.java new file mode 100644 index 0000000..b3900e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImplTest.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.trade.service.price; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +/** + * {@link TradePriceServiceImpl} 的单元测试 + * + * @author 芋道源码 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +public class TradePriceServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradePriceServiceImpl tradePriceService; + + @Mock + private ProductSkuApi productSkuApi; + @Mock + private ProductSpuApi productSpuApi; + @Mock + private List priceCalculators; + + @Test + public void testCalculatePrice() { + // 准备参数 + TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO() + .setUserId(10L) + .setCouponId(20L).setAddressId(30L) + .setItems(Arrays.asList( + new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(200L).setCount(3).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(300L).setCount(6).setCartId(233L).setSelected(false) + )); + // mock 方法 + List skuList = Arrays.asList( + new ProductSkuRespDTO().setId(100L).setStock(500).setPrice(1000).setPicUrl("https://t.cn/1.png").setSpuId(1001L) + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") + .setValueId(2L).setValueName("红色"))), + new ProductSkuRespDTO().setId(200L).setStock(400).setPrice(2000).setPicUrl("https://t.cn/2.png").setSpuId(1001L) + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") + .setValueId(3L).setValueName("黄色"))), + new ProductSkuRespDTO().setId(300L).setStock(600).setPrice(3000).setPicUrl("https://t.cn/3.png").setSpuId(1001L) + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") + .setValueId(4L).setValueName("黑色"))) + ); + when(productSkuApi.getSkuList(Mockito.eq(asSet(100L, 200L, 300L)))).thenReturn(skuList); + when(productSpuApi.getSpuList(Mockito.eq(asSet(1001L)))) + .thenReturn(singletonList(new ProductSpuRespDTO().setId(1001L).setName("小菜").setCategoryId(666L) + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()))); + + // 调用 + TradePriceCalculateRespBO calculateRespBO = tradePriceService.calculatePrice(calculateReqBO); + // 断言 + assertEquals(TradeOrderTypeEnum.NORMAL.getType(), calculateRespBO.getType()); + assertEquals(0, calculateRespBO.getPromotions().size()); + assertNull(calculateRespBO.getCouponId()); + // 断言:订单价格 + assertEquals(7000, calculateRespBO.getPrice().getTotalPrice()); + assertEquals(0, calculateRespBO.getPrice().getDiscountPrice()); + assertEquals(0, calculateRespBO.getPrice().getDeliveryPrice()); + assertEquals(0, calculateRespBO.getPrice().getCouponPrice()); + assertEquals(0, calculateRespBO.getPrice().getPointPrice()); + assertEquals(7000, calculateRespBO.getPrice().getPayPrice()); + // 断言:SKU 1 + assertEquals(1001L, calculateRespBO.getItems().get(0).getSpuId()); + assertEquals(100L, calculateRespBO.getItems().get(0).getSkuId()); + assertEquals(1, calculateRespBO.getItems().get(0).getCount()); + assertNull(calculateRespBO.getItems().get(0).getCartId()); + assertTrue(calculateRespBO.getItems().get(0).getSelected()); + assertEquals(1000, calculateRespBO.getItems().get(0).getPrice()); + assertEquals(0, calculateRespBO.getItems().get(0).getDiscountPrice()); + assertEquals(0, calculateRespBO.getItems().get(0).getDeliveryPrice()); + assertEquals(0, calculateRespBO.getItems().get(0).getCouponPrice()); + assertEquals(0, calculateRespBO.getItems().get(0).getPointPrice()); + assertEquals(1000, calculateRespBO.getItems().get(0).getPayPrice()); + assertEquals("小菜", calculateRespBO.getItems().get(0).getSpuName()); + assertEquals("https://t.cn/1.png", calculateRespBO.getItems().get(0).getPicUrl()); + assertEquals(666L, calculateRespBO.getItems().get(0).getCategoryId()); + assertEquals(skuList.get(0).getProperties(), calculateRespBO.getItems().get(0).getProperties()); + // 断言:SKU 2 + assertEquals(1001L, calculateRespBO.getItems().get(1).getSpuId()); + assertEquals(200L, calculateRespBO.getItems().get(1).getSkuId()); + assertEquals(3, calculateRespBO.getItems().get(1).getCount()); + assertNull(calculateRespBO.getItems().get(1).getCartId()); + assertTrue(calculateRespBO.getItems().get(1).getSelected()); + assertEquals(2000, calculateRespBO.getItems().get(1).getPrice()); + assertEquals(0, calculateRespBO.getItems().get(1).getDiscountPrice()); + assertEquals(0, calculateRespBO.getItems().get(1).getDeliveryPrice()); + assertEquals(0, calculateRespBO.getItems().get(1).getCouponPrice()); + assertEquals(0, calculateRespBO.getItems().get(1).getPointPrice()); + assertEquals(6000, calculateRespBO.getItems().get(1).getPayPrice()); + assertEquals("小菜", calculateRespBO.getItems().get(1).getSpuName()); + assertEquals("https://t.cn/2.png", calculateRespBO.getItems().get(1).getPicUrl()); + assertEquals(666L, calculateRespBO.getItems().get(1).getCategoryId()); + assertEquals(skuList.get(1).getProperties(), calculateRespBO.getItems().get(1).getProperties()); + // 断言:SKU 3 + assertEquals(1001L, calculateRespBO.getItems().get(2).getSpuId()); + assertEquals(300L, calculateRespBO.getItems().get(2).getSkuId()); + assertEquals(6, calculateRespBO.getItems().get(2).getCount()); + assertEquals(233L, calculateRespBO.getItems().get(2).getCartId()); + assertFalse(calculateRespBO.getItems().get(2).getSelected()); + assertEquals(3000, calculateRespBO.getItems().get(2).getPrice()); + assertEquals(0, calculateRespBO.getItems().get(2).getDiscountPrice()); + assertEquals(0, calculateRespBO.getItems().get(2).getDeliveryPrice()); + assertEquals(0, calculateRespBO.getItems().get(2).getCouponPrice()); + assertEquals(0, calculateRespBO.getItems().get(2).getPointPrice()); + assertEquals(18000, calculateRespBO.getItems().get(2).getPayPrice()); + assertEquals("小菜", calculateRespBO.getItems().get(2).getSpuName()); + assertEquals("https://t.cn/3.png", calculateRespBO.getItems().get(2).getPicUrl()); + assertEquals(666L, calculateRespBO.getItems().get(2).getCategoryId()); + assertEquals(skuList.get(2).getProperties(), calculateRespBO.getItems().get(2).getProperties()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java new file mode 100644 index 0000000..06655e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeCouponPriceCalculator} 的单元测试类 + * + * @author 芋道源码 + */ +public class TradeCouponPriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradeCouponPriceCalculator tradeCouponPriceCalculator; + + @Mock + private CouponApi couponApi; + + @Test + public void testCalculate() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L).setCouponId(1024L) + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配优惠劵 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 匹配优惠劵 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true), // 不匹配优惠劵 + new TradePriceCalculateReqBO.Item().setSkuId(40L).setCount(5).setSelected(false) // 匹配优惠劵,但是未选中 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(true) + .setPrice(30).setSpuId(3L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(40L).setCount(5).setSelected(false) + .setPrice(60).setSpuId(1L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(优惠劵 Coupon 信息) + CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节") + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L)) + .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) + .setDiscountPercent(50).setDiscountLimitPrice(70)); + when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon); + + // 调用 + tradeCouponPriceCalculator.calculate(param, result); + // 断言 + assertEquals(result.getCouponId(), 1024L); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 470); + assertEquals(price.getDiscountPrice(), 0); + assertEquals(price.getPointPrice(), 0); + assertEquals(price.getDeliveryPrice(), 0); + assertEquals(price.getCouponPrice(), 70); + assertEquals(price.getPayPrice(), 400); + // 断言:SKU 1 + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getDiscountPrice(), 0); + assertEquals(orderItem01.getDeliveryPrice(), 0); + assertEquals(orderItem01.getCouponPrice(), 40); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getPayPrice(), 160); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getDiscountPrice(), 0); + assertEquals(orderItem02.getDeliveryPrice(), 0); + assertEquals(orderItem02.getCouponPrice(), 30); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getPayPrice(), 120); + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 4); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getDiscountPrice(), 0); + assertEquals(orderItem03.getCouponPrice(), 0); + assertEquals(orderItem03.getPointPrice(), 0); + assertEquals(orderItem03.getPayPrice(), 120); + // 断言:SKU 4 + TradePriceCalculateRespBO.OrderItem orderItem04 = result.getItems().get(3); + assertEquals(orderItem04.getSkuId(), 40L); + assertEquals(orderItem04.getCount(), 5); + assertEquals(orderItem04.getPrice(), 60); + assertEquals(orderItem04.getDiscountPrice(), 0); + assertEquals(orderItem04.getCouponPrice(), 0); + assertEquals(orderItem04.getPointPrice(), 0); + assertEquals(orderItem04.getPayPrice(), 300); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), 1024L); + assertEquals(promotion01.getName(), "程序员节"); + assertEquals(promotion01.getType(), PromotionTypeEnum.COUPON.getType()); + assertEquals(promotion01.getTotalPrice(), 350); + assertEquals(promotion01.getDiscountPrice(), 70); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "优惠劵:省 0.70 元"); + assertEquals(promotion01.getItems().size(), 2); + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); + assertEquals(promotionItem011.getSkuId(), 10L); + assertEquals(promotionItem011.getTotalPrice(), 200); + assertEquals(promotionItem011.getDiscountPrice(), 40); + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); + assertEquals(promotionItem012.getSkuId(), 20L); + assertEquals(promotionItem012.getTotalPrice(), 150); + assertEquals(promotionItem012.getDiscountPrice(), 30); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java new file mode 100644 index 0000000..9441e47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java @@ -0,0 +1,193 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; +import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeDeliveryPriceCalculator} 的单元测试 + * + * @author jason + */ +public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradeDeliveryPriceCalculator calculator; + + @Mock + private MemberAddressApi addressApi; + + @Mock + private DeliveryExpressTemplateService deliveryExpressTemplateService; + @Mock + private TradeConfigService tradeConfigService; + + private TradePriceCalculateReqBO reqBO; + private TradePriceCalculateRespBO resultBO; + + private DeliveryExpressTemplateRespBO templateRespBO; + private DeliveryExpressTemplateRespBO.Charge chargeBO; + private DeliveryExpressTemplateRespBO.Free freeBO; + + @BeforeEach + public void init(){ + // 准备参数 + reqBO = new TradePriceCalculateReqBO() + .setDeliveryType(DeliveryTypeEnum.EXPRESS.getType()) + .setAddressId(10L) + .setUserId(1L) + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(10).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(false) // 未选中 + )); + resultBO = new TradePriceCalculateRespBO() + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(10L).setCount(2).setSelected(true) + .setWeight(10d).setVolume(10d).setPrice(100), + new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(20L).setCount(10).setSelected(true) + .setWeight(10d).setVolume(10d).setPrice(200), + new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(30L).setCount(1).setSelected(false) + .setWeight(10d).setVolume(10d).setPrice(300) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(resultBO.getItems()); + TradePriceCalculatorHelper.recountAllPrice(resultBO); + + // 准备收件地址数据 + MemberAddressRespDTO addressResp = randomPojo(MemberAddressRespDTO.class, item -> item.setAreaId(10)); + when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); + + // 准备运费模板费用配置数据 + chargeBO = randomPojo(DeliveryExpressTemplateRespBO.Charge.class, + item -> item.setStartCount(10D).setStartPrice(1000).setExtraCount(10D).setExtraPrice(2000)); + // 准备运费模板包邮配置数据:订单总件数 < 包邮件数时 12 < 20 + freeBO = randomPojo(DeliveryExpressTemplateRespBO.Free.class, + item -> item.setFreeCount(20).setFreePrice(100)); + // 准备 SP 运费模板数据 + templateRespBO = randomPojo(DeliveryExpressTemplateRespBO.class, + item -> item.setChargeMode(DeliveryExpressChargeModeEnum.COUNT.getType()) + .setCharge(chargeBO).setFree(freeBO)); + } + + @Test + @DisplayName("全场包邮") + public void testCalculate_expressGlobalFree() { + // mock 方法(全场包邮) + when(tradeConfigService.getTradeConfig()).thenReturn(new TradeConfigDO().setDeliveryExpressFreeEnabled(true) + .setDeliveryExpressFreePrice(2200)); + + // 调用 + calculator.calculate(reqBO, resultBO); + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); + assertThat(price) + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") + .containsExactly(2200, 0, 0, 0, 0, 2200); + assertThat(resultBO.getItems()).hasSize(3); + // 断言:SKU1 + assertThat(resultBO.getItems().get(0)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(100, 2, 0, 0, 0, 0, 200); + // 断言:SKU2 + assertThat(resultBO.getItems().get(1)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(200, 10, 0, 0, 0, 0, 2000); + // 断言:SKU3 未选中 + assertThat(resultBO.getItems().get(2)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(300, 1, 0, 0, 0, 0, 300); + } + + @Test + @DisplayName("按件计算运费不包邮的情况") + public void testCalculate_expressTemplateCharge() { + // SKU 1 : 100 * 2 = 200 + // SKU 2 :200 * 10 = 2000 + // 运费 首件 1000 + 续件 2000 = 3000 + // mock 方法 + when(deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(eq(asSet(1L)), eq(10))) + .thenReturn(MapUtil.of(1L, templateRespBO)); + + // 调用 + calculator.calculate(reqBO, resultBO); + // 断言 + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); + assertThat(price) + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") + .containsExactly(2200, 0, 0, 0, 3000, 5200); + assertThat(resultBO.getItems()).hasSize(3); + // 断言:SKU1 + assertThat(resultBO.getItems().get(0)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(100, 2, 0, 0, 0, 500, 700); + // 断言:SKU2 + assertThat(resultBO.getItems().get(1)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(200, 10, 0, 0, 0, 2500, 4500); + // 断言:SKU3 未选中 + assertThat(resultBO.getItems().get(2)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(300, 1, 0, 0, 0, 0, 300); + } + + @Test + @DisplayName("按件计算运费包邮的情况") + public void testCalculate_expressTemplateFree() { + // SKU 1 : 100 * 2 = 200 + // SKU 2 :200 * 10 = 2000 + // 运费 0 + // mock 方法 + // 准备运费模板包邮配置数据 包邮 订单总件数 > 包邮件数时 12 > 10 + templateRespBO.setFree(randomPojo(DeliveryExpressTemplateRespBO.Free.class, + item -> item.setFreeCount(10).setFreePrice(1000))); + when(deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(eq(asSet(1L)), eq(10))) + .thenReturn(MapUtil.of(1L, templateRespBO)); + + // 调用 + calculator.calculate(reqBO, resultBO); + // 断言 + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); + assertThat(price) + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") + .containsExactly(2200, 0, 0, 0, 0, 2200); + assertThat(resultBO.getItems()).hasSize(3); + // 断言:SKU1 + assertThat(resultBO.getItems().get(0)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(100, 2, 0, 0, 0, 0, 200); + // 断言:SKU2 + assertThat(resultBO.getItems().get(1)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(200, 10, 0, 0, 0, 0, 2000); + // 断言:SKU3 未选中 + assertThat(resultBO.getItems().get(2)) + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") + .containsExactly(300, 1, 0, 0, 0, 0, 300); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculatorTest.java new file mode 100644 index 0000000..2176021 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculatorTest.java @@ -0,0 +1,120 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeDiscountActivityPriceCalculator} 的单元测试类 + * + * @author 芋道源码 + */ +public class TradeDiscountActivityPriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradeDiscountActivityPriceCalculator tradeDiscountActivityPriceCalculator; + + @Mock + private DiscountActivityApi discountActivityApi; + + @Test + public void testCalculate() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动,且已选中 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(false) // 匹配活动,但未选中 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(false) + .setPrice(50) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(限时折扣活动) + when(discountActivityApi.getMatchDiscountProductList(eq(asSet(10L, 20L)))).thenReturn(asList( + randomPojo(DiscountProductRespDTO.class, o -> o.setActivityId(1000L) + .setActivityName("活动 1000 号").setSkuId(10L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40)), + randomPojo(DiscountProductRespDTO.class, o -> o.setActivityId(2000L) + .setActivityName("活动 2000 号").setSkuId(20L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60)) + )); + // 10L: 100 * 2 - 40 * 2 = 120 + // 20L:50 * 3 - 50 * 3 * 0.4 = 90 + + // 调用 + tradeDiscountActivityPriceCalculator.calculate(param, result); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 200); + assertEquals(price.getDiscountPrice(), 80); + assertEquals(price.getPointPrice(), 0); + assertEquals(price.getDeliveryPrice(), 0); + assertEquals(price.getCouponPrice(), 0); + assertEquals(price.getPayPrice(), 120); + assertNull(result.getCouponId()); + // 断言:SKU 1 + assertEquals(result.getItems().size(), 2); + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getDiscountPrice(), 80); + assertEquals(orderItem01.getDeliveryPrice(), 0); + assertEquals(orderItem01.getCouponPrice(), 0); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getPayPrice(), 120); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getDiscountPrice(), 60); + assertEquals(orderItem02.getDeliveryPrice(), 0); + assertEquals(orderItem02.getCouponPrice(), 0); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getPayPrice(), 90); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), 1000L); + assertEquals(promotion01.getName(), "活动 1000 号"); + assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); + assertEquals(promotion01.getTotalPrice(), 200); + assertEquals(promotion01.getDiscountPrice(), 80); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "限时折扣:省 0.80 元"); + TradePriceCalculateRespBO.PromotionItem promotionItem01 = promotion01.getItems().get(0); + assertEquals(promotion01.getItems().size(), 1); + assertEquals(promotionItem01.getSkuId(), 10L); + assertEquals(promotionItem01.getTotalPrice(), 200); + assertEquals(promotionItem01.getDiscountPrice(), 80); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculatorTest.java new file mode 100644 index 0000000..44e7831 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculatorTest.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeMemberLevelPriceCalculator} 的单元测试类 + * + * @author 芋道源码 + */ +public class TradeMemberLevelPriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradeMemberLevelPriceCalculator memberLevelPriceCalculator; + + @Mock + private MemberLevelApi memberLevelApi; + @Mock + private MemberUserApi memberUserApi; + + @Test + public void testCalculate() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(1024L) + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动,且已选中 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(false) // 匹配活动,但未选中 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(false) + .setPrice(50) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(会员等级) + when(memberUserApi.getUser(eq(1024L))).thenReturn(new MemberUserRespDTO().setLevelId(2048L)); + when(memberLevelApi.getMemberLevel(eq(2048L))).thenReturn( + new MemberLevelRespDTO().setId(2048L).setName("VIP 会员").setDiscountPercent(60)); + + // 调用 + memberLevelPriceCalculator.calculate(param, result); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 200); + assertEquals(price.getDiscountPrice(), 0); + assertEquals(price.getPointPrice(), 0); + assertEquals(price.getDeliveryPrice(), 0); + assertEquals(price.getCouponPrice(), 0); + assertEquals(price.getVipPrice(), 80); + assertEquals(price.getPayPrice(), 120); + assertNull(result.getCouponId()); + // 断言:SKU 1 + assertEquals(result.getItems().size(), 2); + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getDiscountPrice(), 0); + assertEquals(orderItem01.getDeliveryPrice(), 0); + assertEquals(orderItem01.getCouponPrice(), 0); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getVipPrice(), 80); + assertEquals(orderItem01.getPayPrice(), 120); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getDiscountPrice(), 0); + assertEquals(orderItem02.getDeliveryPrice(), 0); + assertEquals(orderItem02.getCouponPrice(), 0); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getVipPrice(), 60); + assertEquals(orderItem02.getPayPrice(), 90); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), 2048L); + assertEquals(promotion01.getName(), "VIP 会员"); + assertEquals(promotion01.getType(), PromotionTypeEnum.MEMBER_LEVEL.getType()); + assertEquals(promotion01.getTotalPrice(), 200); + assertEquals(promotion01.getDiscountPrice(), 80); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "会员等级折扣:省 0.80 元"); + TradePriceCalculateRespBO.PromotionItem promotionItem01 = promotion01.getItems().get(0); + assertEquals(promotion01.getItems().size(), 1); + assertEquals(promotionItem01.getSkuId(), 10L); + assertEquals(promotionItem01.getTotalPrice(), 200); + assertEquals(promotionItem01.getDiscountPrice(), 80); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculatorTest.java new file mode 100644 index 0000000..910639e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculatorTest.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +// TODO 芋艿:晚点 review +/** + * {@link TradePointGiveCalculator} 的单元测试类 + * + * @author owen + */ +public class TradePointGiveCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradePointGiveCalculator tradePointGiveCalculator; + + @Mock + private MemberConfigApi memberConfigApi; + + @Test + public void testCalculate() { + + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L) + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 全局积分 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 全局积分 + SKU 积分 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(false), // 全局积分,但是未选中 + new TradePriceCalculateReqBO.Item().setSkuId(40L).setCount(5).setSelected(false) // 全局积分 + SKU 积分,但是未选中 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L).setGivePoint(0), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L).setGivePoint(100), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(false) + .setPrice(30).setSpuId(3L).setGivePoint(0), + new TradePriceCalculateRespBO.OrderItem().setSkuId(40L).setCount(5).setSelected(false) + .setPrice(60).setSpuId(1L).setGivePoint(100) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(积分配置 信息) + MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class, + o -> o.setPointTradeDeductEnable(true) // 启用积分折扣 + .setPointTradeGivePoint(100)); // 1 元赠送多少分 + when(memberConfigApi.getConfig()).thenReturn(memberConfig); + + // 调用 + tradePointGiveCalculator.calculate(param, result); + // 断言:Price 部分 + assertEquals(result.getGivePoint(), 2 * 100 + 3 * 50 + 100); + // 断言:SKU 1 + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getGivePoint(), 2 * 100); // 全局积分 + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getGivePoint(), 3 * 50 + 100); // 全局积分 + SKU 积分 + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 4); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getGivePoint(), 0); // 全局积分,但是未选中 + // 断言:SKU 4 + TradePriceCalculateRespBO.OrderItem orderItem04 = result.getItems().get(3); + assertEquals(orderItem04.getSkuId(), 40L); + assertEquals(orderItem04.getCount(), 5); + assertEquals(orderItem04.getPrice(), 60); + assertEquals(orderItem04.getGivePoint(), 100); // 全局积分 + SKU 积分,但是未选中 + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculatorTest.java new file mode 100644 index 0000000..fe679b4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculatorTest.java @@ -0,0 +1,333 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.member.api.config.MemberConfigApi; +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +// TODO 芋艿:晚点 review +/** + * {@link TradePointUsePriceCalculator } 的单元测试类 + * + * @author owen + */ +public class TradePointUsePriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradePointUsePriceCalculator tradePointUsePriceCalculator; + + @Mock + private MemberConfigApi memberConfigApi; + @Mock + private MemberUserApi memberUserApi; + + @Test + public void testCalculate_success() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L).setPointStatus(true) // 是否使用积分 + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false) + .setPrice(30).setSpuId(3L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(积分配置 信息) + MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class, + o -> o.setPointTradeDeductEnable(true) // 启用积分折扣 + .setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分) + .setPointTradeDeductMaxPrice(100)); // 积分抵扣最大值 + when(memberConfigApi.getConfig()).thenReturn(memberConfig); + // mock 方法(会员 信息) + MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(100)); + when(memberUserApi.getUser(user.getId())).thenReturn(user); + + // 调用 + tradePointUsePriceCalculator.calculate(param, result); + // 断言:使用了多少积分 + assertEquals(result.getUsePoint(), 100); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 350); + assertEquals(price.getPayPrice(), 250); + assertEquals(price.getPointPrice(), 100); + // 断言:SKU 1 + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getPointPrice(), 57); + assertEquals(orderItem01.getPayPrice(), 143); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getPointPrice(), 43); + assertEquals(orderItem02.getPayPrice(), 107); + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 5); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getPointPrice(), 0); + assertEquals(orderItem03.getPayPrice(), 150); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), user.getId()); + assertEquals(promotion01.getName(), "积分抵扣"); + assertEquals(promotion01.getType(), PromotionTypeEnum.POINT.getType()); + assertEquals(promotion01.getTotalPrice(), 350); + assertEquals(promotion01.getDiscountPrice(), 100); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "积分抵扣:省 1.00 元"); + assertEquals(promotion01.getItems().size(), 2); + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); + assertEquals(promotionItem011.getSkuId(), 10L); + assertEquals(promotionItem011.getTotalPrice(), 200); + assertEquals(promotionItem011.getDiscountPrice(), 57); + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); + assertEquals(promotionItem012.getSkuId(), 20L); + assertEquals(promotionItem012.getTotalPrice(), 150); + assertEquals(promotionItem012.getDiscountPrice(), 43); + } + + /** + * 当用户积分充足时,抵扣的金额为:配置表的“积分抵扣最大值” + */ + @Test + public void testCalculate_TradeDeductMaxPrice() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L).setPointStatus(true) // 是否使用积分 + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false) + .setPrice(30).setSpuId(3L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(积分配置 信息) + MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class, + o -> o.setPointTradeDeductEnable(true) // 启用积分折扣 + .setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分) + .setPointTradeDeductMaxPrice(50)); // 积分抵扣最大值 + when(memberConfigApi.getConfig()).thenReturn(memberConfig); + // mock 方法(会员 信息) + MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(100)); + when(memberUserApi.getUser(user.getId())).thenReturn(user); + + // 调用 + tradePointUsePriceCalculator.calculate(param, result); + // 断言:使用了多少积分 + assertEquals(result.getUsePoint(), 50); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 350); + assertEquals(price.getPayPrice(), 300); + assertEquals(price.getPointPrice(), 50); + // 断言:SKU 1 + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getPointPrice(), 28); + assertEquals(orderItem01.getPayPrice(), 172); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getPointPrice(), 22); + assertEquals(orderItem02.getPayPrice(), 128); + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 5); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getPointPrice(), 0); + assertEquals(orderItem03.getPayPrice(), 150); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), user.getId()); + assertEquals(promotion01.getName(), "积分抵扣"); + assertEquals(promotion01.getType(), PromotionTypeEnum.POINT.getType()); + assertEquals(promotion01.getTotalPrice(), 350); + assertEquals(promotion01.getDiscountPrice(), 50); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "积分抵扣:省 0.50 元"); + assertEquals(promotion01.getItems().size(), 2); + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); + assertEquals(promotionItem011.getSkuId(), 10L); + assertEquals(promotionItem011.getTotalPrice(), 200); + assertEquals(promotionItem011.getDiscountPrice(), 28); + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); + assertEquals(promotionItem012.getSkuId(), 20L); + assertEquals(promotionItem012.getTotalPrice(), 150); + assertEquals(promotionItem012.getDiscountPrice(), 22); + } + + /** + * 订单不使用积分,不会产生优惠 + */ + @Test + public void testCalculate_PointStatusFalse() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L).setPointStatus(false) // 是否使用积分 + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false) + .setPrice(30).setSpuId(3L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // 调用 + tradePointUsePriceCalculator.calculate(param, result); + // 断言:没有使用积分 + assertNotUsePoint(result); + } + + /** + * 会员积分不足,不会产生优惠 + */ + @Test + public void testCalculate_UserPointNotEnough() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setUserId(233L).setPointStatus(true) // 是否使用积分 + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 使用积分 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(5).setSelected(false) // 未选中,不使用积分 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(5).setSelected(false) + .setPrice(30).setSpuId(3L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(积分配置 信息) + MemberConfigRespDTO memberConfig = randomPojo(MemberConfigRespDTO.class, + o -> o.setPointTradeDeductEnable(true) // 启用积分折扣 + .setPointTradeDeductUnitPrice(1) // 1 积分抵扣多少金额(单位分) + .setPointTradeDeductMaxPrice(100)); // 积分抵扣最大值 + when(memberConfigApi.getConfig()).thenReturn(memberConfig); + // mock 方法(会员 信息) + MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(param.getUserId()).setPoint(0)); + when(memberUserApi.getUser(user.getId())).thenReturn(user); + + // 调用 + tradePointUsePriceCalculator.calculate(param, result); + + // 断言:没有使用积分 + assertNotUsePoint(result); + } + + /** + * 断言:没有使用积分 + */ + private static void assertNotUsePoint(TradePriceCalculateRespBO result) { + // 断言:使用了多少积分 + assertEquals(result.getUsePoint(), 0); + // 断言:Price 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 350); + assertEquals(price.getPayPrice(), 350); + assertEquals(price.getPointPrice(), 0); + // 断言:SKU 1 + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getPayPrice(), 200); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getPayPrice(), 150); + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 5); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getPointPrice(), 0); + assertEquals(orderItem03.getPayPrice(), 150); + // 断言:Promotion 部分 + assertEquals(result.getPromotions().size(), 0); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java new file mode 100644 index 0000000..de72ed6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java @@ -0,0 +1,235 @@ +package cn.iocoder.yudao.module.trade.service.price.calculator; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.ArrayList; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link TradeRewardActivityPriceCalculator} 的单元测试类 + * + * @author 芋道源码 + */ +public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest { + + @InjectMocks + private TradeRewardActivityPriceCalculator tradeRewardActivityPriceCalculator; + + @Mock + private RewardActivityApi rewardActivityApi; + + @Test + public void testCalculate_match() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动 1 + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 匹配活动 1 + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true) // 匹配活动 2 + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(true) + .setPrice(30).setSpuId(3L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(限时折扣 DiscountActivity 信息) + when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList( + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") + .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) + .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(200).setDiscountPrice(70)))), + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号") + .setSpuIds(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) + .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10), + new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个 + new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)))) + )); + + // 调用 + tradeRewardActivityPriceCalculator.calculate(param, result); + // 断言 Order 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 470); + assertEquals(price.getDiscountPrice(), 130); + assertEquals(price.getPointPrice(), 0); + assertEquals(price.getDeliveryPrice(), 0); + assertEquals(price.getCouponPrice(), 0); + assertEquals(price.getPayPrice(), 340); + assertNull(result.getCouponId()); + // 断言:SKU 1 + assertEquals(result.getItems().size(), 3); + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getDiscountPrice(), 40); + assertEquals(orderItem01.getDeliveryPrice(), 0); + assertEquals(orderItem01.getCouponPrice(), 0); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getPayPrice(), 160); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getDiscountPrice(), 30); + assertEquals(orderItem02.getDeliveryPrice(), 0); + assertEquals(orderItem02.getCouponPrice(), 0); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getPayPrice(), 120); + // 断言:SKU 3 + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); + assertEquals(orderItem03.getSkuId(), 30L); + assertEquals(orderItem03.getCount(), 4); + assertEquals(orderItem03.getPrice(), 30); + assertEquals(orderItem03.getDiscountPrice(), 60); + assertEquals(orderItem03.getDeliveryPrice(), 0); + assertEquals(orderItem03.getCouponPrice(), 0); + assertEquals(orderItem03.getPointPrice(), 0); + assertEquals(orderItem03.getPayPrice(), 60); + // 断言:Promotion 部分(第一个) + assertEquals(result.getPromotions().size(), 2); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), 1000L); + assertEquals(promotion01.getName(), "活动 1000 号"); + assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); + assertEquals(promotion01.getTotalPrice(), 350); + assertEquals(promotion01.getDiscountPrice(), 70); + assertTrue(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "满减送:省 0.70 元"); + assertEquals(promotion01.getItems().size(), 2); + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); + assertEquals(promotionItem011.getSkuId(), 10L); + assertEquals(promotionItem011.getTotalPrice(), 200); + assertEquals(promotionItem011.getDiscountPrice(), 40); + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); + assertEquals(promotionItem012.getSkuId(), 20L); + assertEquals(promotionItem012.getTotalPrice(), 150); + assertEquals(promotionItem012.getDiscountPrice(), 30); + // 断言:Promotion 部分(第二个) + TradePriceCalculateRespBO.Promotion promotion02 = result.getPromotions().get(1); + assertEquals(promotion02.getId(), 2000L); + assertEquals(promotion02.getName(), "活动 2000 号"); + assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); + assertEquals(promotion02.getTotalPrice(), 120); + assertEquals(promotion02.getDiscountPrice(), 60); + assertTrue(promotion02.getMatch()); + assertEquals(promotion02.getDescription(), "满减送:省 0.60 元"); + TradePriceCalculateRespBO.PromotionItem promotionItem02 = promotion02.getItems().get(0); + assertEquals(promotion02.getItems().size(), 1); + assertEquals(promotionItem02.getSkuId(), 30L); + assertEquals(promotionItem02.getTotalPrice(), 120); + assertEquals(promotionItem02.getDiscountPrice(), 60); + } + + @Test + public void testCalculate_notMatch() { + // 准备参数 + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() + .setItems(asList( + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true) + )); + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() + .setType(TradeOrderTypeEnum.NORMAL.getType()) + .setPrice(new TradePriceCalculateRespBO.Price()) + .setPromotions(new ArrayList<>()) + .setItems(asList( + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) + .setPrice(100).setSpuId(1L), + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) + .setPrice(50).setSpuId(2L) + )); + // 保证价格被初始化上 + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); + TradePriceCalculatorHelper.recountAllPrice(result); + + // mock 方法(限时折扣 DiscountActivity 信息) + when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L)))).thenReturn(singletonList( + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") + .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) + .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(351).setDiscountPrice(70)))) + )); + + // 调用 + tradeRewardActivityPriceCalculator.calculate(param, result); + // 断言 Order 部分 + TradePriceCalculateRespBO.Price price = result.getPrice(); + assertEquals(price.getTotalPrice(), 350); + assertEquals(price.getDiscountPrice(), 0); + assertEquals(price.getPointPrice(), 0); + assertEquals(price.getDeliveryPrice(), 0); + assertEquals(price.getCouponPrice(), 0); + assertEquals(price.getPayPrice(), 350); + assertNull(result.getCouponId()); + // 断言:SKU 1 + assertEquals(result.getItems().size(), 2); + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); + assertEquals(orderItem01.getSkuId(), 10L); + assertEquals(orderItem01.getCount(), 2); + assertEquals(orderItem01.getPrice(), 100); + assertEquals(orderItem01.getDiscountPrice(), 0); + assertEquals(orderItem01.getDeliveryPrice(), 0); + assertEquals(orderItem01.getCouponPrice(), 0); + assertEquals(orderItem01.getPointPrice(), 0); + assertEquals(orderItem01.getPayPrice(), 200); + // 断言:SKU 2 + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); + assertEquals(orderItem02.getSkuId(), 20L); + assertEquals(orderItem02.getCount(), 3); + assertEquals(orderItem02.getPrice(), 50); + assertEquals(orderItem02.getDiscountPrice(), 0); + assertEquals(orderItem02.getDeliveryPrice(), 0); + assertEquals(orderItem02.getCouponPrice(), 0); + assertEquals(orderItem02.getPointPrice(), 0); + assertEquals(orderItem02.getPayPrice(), 150); + // 断言 Promotion 部分 + assertEquals(result.getPromotions().size(), 1); + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); + assertEquals(promotion01.getId(), 1000L); + assertEquals(promotion01.getName(), "活动 1000 号"); + assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); + assertEquals(promotion01.getTotalPrice(), 350); + assertEquals(promotion01.getDiscountPrice(), 0); + assertFalse(promotion01.getMatch()); + assertEquals(promotion01.getDescription(), "TODO"); // TODO 芋艿:后面再想想 + assertEquals(promotion01.getItems().size(), 2); + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); + assertEquals(promotionItem011.getSkuId(), 10L); + assertEquals(promotionItem011.getTotalPrice(), 200); + assertEquals(promotionItem011.getDiscountPrice(), 0); + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); + assertEquals(promotionItem012.getSkuId(), 20L); + assertEquals(promotionItem012.getTotalPrice(), 150); + assertEquals(promotionItem012.getDiscountPrice(), 0); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..8ba2503 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,59 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module + trade: + order: + app-id: 1 + merchant-order-id: 1 + express: + kd-niao: + api-key: xxxx + business-id: xxxxx + kd100: + customer: xxxxx + key: xxxxx + client: not_provide \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..f7f3477 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,7 @@ +DELETE FROM trade_order; +DELETE FROM trade_order_item; +DELETE FROM trade_after_sale; +DELETE FROM trade_after_sale_log; +DELETE FROM trade_brokerage_user; +DELETE FROM trade_brokerage_record; +DELETE FROM "trade_brokerage_withdraw"; diff --git a/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..f619c01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,234 @@ +CREATE TABLE IF NOT EXISTS "trade_order" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "no" varchar NOT NULL, + "type" int NOT NULL, + "terminal" int NOT NULL, + "user_id" bigint NOT NULL, + "user_ip" varchar NOT NULL, + "user_remark" varchar, + "status" int NOT NULL, + "product_count" int NOT NULL, + "cancel_type" int, + "remark" varchar, + "comment_status" boolean, + "brokerage_user_id" bigint, + "pay_status" bit NOT NULL, + "pay_time" datetime, + "finish_time" datetime, + "cancel_time" datetime, + "total_price" int NULL, + "order_price" int NULL, + "discount_price" int NOT NULL, + "delivery_price" int NOT NULL, + "adjust_price" int NOT NULL, + "pay_price" int NOT NULL, + "delivery_type" int NOT NULL, + "pay_order_id" bigint, + "pay_channel_code" varchar, + "delivery_template_id" bigint, + "logistics_id" bigint, + "logistics_no" varchar, + "delivery_time" datetime, + "receive_time" datetime, + "receiver_name" varchar NOT NULL, + "receiver_mobile" varchar NOT NULL, + "receiver_area_id" int NOT NULL, + "receiver_post_code" int, + "receiver_detail_address" varchar NOT NULL, + "pick_up_store_id" long NULL, + "pick_up_verify_code" varchar NULL, + "refund_status" int NULL, + "refund_price" int NULL, + "after_sale_status" int NULL, + "coupon_id" bigint NOT NULL, + "coupon_price" int NOT NULL, + "use_point" int NULL, + "point_price" int NOT NULL, + "give_point" int NULL, + "refund_point" int NULL, + "vip_price" int NULL, + "seckill_activity_id" long NULL, + "bargain_activity_id" long NULL, + "bargain_record_id" long NULL, + "combination_activity_id" long NULL, + "combination_head_id" long NULL, + "combination_record_id" long NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '交易订单表'; + +CREATE TABLE IF NOT EXISTS "trade_order_item" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "order_id" bigint NOT NULL, + "cart_id" int NULL, + "spu_id" bigint NOT NULL, + "spu_name" varchar NOT NULL, + "sku_id" bigint NOT NULL, + "properties" varchar, + "pic_url" varchar, + "count" int NOT NULL, + "comment_status" boolean NULL, + "price" int NOT NULL, + "discount_price" int NOT NULL, + "delivery_price" int NULL, + "adjust_price" int NULL, + "pay_price" int NOT NULL, + "coupon_price" int NULL, + "point_price" int NULL, + "use_point" int NULL, + "give_point" int NULL, + "vip_price" int NULL, + "after_sale_id" long NULL, + "after_sale_status" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '交易订单明细表'; + +CREATE TABLE IF NOT EXISTS "trade_after_sale" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "no" varchar NOT NULL, + "status" int NOT NULL, + "type" int NOT NULL, + "way" int NOT NULL, + "user_id" bigint NOT NULL, + "apply_reason" varchar NOT NULL, + "apply_description" varchar, + "apply_pic_urls" varchar, + "order_id" bigint NOT NULL, + "order_no" varchar NOT NULL, + "order_item_id" bigint NOT NULL, + "spu_id" bigint NOT NULL, + "spu_name" varchar NOT NULL, + "sku_id" bigint NOT NULL, + "properties" varchar, + "pic_url" varchar, + "count" int NOT NULL, + "audit_time" varchar, + "audit_user_id" bigint, + "audit_reason" varchar, + "refund_price" int NOT NULL, + "pay_refund_id" bigint, + "refund_time" varchar, + "logistics_id" bigint, + "logistics_no" varchar, + "delivery_time" varchar, + "receive_time" varchar, + "receive_reason" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '交易售后表'; + +CREATE TABLE IF NOT EXISTS "trade_after_sale_log" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" int NOT NULL, + "after_sale_id" bigint NOT NULL, + "order_id" bigint NOT NULL, + "order_item_id" bigint NOT NULL, + "before_status" int, + "after_status" int NOT NULL, + "content" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '交易售后日志'; + +CREATE TABLE IF NOT EXISTS "trade_brokerage_user" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "bind_user_id" bigint NOT NULL, + "bind_user_time" varchar, + "brokerage_enabled" bit NOT NULL, + "brokerage_time" varchar, + "price" int NOT NULL, + "frozen_price" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL DEFAULT '0', + PRIMARY KEY ("id") +) COMMENT '分销用户'; +CREATE TABLE IF NOT EXISTS "trade_brokerage_record" +( + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "biz_id" varchar NOT NULL, + "biz_type" varchar NOT NULL, + "title" varchar NOT NULL, + "price" int NOT NULL, + "total_price" int NOT NULL, + "description" varchar NOT NULL, + "status" varchar NOT NULL, + "frozen_days" int NOT NULL, + "unfreeze_time" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '佣金记录'; +CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw" +( + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "price" int NOT NULL, + "fee_price" int NOT NULL, + "total_price" int NOT NULL, + "type" varchar NOT NULL, + "name" varchar, + "account_no" varchar, + "bank_name" varchar, + "bank_address" varchar, + "account_qr_code_url" varchar, + "status" varchar NOT NULL, + "audit_reason" varchar, + "audit_time" varchar, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '佣金提现'; + +CREATE TABLE IF NOT EXISTS "trade_delivery_express" +( + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar NULL, + "name" varchar, + "logo" varchar NULL, + "sort" int NOT NULL, + "status" int NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '佣金提现'; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/pom.xml b/ruoyi-vue-pro-master/yudao-module-member/pom.xml new file mode 100644 index 0000000..ea65199 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/pom.xml @@ -0,0 +1,24 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + + yudao-module-member-api + yudao-module-member-biz + + yudao-module-member + pom + + ${project.artifactId} + + member 模块,我们放会员业务。 + 例如说:会员中心等等 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/pom.xml new file mode 100644 index 0000000..1f60cd0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-member + ${revision} + + 4.0.0 + yudao-module-member-api + jar + + ${project.artifactId} + + member 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApi.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApi.java new file mode 100644 index 0000000..913316f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApi.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.member.api.address; + +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; + +/** + * 用户收件地址 API 接口 + * + * @author 芋道源码 + */ +public interface MemberAddressApi { + + /** + * 获得用户收件地址 + * + * @param id 收件地址编号 + * @param userId 用户编号 + * @return 用户收件地址 + */ + MemberAddressRespDTO getAddress(Long id, Long userId); + + /** + * 获得用户默认收件地址 + * + * @param userId 用户编号 + * @return 用户收件地址 + */ + MemberAddressRespDTO getDefaultAddress(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/MemberAddressRespDTO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/MemberAddressRespDTO.java new file mode 100644 index 0000000..969e868 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/MemberAddressRespDTO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.member.api.address.dto; + +import lombok.Data; + +/** + * 用户收件地址 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MemberAddressRespDTO { + + /** + * 编号 + */ + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 收件人名称 + */ + private String name; + /** + * 手机号 + */ + private String mobile; + /** + * 地区编号 + */ + private Integer areaId; + /** + * 收件详细地址 + */ + private String detailAddress; + /** + * 是否默认 + */ + private Boolean defaultStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApi.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApi.java new file mode 100644 index 0000000..dab7f68 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApi.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.member.api.config; + +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; + +/** + * 用户配置 API 接口 + * + * @author owen + */ +public interface MemberConfigApi { + + /** + * 获得积分配置 + * + * @return 积分配置 + */ + MemberConfigRespDTO getConfig(); +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/dto/MemberConfigRespDTO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/dto/MemberConfigRespDTO.java new file mode 100644 index 0000000..59aab53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/config/dto/MemberConfigRespDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.member.api.config.dto; + +import lombok.Data; + +/** + * 用户信息 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MemberConfigRespDTO { + + /** + * 积分抵扣开关 + */ + private Boolean pointTradeDeductEnable; + /** + * 积分抵扣,单位:分 + *

+ * 1 积分抵扣多少分 + */ + private Integer pointTradeDeductUnitPrice; + /** + * 积分抵扣最大值 + */ + private Integer pointTradeDeductMaxPrice; + /** + * 1 元赠送多少分 + */ + private Integer pointTradeGivePoint; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApi.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApi.java new file mode 100644 index 0000000..5876837 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApi.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.member.api.level; + +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; + +/** + * 会员等级 API 接口 + * + * @author owen + */ +public interface MemberLevelApi { + + /** + * 获得会员等级 + * + * @param id 会员等级编号 + * @return 会员等级 + */ + MemberLevelRespDTO getMemberLevel(Long id); + + /** + * 增加会员经验 + * + * @param userId 会员ID + * @param experience 经验 + * @param bizType 业务类型 {@link MemberExperienceBizTypeEnum} + * @param bizId 业务编号 + */ + void addExperience(Long userId, Integer experience, Integer bizType, String bizId); + + /** + * 扣减会员经验 + * + * @param userId 会员ID + * @param experience 经验 + * @param bizType 业务类型 {@link MemberExperienceBizTypeEnum} + * @param bizId 业务编号 + */ + void reduceExperience(Long userId, Integer experience, Integer bizType, String bizId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/dto/MemberLevelRespDTO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/dto/MemberLevelRespDTO.java new file mode 100644 index 0000000..a72d65f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/level/dto/MemberLevelRespDTO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.member.api.level.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +/** + * 会员等级 Resp DTO + * + * @author 芋道源码 + */ +@Data +public class MemberLevelRespDTO { + + /** + * 编号 + */ + private Long id; + /** + * 等级名称 + */ + private String name; + /** + * 等级 + */ + private Integer level; + /** + * 升级经验 + */ + private Integer experience; + /** + * 享受折扣 + */ + private Integer discountPercent; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java new file mode 100644 index 0000000..56cd985 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java @@ -0,0 +1,4 @@ +/** + * member API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.member.api; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java new file mode 100644 index 0000000..3eb749f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.member.api.point; + +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; + +import javax.validation.constraints.Min; + +/** + * 用户积分的 API 接口 + * + * @author owen + */ +public interface MemberPointApi { + + /** + * 增加用户积分 + * + * @param userId 用户编号 + * @param point 积分 + * @param bizType 业务类型 {@link MemberPointBizTypeEnum} + * @param bizId 业务编号 + */ + void addPoint(Long userId, @Min(value = 1L, message = "积分必须是正数") Integer point, + Integer bizType, String bizId); + + /** + * 减少用户积分 + * + * @param userId 用户编号 + * @param point 积分 + * @param bizType 业务类型 {@link MemberPointBizTypeEnum} + * @param bizId 业务编号 + */ + void reducePoint(Long userId, @Min(value = 1L, message = "积分必须是正数") Integer point, + Integer bizType, String bizId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java new file mode 100644 index 0000000..c9fb801 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.member.api.user; + +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 会员用户的 API 接口 + * + * @author 芋道源码 + */ +public interface MemberUserApi { + + /** + * 获得会员用户信息 + * + * @param id 用户编号 + * @return 用户信息 + */ + MemberUserRespDTO getUser(Long id); + + /** + * 获得会员用户信息们 + * + * @param ids 用户编号的数组 + * @return 用户信息们 + */ + List getUserList(Collection ids); + + /** + * 获得会员用户 Map + * + * @param ids 用户编号的数组 + * @return 会员用户 Map + */ + default Map getUserMap(Collection ids) { + List list = getUserList(ids); + return convertMap(list, MemberUserRespDTO::getId); + } + + /** + * 基于用户昵称,模糊匹配用户列表 + * + * @param nickname 用户昵称,模糊匹配 + * @return 用户信息的列表 + */ + List getUserListByNickname(String nickname); + + /** + * 基于手机号,精准匹配用户 + * + * @param mobile 手机号 + * @return 用户信息 + */ + MemberUserRespDTO getUserByMobile(String mobile); +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java new file mode 100644 index 0000000..50548f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.member.api.user.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户信息 Response DTO + * + * @author 芋道源码 + */ +@Data +public class MemberUserRespDTO { + + /** + * 用户ID + */ + private Long id; + /** + * 用户昵称 + */ + private String nickname; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 用户头像 + */ + private String avatar; + /** + * 手机 + */ + private String mobile; + /** + * 创建时间(注册时间) + */ + private LocalDateTime createTime; + + // ========== 其它信息 ========== + + /** + * 会员级别编号 + */ + private Long levelId; + + /** + * 积分 + */ + private Integer point; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/DictTypeConstants.java new file mode 100644 index 0000000..c87cbb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/DictTypeConstants.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.member.enums; + +/** + * Member 字典类型的枚举类 + * + * @author owen + */ +public interface DictTypeConstants { + + /** + * 会员经验记录 - 业务类型 + */ + String MEMBER_EXPERIENCE_BIZ_TYPE = "member_experience_biz_type"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..ee970a5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.member.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Member 错误码枚举类 + *

+ * member 系统,使用 1-004-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 用户相关 1-004-001-000 ============ + ErrorCode USER_NOT_EXISTS = new ErrorCode(1_004_001_000, "用户不存在"); + ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_004_001_001, "手机号未注册用户"); + ErrorCode USER_MOBILE_USED = new ErrorCode(1_004_001_002, "修改手机失败,该手机号({})已经被使用"); + ErrorCode USER_POINT_NOT_ENOUGH = new ErrorCode(1_004_001_003, "用户积分余额不足"); + + // ========== AUTH 模块 1-004-003-000 ========== + ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确"); + ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_004_003_001, "登录失败,账号被禁用"); + ErrorCode AUTH_SOCIAL_USER_NOT_FOUND = new ErrorCode(1_004_003_005, "登录失败,解析不到三方登录信息"); + ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用"); + + // ========== 用户收件地址 1-004-004-000 ========== + ErrorCode ADDRESS_NOT_EXISTS = new ErrorCode(1_004_004_000, "用户收件地址不存在"); + + //========== 用户标签 1-004-006-000 ========== + ErrorCode TAG_NOT_EXISTS = new ErrorCode(1_004_006_000, "用户标签不存在"); + ErrorCode TAG_NAME_EXISTS = new ErrorCode(1_004_006_001, "用户标签已经存在"); + ErrorCode TAG_HAS_USER = new ErrorCode(1_004_006_002, "用户标签下存在用户,无法删除"); + + //========== 积分配置 1-004-007-000 ========== + + //========== 积分记录 1-004-008-000 ========== + ErrorCode POINT_RECORD_BIZ_NOT_SUPPORT = new ErrorCode(1_004_008_000, "用户积分记录业务类型不支持"); + + //========== 签到配置 1-004-009-000 ========== + ErrorCode SIGN_IN_CONFIG_NOT_EXISTS = new ErrorCode(1_004_009_000, "签到天数规则不存在"); + ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1_004_009_001, "签到天数规则已存在"); + + //========== 签到配置 1-004-010-000 ========== + ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000, "今日已签到,请勿重复签到"); + + //========== 用户等级 1-004-011-000 ========== + ErrorCode LEVEL_NOT_EXISTS = new ErrorCode(1_004_011_000, "用户等级不存在"); + ErrorCode LEVEL_NAME_EXISTS = new ErrorCode(1_004_011_001, "用户等级名称[{}]已被使用"); + ErrorCode LEVEL_VALUE_EXISTS = new ErrorCode(1_004_011_002, "用户等级值[{}]已被[{}]使用"); + ErrorCode LEVEL_EXPERIENCE_MIN = new ErrorCode(1_004_011_003, "升级经验必须大于上一个等级[{}]设置的升级经验[{}]"); + ErrorCode LEVEL_EXPERIENCE_MAX = new ErrorCode(1_004_011_004, "升级经验必须小于下一个等级[{}]设置的升级经验[{}]"); + ErrorCode LEVEL_HAS_USER = new ErrorCode(1_004_011_005, "用户等级下存在用户,无法删除"); + + ErrorCode EXPERIENCE_BIZ_NOT_SUPPORT = new ErrorCode(1_004_011_201, "用户经验业务类型不支持"); + + //========== 用户分组 1-004-012-000 ========== + ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_004_012_000, "用户分组不存在"); + ErrorCode GROUP_HAS_USER = new ErrorCode(1_004_012_001, "用户分组下存在用户,无法删除"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/MemberExperienceBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/MemberExperienceBizTypeEnum.java new file mode 100644 index 0000000..3038dba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/MemberExperienceBizTypeEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.member.enums; + +import cn.hutool.core.util.EnumUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 会员经验 - 业务类型 + * + * @author owen + */ +@Getter +@AllArgsConstructor +public enum MemberExperienceBizTypeEnum { + + /** + * 管理员调整、邀请新用户、下单、退单、签到、抽奖 + */ + ADMIN(0, "管理员调整", "管理员调整获得 {} 经验", true), + INVITE_REGISTER(1, "邀新奖励", "邀请好友获得 {} 经验", true), + SIGN_IN(4, "签到奖励", "签到获得 {} 经验", true), + LOTTERY(5, "抽奖奖励", "抽奖获得 {} 经验", true), + ORDER_GIVE(11, "下单奖励", "下单获得 {} 经验", true), + ORDER_GIVE_CANCEL(12, "下单奖励(整单取消)", "取消订单获得 {} 经验", false), // ORDER_GIVE 的取消 + ORDER_GIVE_CANCEL_ITEM(13, "下单奖励(单个退款)", "退款订单获得 {} 经验", false), // ORDER_GIVE 的取消 + ; + + /** + * 业务类型 + */ + private final int type; + /** + * 标题 + */ + private final String title; + /** + * 描述 + */ + private final String description; + /** + * 是否为扣减积分 + */ + private final boolean add; + + public static MemberExperienceBizTypeEnum getByType(Integer type) { + return EnumUtil.getBy(MemberExperienceBizTypeEnum.class, + e -> Objects.equals(type, e.getType())); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java new file mode 100644 index 0000000..ef491f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.member.enums.point; + +import cn.hutool.core.util.EnumUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 会员积分的业务类型枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum MemberPointBizTypeEnum implements IntArrayValuable { + + SIGN(1, "签到", "签到获得 {} 积分", true), + ADMIN(2, "管理员修改", "管理员修改 {} 积分", true), + + ORDER_USE(11, "订单积分抵扣", "下单使用 {} 积分", false), // 下单时,扣减积分 + ORDER_USE_CANCEL(12, "订单积分抵扣(整单取消)", "订单取消,退还 {} 积分", true), // ORDER_USE 的取消 + ORDER_USE_CANCEL_ITEM(13, "订单积分抵扣(单个退款)", "订单退款,退还 {} 积分", true), // ORDER_USE 的取消 + + ORDER_GIVE(21, "订单积分奖励", "下单获得 {} 积分", true), // 支付订单时,赠送积分 + ORDER_GIVE_CANCEL(22, "订单积分奖励(整单取消)", "订单取消,退还 {} 积分", false), // ORDER_GIVE 的取消 + ORDER_GIVE_CANCEL_ITEM(23, "订单积分奖励(单个退款)", "订单退款,扣除赠送的 {} 积分", false) // ORDER_GIVE 的取消 + ; + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + /** + * 描述 + */ + private final String description; + /** + * 是否为扣减积分 + */ + private final boolean add; + + @Override + public int[] array() { + return new int[0]; + } + + public static MemberPointBizTypeEnum getByType(Integer type) { + return EnumUtil.getBy(MemberPointBizTypeEnum.class, + e -> Objects.equals(type, e.getType())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/package-info.java new file mode 100644 index 0000000..6ae3b64 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package cn.iocoder.yudao.module.member.message; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/user/MemberUserCreateMessage.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/user/MemberUserCreateMessage.java new file mode 100644 index 0000000..cfb24eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/message/user/MemberUserCreateMessage.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.member.message.user; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 会员用户创建消息 + * + * @author owen + */ +@Data +public class MemberUserCreateMessage { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/pom.xml new file mode 100644 index 0000000..3c9b81e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/pom.xml @@ -0,0 +1,91 @@ + + + + cn.iocoder.boot + yudao-module-member + ${revision} + + 4.0.0 + yudao-module-member-biz + jar + + ${project.artifactId} + + member 模块,我们放会员业务。 + 例如说:会员中心等等 + + + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-infra-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-validation + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApiImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApiImpl.java new file mode 100644 index 0000000..c113ca2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/MemberAddressApiImpl.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.member.api.address; + +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; +import cn.iocoder.yudao.module.member.service.address.AddressService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 用户收件地址 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MemberAddressApiImpl implements MemberAddressApi { + + @Resource + private AddressService addressService; + + @Override + public MemberAddressRespDTO getAddress(Long id, Long userId) { + return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); + } + + @Override + public MemberAddressRespDTO getDefaultAddress(Long userId) { + return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApiImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApiImpl.java new file mode 100644 index 0000000..510f4ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/config/MemberConfigApiImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.member.api.config; + +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert; +import cn.iocoder.yudao.module.member.service.config.MemberConfigService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 用户配置 API 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberConfigApiImpl implements MemberConfigApi { + + @Resource + private MemberConfigService memberConfigService; + + @Override + public MemberConfigRespDTO getConfig() { + return MemberConfigConvert.INSTANCE.convert01(memberConfigService.getConfig()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApiImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApiImpl.java new file mode 100644 index 0000000..79fed98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/level/MemberLevelApiImpl.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.member.api.level; + +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.EXPERIENCE_BIZ_NOT_SUPPORT; + +/** + * 会员等级 API 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberLevelApiImpl implements MemberLevelApi { + + @Resource + private MemberLevelService memberLevelService; + + @Override + public MemberLevelRespDTO getMemberLevel(Long id) { + return MemberLevelConvert.INSTANCE.convert02(memberLevelService.getLevel(id)); + } + + @Override + public void addExperience(Long userId, Integer experience, Integer bizType, String bizId) { + MemberExperienceBizTypeEnum bizTypeEnum = MemberExperienceBizTypeEnum.getByType(bizType); + if (bizTypeEnum == null) { + throw exception(EXPERIENCE_BIZ_NOT_SUPPORT); + } + memberLevelService.addExperience(userId, experience, bizTypeEnum, bizId); + } + + @Override + public void reduceExperience(Long userId, Integer experience, Integer bizType, String bizId) { + addExperience(userId, -experience, bizType, bizId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java new file mode 100644 index 0000000..5f97979 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.api; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java new file mode 100644 index 0000000..6e21e85 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApiImpl.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.member.api.point; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.POINT_RECORD_BIZ_NOT_SUPPORT; + +/** + * 用户积分的 API 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberPointApiImpl implements MemberPointApi { + + @Resource + private MemberPointRecordService memberPointRecordService; + + @Override + public void addPoint(Long userId, Integer point, Integer bizType, String bizId) { + Assert.isTrue(point > 0); + MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); + if (bizTypeEnum == null) { + throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); + } + memberPointRecordService.createPointRecord(userId, point, bizTypeEnum, bizId); + } + + @Override + public void reducePoint(Long userId, Integer point, Integer bizType, String bizId) { + Assert.isTrue(point > 0); + MemberPointBizTypeEnum bizTypeEnum = MemberPointBizTypeEnum.getByType(bizType); + if (bizTypeEnum == null) { + throw exception(POINT_RECORD_BIZ_NOT_SUPPORT); + } + memberPointRecordService.createPointRecord(userId, -point, bizTypeEnum, bizId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java new file mode 100644 index 0000000..8da857c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.member.api.user; + +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 会员用户的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MemberUserApiImpl implements MemberUserApi { + + @Resource + private MemberUserService userService; + + @Override + public MemberUserRespDTO getUser(Long id) { + MemberUserDO user = userService.getUser(id); + return MemberUserConvert.INSTANCE.convert2(user); + } + + @Override + public List getUserList(Collection ids) { + return MemberUserConvert.INSTANCE.convertList2(userService.getUserList(ids)); + } + + @Override + public List getUserListByNickname(String nickname) { + return MemberUserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname)); + } + + @Override + public MemberUserRespDTO getUserByMobile(String mobile) { + return MemberUserConvert.INSTANCE.convert2(userService.getUserByMobile(mobile)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/AddressController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/AddressController.java new file mode 100644 index 0000000..0363634 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/AddressController.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.member.controller.admin.address; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.admin.address.vo.AddressRespVO; +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import cn.iocoder.yudao.module.member.service.address.AddressService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 用户收件地址") +@RestController +@RequestMapping("/member/address") +@Validated +public class AddressController { + + @Resource + private AddressService addressService; + + @GetMapping("/list") + @Operation(summary = "获得用户收件地址列表") + @Parameter(name = "userId", description = "用户编号", required = true) + @PreAuthorize("@ss.hasPermission('member:user:query')") + public CommonResult> getAddressList(@RequestParam("userId") Long userId) { + List list = addressService.getAddressList(userId); + return success(AddressConvert.INSTANCE.convertList2(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java new file mode 100644 index 0000000..652bbb6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.member.controller.admin.address; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressBaseVO.java new file mode 100644 index 0000000..5fa2d1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressBaseVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.member.controller.admin.address.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.util.*; +import javax.validation.constraints.*; + +/** + * 用户收件地址 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class AddressBaseVO { + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + @NotNull(message = "收件人名称不能为空") + private String name; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "手机号不能为空") + private String mobile; + + @Schema(description = "地区编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "15716") + @NotNull(message = "地区编码不能为空") + private Long areaId; + + @Schema(description = "收件详细地址", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收件详细地址不能为空") + private String detailAddress; + + @Schema(description = "是否默认", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "是否默认不能为空") + private Boolean defaultStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java new file mode 100644 index 0000000..26a4988 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.controller.admin.address.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 用户收件地址 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AddressRespVO extends AddressBaseVO { + + @Schema(description = "收件地址编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7380") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/MemberConfigController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/MemberConfigController.java new file mode 100644 index 0000000..730358f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/MemberConfigController.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.member.controller.admin.config; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigRespVO; +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO; +import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO; +import cn.iocoder.yudao.module.member.service.config.MemberConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员设置") +@RestController +@RequestMapping("/member/config") +@Validated +public class MemberConfigController { + + @Resource + private MemberConfigService memberConfigService; + + @PutMapping("/save") + @Operation(summary = "保存会员配置") + @PreAuthorize("@ss.hasPermission('member:config:save')") + public CommonResult saveConfig(@Valid @RequestBody MemberConfigSaveReqVO saveReqVO) { + memberConfigService.saveConfig(saveReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得会员配置") + @PreAuthorize("@ss.hasPermission('member:config:query')") + public CommonResult getConfig() { + MemberConfigDO config = memberConfigService.getConfig(); + return success(MemberConfigConvert.INSTANCE.convert(config)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigBaseVO.java new file mode 100644 index 0000000..a9a6b31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigBaseVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 会员配置 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberConfigBaseVO { + + @Schema(description = "积分抵扣开关", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "积分抵扣开发不能为空") + private Boolean pointTradeDeductEnable; + + @Schema(description = "积分抵扣,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "13506") + @NotNull(message = "积分抵扣不能为空") + private Integer pointTradeDeductUnitPrice; + + @Schema(description = "积分抵扣最大值", requiredMode = Schema.RequiredMode.REQUIRED, example = "32428") + @NotNull(message = "积分抵扣最大值不能为空") + private Integer pointTradeDeductMaxPrice; + + @Schema(description = "1 元赠送多少分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "1 元赠送积分不能为空") + private Integer pointTradeGivePoint; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigRespVO.java new file mode 100644 index 0000000..04f14f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.member.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员配置 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberConfigRespVO extends MemberConfigBaseVO { + + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigSaveReqVO.java new file mode 100644 index 0000000..8348f1f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/config/vo/MemberConfigSaveReqVO.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.member.controller.admin.config.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员配置保存 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberConfigSaveReqVO extends MemberConfigBaseVO { +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/MemberGroupController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/MemberGroupController.java new file mode 100644 index 0000000..566e516 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/MemberGroupController.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.member.controller.admin.group; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.*; +import cn.iocoder.yudao.module.member.convert.group.MemberGroupConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.service.group.MemberGroupService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - 用户分组") +@RestController +@RequestMapping("/member/group") +@Validated +public class MemberGroupController { + + @Resource + private MemberGroupService groupService; + + @PostMapping("/create") + @Operation(summary = "创建用户分组") + @PreAuthorize("@ss.hasPermission('member:group:create')") + public CommonResult createGroup(@Valid @RequestBody MemberGroupCreateReqVO createReqVO) { + return success(groupService.createGroup(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新用户分组") + @PreAuthorize("@ss.hasPermission('member:group:update')") + public CommonResult updateGroup(@Valid @RequestBody MemberGroupUpdateReqVO updateReqVO) { + groupService.updateGroup(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户分组") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('member:group:delete')") + public CommonResult deleteGroup(@RequestParam("id") Long id) { + groupService.deleteGroup(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得用户分组") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:group:query')") + public CommonResult getGroup(@RequestParam("id") Long id) { + MemberGroupDO group = groupService.getGroup(id); + return success(MemberGroupConvert.INSTANCE.convert(group)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取会员分组精简信息列表", description = "只包含被开启的会员分组,主要用于前端的下拉选项") + public CommonResult> getSimpleGroupList() { + // 获用户列表,只要开启状态的 + List list = groupService.getEnableGroupList(); + return success(MemberGroupConvert.INSTANCE.convertSimpleList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得用户分组分页") + @PreAuthorize("@ss.hasPermission('member:group:query')") + public CommonResult> getGroupPage(@Valid MemberGroupPageReqVO pageVO) { + PageResult pageResult = groupService.getGroupPage(pageVO); + return success(MemberGroupConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupBaseVO.java new file mode 100644 index 0000000..0519bd9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupBaseVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 用户分组 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberGroupBaseVO { + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "购物达人") + @NotNull(message = "名称不能为空") + private String name; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String remark; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupCreateReqVO.java new file mode 100644 index 0000000..ef3f833 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 用户分组创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberGroupCreateReqVO extends MemberGroupBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupPageReqVO.java new file mode 100644 index 0000000..ae67d5f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 用户分组分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberGroupPageReqVO extends PageParam { + + @Schema(description = "名称", example = "购物达人") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupRespVO.java new file mode 100644 index 0000000..9736538 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 用户分组 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberGroupRespVO extends MemberGroupBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20357") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupSimpleRespVO.java new file mode 100644 index 0000000..ee7d905 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupSimpleRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 用户分组 Response VO") +@Data +@ToString(callSuper = true) +public class MemberGroupSimpleRespVO { + + @Schema(description = "编号", example = "6103") + private Long id; + + @Schema(description = "等级名称", example = "芋艿") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupUpdateReqVO.java new file mode 100644 index 0000000..7591088 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/group/vo/MemberGroupUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.controller.admin.group.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户分组更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberGroupUpdateReqVO extends MemberGroupBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20357") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberExperienceRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberExperienceRecordController.java new file mode 100644 index 0000000..cdbd760 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberExperienceRecordController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.member.controller.admin.level; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordRespVO; +import cn.iocoder.yudao.module.member.convert.level.MemberExperienceRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import cn.iocoder.yudao.module.member.service.level.MemberExperienceRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员经验记录") +@RestController +@RequestMapping("/member/experience-record") +@Validated +public class MemberExperienceRecordController { + + @Resource + private MemberExperienceRecordService experienceLogService; + + @GetMapping("/get") + @Operation(summary = "获得会员经验记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:experience-record:query')") + public CommonResult getExperienceRecord(@RequestParam("id") Long id) { + MemberExperienceRecordDO experienceLog = experienceLogService.getExperienceRecord(id); + return success(MemberExperienceRecordConvert.INSTANCE.convert(experienceLog)); + } + + @GetMapping("/page") + @Operation(summary = "获得会员经验记录分页") + @PreAuthorize("@ss.hasPermission('member:experience-record:query')") + public CommonResult> getExperienceRecordPage( + @Valid MemberExperienceRecordPageReqVO pageVO) { + PageResult pageResult = experienceLogService.getExperienceRecordPage(pageVO); + return success(MemberExperienceRecordConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelController.java new file mode 100644 index 0000000..195800e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelController.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.member.controller.admin.level; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.*; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员等级") +@RestController +@RequestMapping("/member/level") +@Validated +public class MemberLevelController { + + @Resource + private MemberLevelService levelService; + + @PostMapping("/create") + @Operation(summary = "创建会员等级") + @PreAuthorize("@ss.hasPermission('member:level:create')") + public CommonResult createLevel(@Valid @RequestBody MemberLevelCreateReqVO createReqVO) { + return success(levelService.createLevel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新会员等级") + @PreAuthorize("@ss.hasPermission('member:level:update')") + public CommonResult updateLevel(@Valid @RequestBody MemberLevelUpdateReqVO updateReqVO) { + levelService.updateLevel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除会员等级") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('member:level:delete')") + public CommonResult deleteLevel(@RequestParam("id") Long id) { + levelService.deleteLevel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得会员等级") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:level:query')") + public CommonResult getLevel(@RequestParam("id") Long id) { + MemberLevelDO level = levelService.getLevel(id); + return success(MemberLevelConvert.INSTANCE.convert(level)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取会员等级精简信息列表", description = "只包含被开启的会员等级,主要用于前端的下拉选项") + public CommonResult> getSimpleLevelList() { + // 获用户列表,只要开启状态的 + List list = levelService.getEnableLevelList(); + // 排序后,返回给前端 + return success(MemberLevelConvert.INSTANCE.convertSimpleList(list)); + } + + @GetMapping("/list") + @Operation(summary = "获得会员等级列表") + @PreAuthorize("@ss.hasPermission('member:level:query')") + public CommonResult> getLevelList(@Valid MemberLevelListReqVO listReqVO) { + List result = levelService.getLevelList(listReqVO); + return success(MemberLevelConvert.INSTANCE.convertList(result)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelRecordController.java new file mode 100644 index 0000000..b54a54d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/MemberLevelRecordController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.member.controller.admin.level; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordRespVO; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; +import cn.iocoder.yudao.module.member.service.level.MemberLevelRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员等级记录") +@RestController +@RequestMapping("/member/level-record") +@Validated +public class MemberLevelRecordController { + + @Resource + private MemberLevelRecordService levelLogService; + + @GetMapping("/get") + @Operation(summary = "获得会员等级记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:level-record:query')") + public CommonResult getLevelRecord(@RequestParam("id") Long id) { + MemberLevelRecordDO levelLog = levelLogService.getLevelRecord(id); + return success(MemberLevelRecordConvert.INSTANCE.convert(levelLog)); + } + + @GetMapping("/page") + @Operation(summary = "获得会员等级记录分页") + @PreAuthorize("@ss.hasPermission('member:level-record:query')") + public CommonResult> getLevelRecordPage( + @Valid MemberLevelRecordPageReqVO pageVO) { + PageResult pageResult = levelLogService.getLevelRecordPage(pageVO); + return success(MemberLevelRecordConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordBaseVO.java new file mode 100644 index 0000000..7c71f82 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordBaseVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.experience; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 会员经验记录 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberExperienceRecordBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3638") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12164") + @NotNull(message = "业务编号不能为空") + private String bizId; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "业务类型不能为空") + private Integer bizType; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "增加经验") + @NotNull(message = "标题不能为空") + private String title; + + @Schema(description = "经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "经验不能为空") + private Integer experience; + + @Schema(description = "变更后的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + @NotNull(message = "变更后的经验不能为空") + private Integer totalExperience; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "下单增加 100 经验") + @NotNull(message = "描述不能为空") + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordPageReqVO.java new file mode 100644 index 0000000..d18201d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.experience; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员经验记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberExperienceRecordPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "3638") + private Long userId; + + @Schema(description = "业务编号", example = "12164") + private String bizId; + + @Schema(description = "业务类型", example = "1") + private Integer bizType; + + @Schema(description = "标题", example = "增加经验") + private String title; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordRespVO.java new file mode 100644 index 0000000..5e652fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/experience/MemberExperienceRecordRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.experience; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 会员经验记录 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberExperienceRecordRespVO extends MemberExperienceRecordBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19610") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelBaseVO.java new file mode 100644 index 0000000..9580647 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelBaseVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Range; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; + +/** + * 会员等级 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberLevelBaseVO { + + @Schema(description = "等级名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotBlank(message = "等级名称不能为空") + private String name; + + @Schema(description = "升级经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "升级经验不能为空") + @Positive(message = "升级经验必须大于 0") + private Integer experience; + + @Schema(description = "等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "等级不能为空") + @Positive(message = "等级必须大于 0") + private Integer level; + + @Schema(description = "享受折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "98") + @NotNull(message = "享受折扣不能为空") + @Range(min = 0, max = 100, message = "享受折扣的范围为 0-100") + private Integer discountPercent; + + @Schema(description = "等级图标", example = "https://www.iocoder.cn/yudao.jpg") + @URL(message = "等级图标必须是 URL 格式") + private String icon; + + @Schema(description = "等级背景图", example = "https://www.iocoder.cn/yudao.jpg") + @URL(message = "等级背景图必须是 URL 格式") + private String backgroundUrl; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelCreateReqVO.java new file mode 100644 index 0000000..f51a7d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员等级创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberLevelCreateReqVO extends MemberLevelBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelListReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelListReqVO.java new file mode 100644 index 0000000..348e78e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelListReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员等级列表筛选 Request VO") +@Data +@ToString(callSuper = true) +public class MemberLevelListReqVO { + + @Schema(description = "等级名称", example = "芋艿") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelRespVO.java new file mode 100644 index 0000000..df91a81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 会员等级 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberLevelRespVO extends MemberLevelBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6103") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelSimpleRespVO.java new file mode 100644 index 0000000..96c515c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelSimpleRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员等级 Response VO") +@Data +@ToString(callSuper = true) +public class MemberLevelSimpleRespVO { + + @Schema(description = "编号", example = "6103") + private Long id; + + @Schema(description = "等级名称", example = "芋艿") + private String name; + + @Schema(description = "等级图标", example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelUpdateReqVO.java new file mode 100644 index 0000000..83ad768 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/level/MemberLevelUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 会员等级更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberLevelUpdateReqVO extends MemberLevelBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6103") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordBaseVO.java new file mode 100644 index 0000000..99df536 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordBaseVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 会员等级记录 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberLevelRecordBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25923") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "等级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25985") + @NotNull(message = "等级编号不能为空") + private Long levelId; + + @Schema(description = "会员等级", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "会员等级不能为空") + private Integer level; + + @Schema(description = "享受折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "13319") + @NotNull(message = "享受折扣不能为空") + private Integer discountPercent; + + @Schema(description = "升级经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "13319") + @NotNull(message = "升级经验不能为空") + private Integer experience; + + @Schema(description = "会员此时的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "13319") + @NotNull(message = "会员此时的经验不能为空") + private Integer userExperience; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "推广需要") + @NotNull(message = "备注不能为空") + private String remark; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级为金牌会员") + @NotNull(message = "描述不能为空") + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordPageReqVO.java new file mode 100644 index 0000000..2590cfb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员等级记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberLevelRecordPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "25923") + private Long userId; + + @Schema(description = "等级编号", example = "25985") + private Long levelId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordRespVO.java new file mode 100644 index 0000000..caf98ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/level/vo/record/MemberLevelRecordRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.level.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 会员等级记录 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberLevelRecordRespVO extends MemberLevelRecordBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8741") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/MemberPointRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/MemberPointRecordController.java new file mode 100644 index 0000000..4897224 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/MemberPointRecordController.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.member.controller.admin.point; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO; +import cn.iocoder.yudao.module.member.convert.point.MemberPointRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.CollectionUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 签到记录") +@RestController +@RequestMapping("/member/point/record") +@Validated +public class MemberPointRecordController { + + @Resource + private MemberPointRecordService pointRecordService; + + @Resource + private MemberUserService memberUserService; + + @GetMapping("/page") + @Operation(summary = "获得用户积分记录分页") + @PreAuthorize("@ss.hasPermission('point:record:query')") + public CommonResult> getPointRecordPage(@Valid MemberPointRecordPageReqVO pageVO) { + // 执行分页查询 + PageResult pageResult = pointRecordService.getPointRecordPage(pageVO); + if (CollectionUtils.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接结果返回 + List users = memberUserService.getUserList( + convertSet(pageResult.getList(), MemberPointRecordDO::getUserId)); + return success(MemberPointRecordConvert.INSTANCE.convertPage(pageResult, users)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordPageReqVO.java new file mode 100644 index 0000000..63cc800 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 用户积分记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberPointRecordPageReqVO extends PageParam { + + @Schema(description = "用户昵称", example = "张三") + private String nickname; + + @Schema(description = "用户编号", example = "123") + private Long userId; + + @Schema(description = "业务类型", example = "1") + private Integer bizType; + + @Schema(description = "积分标题", example = "呵呵") + private String title; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordRespVO.java new file mode 100644 index 0000000..6714aa8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/point/vo/recrod/MemberPointRecordRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 用户积分记录 Response VO") +@Data +public class MemberPointRecordRespVO { + + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "31457") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "昵称", example = "张三") + private String nickname; + + @Schema(description = "业务编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "22706") + private String bizId; + + @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer bizType; + + @Schema(description = "积分标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String title; + + @Schema(description = "积分描述", example = "你猜") + private String description; + + @Schema(description = "积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer point; + + @Schema(description = "变动后的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer totalPoint; + + @Schema(description = "发生时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInConfigController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInConfigController.java new file mode 100644 index 0000000..65bfe44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInConfigController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigRespVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInConfigConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import cn.iocoder.yudao.module.member.service.signin.MemberSignInConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +// TODO 芋艿:url +@Tag(name = "管理后台 - 签到规则") +@RestController +@RequestMapping("/member/sign-in/config") +@Validated +public class MemberSignInConfigController { + + @Resource + private MemberSignInConfigService signInConfigService; + + @PostMapping("/create") + @Operation(summary = "创建签到规则") + @PreAuthorize("@ss.hasPermission('point:sign-in-config:create')") + public CommonResult createSignInConfig(@Valid @RequestBody MemberSignInConfigCreateReqVO createReqVO) { + return success(signInConfigService.createSignInConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新签到规则") + @PreAuthorize("@ss.hasPermission('point:sign-in-config:update')") + public CommonResult updateSignInConfig(@Valid @RequestBody MemberSignInConfigUpdateReqVO updateReqVO) { + signInConfigService.updateSignInConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除签到规则") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('point:sign-in-config:delete')") + public CommonResult deleteSignInConfig(@RequestParam("id") Long id) { + signInConfigService.deleteSignInConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得签到规则") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('point:sign-in-config:query')") + public CommonResult getSignInConfig(@RequestParam("id") Long id) { + MemberSignInConfigDO signInConfig = signInConfigService.getSignInConfig(id); + return success(MemberSignInConfigConvert.INSTANCE.convert(signInConfig)); + } + + @GetMapping("/list") + @Operation(summary = "获得签到规则列表") + @PreAuthorize("@ss.hasPermission('point:sign-in-config:query')") + public CommonResult> getSignInConfigList() { + List list = signInConfigService.getSignInConfigList(); + return success(MemberSignInConfigConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInRecordController.java new file mode 100644 index 0000000..8bf1796 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/MemberSignInRecordController.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.CollectionUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 签到记录") +@RestController +@RequestMapping("/member/sign-in/record") +@Validated +public class MemberSignInRecordController { + + @Resource + private MemberSignInRecordService signInRecordService; + + @Resource + private MemberUserService memberUserService; + + @GetMapping("/page") + @Operation(summary = "获得签到记录分页") + @PreAuthorize("@ss.hasPermission('point:sign-in-record:query')") + public CommonResult> getSignInRecordPage(@Valid MemberSignInRecordPageReqVO pageVO) { + // 执行分页查询 + PageResult pageResult = signInRecordService.getSignInRecordPage(pageVO); + if (CollectionUtils.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接结果返回 + List users = memberUserService.getUserList( + convertSet(pageResult.getList(), MemberSignInRecordDO::getUserId)); + return success(MemberSignInRecordConvert.INSTANCE.convertPage(pageResult, users)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java new file mode 100644 index 0000000..2ddeeb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.PositiveOrZero; + +/** + * 签到规则 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberSignInConfigBaseVO { + + @Schema(description = "签到第 x 天", requiredMode = Schema.RequiredMode.REQUIRED, example = "7") + @NotNull(message = "签到天数不能为空") + private Integer day; + + @Schema(description = "奖励积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "奖励积分不能为空") + @PositiveOrZero(message = "奖励积分不能小于 0") + private Integer point; + + @Schema(description = "奖励经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "奖励经验不能为空") + @PositiveOrZero(message = "奖励经验不能小于 0") + private Integer experience; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @AssertTrue(message = "签到奖励积分和经验不能同时为空") + @JsonIgnore + public boolean isConfigAward() { + return ObjUtil.notEqual(point, 0) || ObjUtil.notEqual(experience, 0); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigCreateReqVO.java new file mode 100644 index 0000000..7ca03fa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigCreateReqVO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "管理后台 - 签到规则创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberSignInConfigCreateReqVO extends MemberSignInConfigBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigRespVO.java new file mode 100644 index 0000000..8d423b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 签到规则 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberSignInConfigRespVO extends MemberSignInConfigBaseVO { + + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "20937") + private Integer id; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigUpdateReqVO.java new file mode 100644 index 0000000..89b6de1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigUpdateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 签到规则更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberSignInConfigUpdateReqVO extends MemberSignInConfigBaseVO { + + @Schema(description = "规则自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "13653") + @NotNull(message = "规则自增主键不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordPageReqVO.java new file mode 100644 index 0000000..b46712b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 签到记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberSignInRecordPageReqVO extends PageParam { + + @Schema(description = "签到用户", example = "土豆") + private String nickname; + + @Schema(description = "第几天签到", example = "10") + private Integer day; + + @Schema(description = "用户编号", example = "123") + private Long userId; + + @Schema(description = "签到时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordRespVO.java new file mode 100644 index 0000000..b5755ba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/record/MemberSignInRecordRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.member.controller.admin.signin.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 签到记录 Response VO") +@Data +public class MemberSignInRecordRespVO { + + @Schema(description = "签到自增 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "11903") + private Long id; + + @Schema(description = "签到用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "6507") + private Long userId; + + @Schema(description = "昵称", example = "张三") + private String nickname; + + @Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer day; + + @Schema(description = "签到的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer point; + + @Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/MemberTagController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/MemberTagController.java new file mode 100644 index 0000000..34f3c20 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/MemberTagController.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagRespVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.tag.MemberTagConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import cn.iocoder.yudao.module.member.service.tag.MemberTagService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 会员标签") +@RestController +@RequestMapping("/member/tag") +@Validated +public class MemberTagController { + + @Resource + private MemberTagService tagService; + + @PostMapping("/create") + @Operation(summary = "创建会员标签") + @PreAuthorize("@ss.hasPermission('member:tag:create')") + public CommonResult createTag(@Valid @RequestBody MemberTagCreateReqVO createReqVO) { + return success(tagService.createTag(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新会员标签") + @PreAuthorize("@ss.hasPermission('member:tag:update')") + public CommonResult updateTag(@Valid @RequestBody MemberTagUpdateReqVO updateReqVO) { + tagService.updateTag(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除会员标签") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('member:tag:delete')") + public CommonResult deleteTag(@RequestParam("id") Long id) { + tagService.deleteTag(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得会员标签") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:tag:query')") + public CommonResult getMemberTag(@RequestParam("id") Long id) { + MemberTagDO tag = tagService.getTag(id); + return success(MemberTagConvert.INSTANCE.convert(tag)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取会员标签精简信息列表", description = "只包含被开启的会员标签,主要用于前端的下拉选项") + public CommonResult> getSimpleTagList() { + // 获用户列表,只要开启状态的 + List list = tagService.getTagList(); + // 排序后,返回给前端 + return success(MemberTagConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/list") + @Operation(summary = "获得会员标签列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('member:tag:query')") + public CommonResult> getMemberTagList(@RequestParam("ids") Collection ids) { + List list = tagService.getTagList(ids); + return success(MemberTagConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得会员标签分页") + @PreAuthorize("@ss.hasPermission('member:tag:query')") + public CommonResult> getTagPage(@Valid MemberTagPageReqVO pageVO) { + PageResult pageResult = tagService.getTagPage(pageVO); + return success(MemberTagConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagBaseVO.java new file mode 100644 index 0000000..bc0efea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagBaseVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 会员标签 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberTagBaseVO { + + @Schema(description = "标签名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "标签名称不能为空") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagCreateReqVO.java new file mode 100644 index 0000000..b61f26b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 会员标签创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberTagCreateReqVO extends MemberTagBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagPageReqVO.java new file mode 100644 index 0000000..99f59b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员标签分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberTagPageReqVO extends PageParam { + + @Schema(description = "标签名称", example = "李四") + private String name; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagRespVO.java new file mode 100644 index 0000000..2c21f53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 会员标签 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberTagRespVO extends MemberTagBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "907") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagUpdateReqVO.java new file mode 100644 index 0000000..2fe0e61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/tag/vo/MemberTagUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 会员标签更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberTagUpdateReqVO extends MemberTagBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "907") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java new file mode 100644 index 0000000..b382c1c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java @@ -0,0 +1,121 @@ +package cn.iocoder.yudao.module.member.controller.admin.user; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.*; +import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import cn.iocoder.yudao.module.member.service.group.MemberGroupService; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; +import cn.iocoder.yudao.module.member.service.tag.MemberTagService; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 会员用户") +@RestController +@RequestMapping("/member/user") +@Validated +public class MemberUserController { + + @Resource + private MemberUserService memberUserService; + @Resource + private MemberTagService memberTagService; + @Resource + private MemberLevelService memberLevelService; + @Resource + private MemberGroupService memberGroupService; + @Resource + private MemberPointRecordService memberPointRecordService; + + @PutMapping("/update") + @Operation(summary = "更新会员用户") + @PreAuthorize("@ss.hasPermission('member:user:update')") + public CommonResult updateUser(@Valid @RequestBody MemberUserUpdateReqVO updateReqVO) { + memberUserService.updateUser(updateReqVO); + return success(true); + } + + @PutMapping("/update-level") + @Operation(summary = "更新会员用户等级") + @PreAuthorize("@ss.hasPermission('member:user:update-level')") + public CommonResult updateUserLevel(@Valid @RequestBody MemberUserUpdateLevelReqVO updateReqVO) { + memberLevelService.updateUserLevel(updateReqVO); + return success(true); + } + + @PutMapping("/update-point") + @Operation(summary = "更新会员用户积分") + @PreAuthorize("@ss.hasPermission('member:user:update-point')") + public CommonResult updateUserPoint(@Valid @RequestBody MemberUserUpdatePointReqVO updateReqVO) { + memberPointRecordService.createPointRecord(updateReqVO.getId(), updateReqVO.getPoint(), + MemberPointBizTypeEnum.ADMIN, String.valueOf(getLoginUserId())); + return success(true); + } + + @PutMapping("/update-balance") + @Operation(summary = "更新会员用户余额") + @PreAuthorize("@ss.hasPermission('member:user:update-balance')") + public CommonResult updateUserBalance(@Valid @RequestBody Long id) { + // todo @jason:增加一个【修改余额】 + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得会员用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('member:user:query')") + public CommonResult getUser(@RequestParam("id") Long id) { + MemberUserDO user = memberUserService.getUser(id); + return success(MemberUserConvert.INSTANCE.convert03(user)); + } + + @GetMapping("/page") + @Operation(summary = "获得会员用户分页") + @PreAuthorize("@ss.hasPermission('member:user:query')") + public CommonResult> getUserPage(@Valid MemberUserPageReqVO pageVO) { + PageResult pageResult = memberUserService.getUserPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 处理用户标签返显 + Set tagIds = pageResult.getList().stream() + .map(MemberUserDO::getTagIds) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + List tags = memberTagService.getTagList(tagIds); + // 处理用户级别返显 + List levels = memberLevelService.getLevelList( + convertSet(pageResult.getList(), MemberUserDO::getLevelId)); + // 处理用户分组返显 + List groups = memberGroupService.getGroupList( + convertSet(pageResult.getList(), MemberUserDO::getGroupId)); + return success(MemberUserConvert.INSTANCE.convertPage(pageResult, tags, levels, groups)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java new file mode 100644 index 0000000..e8c9974 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 会员用户 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MemberUserBaseVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @NotNull(message = "手机号不能为空") + private String mobile; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "状态不能为空") + private Byte status; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "用户昵称不能为空") + private String nickname; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/x.png") + @URL(message = "头像必须是 URL 格式") + private String avatar; + + @Schema(description = "用户昵称", example = "李四") + private String name; + + @Schema(description = "用户性别", example = "1") + private Integer sex; + + @Schema(description = "所在地编号", example = "4371") + private Long areaId; + + @Schema(description = "所在地全程", example = "上海上海市普陀区") + private String areaName; + + @Schema(description = "出生日期", example = "2023-03-12") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDateTime birthday; + + @Schema(description = "会员备注", example = "我是小备注") + private String mark; + + @Schema(description = "会员标签", example = "[1, 2]") + private List tagIds; + + @Schema(description = "会员等级编号", example = "1") + private Long levelId; + + @Schema(description = "用户分组编号", example = "1") + private Long groupId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java new file mode 100644 index 0000000..abb9428 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员用户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberUserPageReqVO extends PageParam { + + @Schema(description = "手机号", example = "15601691300") + private String mobile; + + @Schema(description = "用户昵称", example = "李四") + private String nickname; + + @Schema(description = "最后登录时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] loginDate; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "会员标签编号列表", example = "[1, 2]") + private List tagIds; + + @Schema(description = "会员等级编号", example = "1") + private Long levelId; + + @Schema(description = "用户分组编号", example = "1") + private Long groupId; + + // TODO 芋艿:注册用户类型; + + // TODO 芋艿:登录用户类型; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java new file mode 100644 index 0000000..1cd2283 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 会员用户 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberUserRespVO extends MemberUserBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788") + private Long id; + + @Schema(description = "注册 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String registerIp; + + @Schema(description = "最后登录IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String loginIp; + + @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime loginDate; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 其它信息 ========== + + @Schema(description = "积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer point; + + @Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + private Integer totalPoint; + + @Schema(description = "会员标签", example = "[红色, 快乐]") + private List tagNames; + + @Schema(description = "会员等级", example = "黄金会员") + private String levelName; + + @Schema(description = "用户分组", example = "购物达人") + private String groupName; + + @Schema(description = "用户经验值", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Integer experience; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateLevelReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateLevelReqVO.java new file mode 100644 index 0000000..dba48f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateLevelReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户修改等级 Request VO") +@Data +@ToString(callSuper = true) +public class MemberUserUpdateLevelReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788") + @NotNull(message = "用户编号不能为空") + private Long id; + + /** + * 取消用户等级时,值为空 + */ + @Schema(description = "用户等级编号", example = "1") + private Long levelId; + + @Schema(description = "修改原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "推广需要") + @NotBlank(message = "修改原因不能为空") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdatePointReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdatePointReqVO.java new file mode 100644 index 0000000..a072c07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdatePointReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户修改积分 Request VO") +@Data +@ToString(callSuper = true) +public class MemberUserUpdatePointReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788") + @NotNull(message = "用户编号不能为空") + private Long id; + + @Schema(description = "变动积分,正数为增加,负数为减少", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "变动积分不能为空") + private Integer point; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateReqVO.java new file mode 100644 index 0000000..c6a9275 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 会员用户更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MemberUserUpdateReqVO extends MemberUserBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.http b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.http new file mode 100644 index 0000000..6bae7c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.http @@ -0,0 +1,54 @@ +### 请求 /create 接口 => 成功 +POST {{appApi}}//member/address/create +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +{ + "name": "yunai", + "mobile": "15601691300", + "areaId": "610632", + "postCode": "200000", + "detailAddress": "芋道源码 233 号 666 室", + "defaulted": true +} + +### 请求 /update 接口 => 成功 +PUT {{appApi}}//member/address/update +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +{ + "id": "1", + "name": "yunai888", + "mobile": "15601691300", + "areaId": "610632", + "postCode": "200000", + "detailAddress": "芋道源码 233 号 666 室", + "defaulted": false +} + +### 请求 /delete 接口 => 成功 +DELETE {{appApi}}//member/address/delete?id=2 +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /get 接口 => 成功 +GET {{appApi}}//member/address/get?id=1 +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /get-default 接口 => 成功 +GET {{appApi}}//member/address/get-default +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /list 接口 => 成功 +GET {{appApi}}//member/address/list +Content-Type: application/json +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.java new file mode 100644 index 0000000..7ba55c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.member.controller.app.address; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import cn.iocoder.yudao.module.member.service.address.AddressService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 用户收件地址") +@RestController +@RequestMapping("/member/address") +@Validated +public class AppAddressController { + + @Resource + private AddressService addressService; + + @PostMapping("/create") + @Operation(summary = "创建用户收件地址") + @PreAuthenticated + public CommonResult createAddress(@Valid @RequestBody AppAddressCreateReqVO createReqVO) { + return success(addressService.createAddress(getLoginUserId(), createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新用户收件地址") + @PreAuthenticated + public CommonResult updateAddress(@Valid @RequestBody AppAddressUpdateReqVO updateReqVO) { + addressService.updateAddress(getLoginUserId(), updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户收件地址") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthenticated + public CommonResult deleteAddress(@RequestParam("id") Long id) { + addressService.deleteAddress(getLoginUserId(), id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得用户收件地址") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthenticated + public CommonResult getAddress(@RequestParam("id") Long id) { + MemberAddressDO address = addressService.getAddress(getLoginUserId(), id); + return success(AddressConvert.INSTANCE.convert(address)); + } + + @GetMapping("/get-default") + @Operation(summary = "获得默认的用户收件地址") + @PreAuthenticated + public CommonResult getDefaultUserAddress() { + MemberAddressDO address = addressService.getDefaultUserAddress(getLoginUserId()); + return success(AddressConvert.INSTANCE.convert(address)); + } + + @GetMapping("/list") + @Operation(summary = "获得用户收件地址列表") + @PreAuthenticated + public CommonResult> getAddressList() { + List list = addressService.getAddressList(getLoginUserId()); + return success(AddressConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressBaseVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressBaseVO.java new file mode 100644 index 0000000..076ce36 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressBaseVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.controller.app.address.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +// TODO 芋艿:example 缺失 +/** +* 用户收件地址 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class AppAddressBaseVO { + + @Schema(description = "收件人名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收件人名称不能为空") + private String name; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "手机号不能为空") + private String mobile; + + @Schema(description = "地区编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "地区编号不能为空") + private Long areaId; + + @Schema(description = "收件详细地址", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收件详细地址不能为空") + private String detailAddress; + + @Schema(description = "是否默认地址", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否默认地址不能为空") + private Boolean defaultStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressCreateReqVO.java new file mode 100644 index 0000000..c92687f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressCreateReqVO.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.member.controller.app.address.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Schema(description = "用户 APP - 用户收件地址创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppAddressCreateReqVO extends AppAddressBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressRespVO.java new file mode 100644 index 0000000..d3e2f9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.member.controller.app.address.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "用户 APP - 用户收件地址 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppAddressRespVO extends AppAddressBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海上海市普陀区") + private String areaName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressUpdateReqVO.java new file mode 100644 index 0000000..19b58d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressUpdateReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.member.controller.app.address.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import javax.validation.constraints.*; + +@Schema(description = "用户 APP - 用户收件地址更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AppAddressUpdateReqVO extends AppAddressBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http new file mode 100644 index 0000000..5b68d69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http @@ -0,0 +1,67 @@ +### 请求 /login 接口 => 成功 +POST {{appApi}}/member/auth/login +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "mobile": "15601691388", + "password": "admin123" +} + +### 请求 /send-sms-code 接口 => 成功 +POST {{appApi}}/member/auth/send-sms-code +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "mobile": "15601691388", + "scene": 1 +} + +### 请求 /sms-login 接口 => 成功 +POST {{appApi}}/member/auth/sms-login +Content-Type: application/json +tenant-id: {{appTenentId}} +terminal: 30 + +{ + "mobile": "15601691388", + "code": 9999 +} + +### 请求 /social-login 接口 => 成功 +POST {{appApi}}/member/auth/social-login +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "type": 34, + "code": "0e1oc9000CTjFQ1oim200bhtb61oc90g", + "state": "default" +} + +### 请求 /weixin-mini-app-login 接口 => 成功 +POST {{appApi}}/member/auth/weixin-mini-app-login +Content-Type: application/json +tenant-id: {{appTenentId}} + +{ + "phoneCode": "618e6412e0c728f5b8fc7164497463d0158a923c9e7fd86af8bba393b9decbc5", + "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR" +} + +### 请求 /logout 接口 => 成功 +POST {{appApi}}/member/auth/logout +Content-Type: application/json +Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 +tenant-id: {{appTenentId}} + +### 请求 /auth/refresh-token 接口 => 成功 +POST {{appApi}}/member/auth/refresh-token?refreshToken=bc43d929094849a28b3a69f6e6940d70 +Content-Type: application/json +tenant-id: {{appTenentId}} + +### 请求 /auth/create-weixin-jsapi-signature 接口 => 成功 +POST {{appApi}}/member/auth/create-weixin-jsapi-signature?url=http://www.iocoder.cn +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java new file mode 100644 index 0000000..5d3c936 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.member.controller.app.auth; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.member.service.auth.MemberAuthService; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 认证") +@RestController +@RequestMapping("/member/auth") +@Validated +@Slf4j +public class AppAuthController { + + @Resource + private MemberAuthService authService; + + @Resource + private SocialClientApi socialClientApi; + + @Resource + private SecurityProperties securityProperties; + + @PostMapping("/login") + @Operation(summary = "使用手机 + 密码登录") + public CommonResult login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { + return success(authService.login(reqVO)); + } + + @PostMapping("/logout") + @PermitAll + @Operation(summary = "登出系统") + public CommonResult logout(HttpServletRequest request) { + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); + if (StrUtil.isNotBlank(token)) { + authService.logout(token); + } + return success(true); + } + + @PostMapping("/refresh-token") + @Operation(summary = "刷新令牌") + @Parameter(name = "refreshToken", description = "刷新令牌", required = true) + public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { + return success(authService.refreshToken(refreshToken)); + } + + // ========== 短信登录相关 ========== + + @PostMapping("/sms-login") + @Operation(summary = "使用手机 + 验证码登录") + public CommonResult smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { + return success(authService.smsLogin(reqVO)); + } + + @PostMapping("/send-sms-code") + @Operation(summary = "发送手机验证码") + public CommonResult sendSmsCode(@RequestBody @Valid AppAuthSmsSendReqVO reqVO) { + authService.sendSmsCode(getLoginUserId(), reqVO); + return success(true); + } + + @PostMapping("/validate-sms-code") + @Operation(summary = "校验手机验证码") + public CommonResult validateSmsCode(@RequestBody @Valid AppAuthSmsValidateReqVO reqVO) { + authService.validateSmsCode(getLoginUserId(), reqVO); + return success(true); + } + + // ========== 社交登录相关 ========== + + @GetMapping("/social-auth-redirect") + @Operation(summary = "社交授权的跳转") + @Parameters({ + @Parameter(name = "type", description = "社交类型", required = true), + @Parameter(name = "redirectUri", description = "回调路径") + }) + public CommonResult socialAuthRedirect(@RequestParam("type") Integer type, + @RequestParam("redirectUri") String redirectUri) { + return CommonResult.success(authService.getSocialAuthorizeUrl(type, redirectUri)); + } + + @PostMapping("/social-login") + @Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户") + public CommonResult socialLogin(@RequestBody @Valid AppAuthSocialLoginReqVO reqVO) { + return success(authService.socialLogin(reqVO)); + } + + @PostMapping("/weixin-mini-app-login") + @Operation(summary = "微信小程序的一键登录") + public CommonResult weixinMiniAppLogin(@RequestBody @Valid AppAuthWeixinMiniAppLoginReqVO reqVO) { + return success(authService.weixinMiniAppLogin(reqVO)); + } + + @PostMapping("/create-weixin-jsapi-signature") + @Operation(summary = "创建微信 JS SDK 初始化所需的签名", + description = "参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档") + public CommonResult createWeixinMpJsapiSignature(@RequestParam("url") String url) { + SocialWxJsapiSignatureRespDTO signature = socialClientApi.createWxMpJsapiSignature( + UserTypeEnum.MEMBER.getValue(), url); + return success(AuthConvert.INSTANCE.convert(signature)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java new file mode 100644 index 0000000..eee7062 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthCheckCodeReqVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +// TODO 芋艿:code review 相关逻辑 +@Schema(description = "用户 APP - 校验验证码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthCheckCodeReqVO { + + @Schema(description = "手机号", example = "15601691234") + @NotBlank(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotBlank(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + + @Schema(description = "发送场景,对应 SmsSceneEnum 枚举", example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginReqVO.java new file mode 100644 index 0000000..e64209d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginReqVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; + +@Schema(description = "用户 APP - 手机 + 密码登录 Request VO,如果登录并绑定社交用户,需要传递 social 开头的参数") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthLoginReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + // ========== 绑定社交登录时,需要传递如下参数 ========== + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String socialCode; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + private String socialState; + + @AssertTrue(message = "授权码不能为空") + public boolean isSocialCodeValid() { + return socialType == null || StrUtil.isNotEmpty(socialCode); + } + + @AssertTrue(message = "授权 state 不能为空") + public boolean isSocialState() { + return socialType == null || StrUtil.isNotEmpty(socialState); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java new file mode 100644 index 0000000..072ec9e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "用户 APP - 登录 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthLoginRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + private String refreshToken; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + + /** + * 仅社交登录、社交绑定时会返回 + * + * 为什么需要返回?微信公众号、微信小程序支付需要传递 openid 给支付接口 + */ + @Schema(description = "社交用户 openid", example = "qq768") + private String openid; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsLoginReqVO.java new file mode 100644 index 0000000..8225269 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsLoginReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 手机 + 验证码登录 Request VO,如果登录并绑定社交用户,需要传递 social 开头的参数") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthSmsLoginReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + + // ========== 绑定社交登录时,需要传递如下参数 ========== + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String socialCode; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + private String socialState; + + @AssertTrue(message = "授权码不能为空") + public boolean isSocialCodeValid() { + return socialType == null || StrUtil.isNotEmpty(socialCode); + } + + @AssertTrue(message = "授权 state 不能为空") + public boolean isSocialState() { + return socialType == null || StrUtil.isNotEmpty(socialState); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsSendReqVO.java new file mode 100644 index 0000000..5f4b030 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsSendReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 APP - 发送手机验证码 Request VO") +@Data +@Accessors(chain = true) +public class AppAuthSmsSendReqVO { + + @Schema(description = "手机号", example = "15601691234") + @Mobile + private String mobile; + + @Schema(description = "发送场景,对应 SmsSceneEnum 枚举", example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java new file mode 100644 index 0000000..1a57be7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 校验手机验证码 Request VO") +@Data +@Accessors(chain = true) +public class AppAuthSmsValidateReqVO { + + @Schema(description = "手机号", example = "15601691234") + @Mobile + private String mobile; + + @Schema(description = "发送场景,对应 SmsSceneEnum 枚举", example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialLoginReqVO.java new file mode 100644 index 0000000..d3bac47 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSocialLoginReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 APP - 社交快捷登录 Request VO,使用 code 授权码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthSocialLoginReqVO { + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthWeixinMiniAppLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthWeixinMiniAppLoginReqVO.java new file mode 100644 index 0000000..b14f182 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthWeixinMiniAppLoginReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "用户 APP - 微信小程序手机登录 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppAuthWeixinMiniAppLoginReqVO { + + @Schema(description = "手机 code,小程序通过 wx.getPhoneNumber 方法获得", requiredMode = Schema.RequiredMode.REQUIRED, example = "hello") + @NotEmpty(message = "手机 code 不能为空") + private String phoneCode; + + @Schema(description = "登录 code,小程序通过 wx.login 方法获得", requiredMode = Schema.RequiredMode.REQUIRED, example = "word") + @NotEmpty(message = "登录 code 不能为空") + private String loginCode; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AuthWeixinJsapiSignatureRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AuthWeixinJsapiSignatureRespVO.java new file mode 100644 index 0000000..37e6365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AuthWeixinJsapiSignatureRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "用户 APP - 微信公众号 JSAPI 签名 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthWeixinJsapiSignatureRespVO { + + @Schema(description = "微信公众号的 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "hello") + private String appId; + + @Schema(description = "匿名串", requiredMode = Schema.RequiredMode.REQUIRED, example = "world") + private String nonceStr; + + @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long timestamp; + + @Schema(description = "URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private String url; + + @Schema(description = "签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "阿巴阿巴") + private String signature; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberExperienceRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberExperienceRecordController.java new file mode 100644 index 0000000..5c33e5c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberExperienceRecordController.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.member.controller.app.level; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.level.vo.experience.AppMemberExperienceRecordRespVO; +import cn.iocoder.yudao.module.member.convert.level.MemberExperienceRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import cn.iocoder.yudao.module.member.service.level.MemberExperienceRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 会员经验记录") +@RestController +@RequestMapping("/member/experience-record") +@Validated +public class AppMemberExperienceRecordController { + + @Resource + private MemberExperienceRecordService experienceLogService; + + @GetMapping("/page") + @Operation(summary = "获得会员经验记录分页") + @PreAuthenticated + public CommonResult> getExperienceRecordPage( + @Valid PageParam pageParam) { + PageResult pageResult = experienceLogService.getExperienceRecordPage( + getLoginUserId(), pageParam); + return success(MemberExperienceRecordConvert.INSTANCE.convertPage02(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberLevelController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberLevelController.java new file mode 100644 index 0000000..d4a4483 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/AppMemberLevelController.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.member.controller.app.level; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.app.level.vo.level.AppMemberLevelRespVO; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 会员等级") +@RestController +@RequestMapping("/member/level") +@Validated +public class AppMemberLevelController { + + @Resource + private MemberLevelService levelService; + + @GetMapping("/list") + @Operation(summary = "获得会员等级列表") + public CommonResult> getLevelList() { + List result = levelService.getEnableLevelList(); + return success(MemberLevelConvert.INSTANCE.convertList02(result)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/experience/AppMemberExperienceRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/experience/AppMemberExperienceRecordRespVO.java new file mode 100644 index 0000000..e2d7bb0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/experience/AppMemberExperienceRecordRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.member.controller.app.level.vo.experience; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 会员经验记录 Response VO") +@Data +public class AppMemberExperienceRecordRespVO { + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "增加经验") + private String title; + + @Schema(description = "经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer experience; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "下单增加 100 经验") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/level/AppMemberLevelRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/level/AppMemberLevelRespVO.java new file mode 100644 index 0000000..fdade17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/level/vo/level/AppMemberLevelRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.member.controller.app.level.vo.level; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 会员等级 Response VO") +@Data +public class AppMemberLevelRespVO { + + @Schema(description = "等级名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String name; + + @Schema(description = "等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer level; + + @Schema(description = "升级经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer experience; + + @Schema(description = "享受折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "98") + private Integer discountPercent; + + @Schema(description = "等级图标", example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + + @Schema(description = "等级背景图", example = "https://www.iocoder.cn/yudao.jpg") + private String backgroundUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/AppMemberPointRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/AppMemberPointRecordController.java new file mode 100644 index 0000000..3871b54 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/AppMemberPointRecordController.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.member.controller.app.point; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordRespVO; +import cn.iocoder.yudao.module.member.convert.point.MemberPointRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 签到记录") +@RestController +@RequestMapping("/member/point/record") +@Validated +public class AppMemberPointRecordController { + + @Resource + private MemberPointRecordService pointRecordService; + + @GetMapping("/page") + @Operation(summary = "获得用户积分记录分页") + @PreAuthenticated + public CommonResult> getPointRecordPage( + @Valid AppMemberPointRecordPageReqVO pageReqVO) { + PageResult pageResult = pointRecordService.getPointRecordPage(getLoginUserId(), pageReqVO); + return success(BeanUtils.toBean(pageResult, AppMemberPointRecordRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordPageReqVO.java new file mode 100644 index 0000000..5e51ce6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.member.controller.app.point.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "用户 App - 用户积分记录分页 Request VO") +@Data +public class AppMemberPointRecordPageReqVO extends PageParam { + + @Schema(description = "是否增加积分", example = "true") + private Boolean addStatus; // true - 增加;false - 减少;null - 不筛选 + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordRespVO.java new file mode 100644 index 0000000..51bbe7b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/point/vo/AppMemberPointRecordRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.app.point.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 用户积分记录 Response VO") +@Data +public class AppMemberPointRecordRespVO { + + @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "31457") + private Long id; + + @Schema(description = "积分标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String title; + + @Schema(description = "积分描述", example = "你猜") + private String description; + + @Schema(description = "积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer point; + + @Schema(description = "发生时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInConfigController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInConfigController.java new file mode 100644 index 0000000..62a52e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInConfigController.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.member.controller.app.signin; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.config.AppMemberSignInConfigRespVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInConfigConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import cn.iocoder.yudao.module.member.service.signin.MemberSignInConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 签到规则") +@RestController +@RequestMapping("/member/sign-in/config") +@Validated +public class AppMemberSignInConfigController { + + @Resource + private MemberSignInConfigService signInConfigService; + + @GetMapping("/list") + @Operation(summary = "获得签到规则列表") + public CommonResult> getSignInConfigList() { + List pageResult = signInConfigService.getSignInConfigList(CommonStatusEnum.ENABLE.getStatus()); + return success(MemberSignInConfigConvert.INSTANCE.convertList02(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java new file mode 100644 index 0000000..2f7afa0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.member.controller.app.signin; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 签到记录") +@RestController +@RequestMapping("/member/sign-in/record") +@Validated +public class AppMemberSignInRecordController { + + @Resource + private MemberSignInRecordService signInRecordService; + + @GetMapping("/get-summary") + @Operation(summary = "获得个人签到统计") + @PreAuthenticated + public CommonResult getSignInRecordSummary() { + return success(signInRecordService.getSignInRecordSummary(getLoginUserId())); + } + + @PostMapping("/create") + @Operation(summary = "签到") + @PreAuthenticated + public CommonResult createSignInRecord() { + MemberSignInRecordDO recordDO = signInRecordService.createSignRecord(getLoginUserId()); + return success(MemberSignInRecordConvert.INSTANCE.coverRecordToAppRecordVo(recordDO)); + } + + @GetMapping("/page") + @Operation(summary = "获得签到记录分页") + @PreAuthenticated + public CommonResult> getSignRecordPage(PageParam pageParam) { + PageResult pageResult = signInRecordService.getSignRecordPage(getLoginUserId(), pageParam); + return success(MemberSignInRecordConvert.INSTANCE.convertPage02(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/config/AppMemberSignInConfigRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/config/AppMemberSignInConfigRespVO.java new file mode 100644 index 0000000..a18d3a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/config/AppMemberSignInConfigRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.member.controller.app.signin.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 签到规则 Response VO") +@Data +public class AppMemberSignInConfigRespVO { + + @Schema(description = "签到第 x 天", requiredMode = Schema.RequiredMode.REQUIRED, example = "7") + private Integer day; + + @Schema(description = "奖励积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer point; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordRespVO.java new file mode 100644 index 0000000..2d910d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.member.controller.app.signin.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 App - 签到记录 Response VO") +@Data +public class AppMemberSignInRecordRespVO { + + @Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer day; + + @Schema(description = "签到的分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer point; + + @Schema(description = "签到的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer experience; + + @Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordSummaryRespVO.java new file mode 100644 index 0000000..30fb66a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/record/AppMemberSignInRecordSummaryRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.controller.app.signin.vo.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 App - 个人签到统计 Response VO") +@Data +public class AppMemberSignInRecordSummaryRespVO { + + @Schema(description = "总签到天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer totalDay; + + @Schema(description = "连续签到第 x 天", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private Integer continuousDay; + + @Schema(description = "今天是否已签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean todaySignIn; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java new file mode 100644 index 0000000..3dad97b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.member.controller.app.social; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserBindReqVO; +import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserRespVO; +import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; +import cn.iocoder.yudao.module.system.api.social.SocialUserApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 App - 社交用户") +@RestController +@RequestMapping("/member/social-user") +@Validated +public class AppSocialUserController { + + @Resource + private SocialUserApi socialUserApi; + + @PostMapping("/bind") + @Operation(summary = "社交绑定,使用 code 授权码") + public CommonResult socialBind(@RequestBody @Valid AppSocialUserBindReqVO reqVO) { + SocialUserBindReqDTO reqDTO = new SocialUserBindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(), + reqVO.getType(), reqVO.getCode(), reqVO.getState()); + String openid = socialUserApi.bindSocialUser(reqDTO); + return success(openid); + } + + @DeleteMapping("/unbind") + @Operation(summary = "取消社交绑定") + @PreAuthenticated + public CommonResult socialUnbind(@RequestBody AppSocialUserUnbindReqVO reqVO) { + SocialUserUnbindReqDTO reqDTO = new SocialUserUnbindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(), + reqVO.getType(), reqVO.getOpenid()); + socialUserApi.unbindSocialUser(reqDTO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得社交用户") + @Parameter(name = "type", description = "社交平台的类型,参见 SocialTypeEnum 枚举值", required = true, example = "10") + @PreAuthenticated + public CommonResult getSocialUser(@RequestParam("type") Integer type) { + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), getLoginUserId(), type); + return success(BeanUtils.toBean(socialUser, AppSocialUserRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserBindReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserBindReqVO.java new file mode 100644 index 0000000..2893363 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserBindReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.controller.app.social.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 APP - 社交绑定 Request VO,使用 code 授权码") +@Data +public class AppSocialUserBindReqVO { + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserRespVO.java new file mode 100644 index 0000000..f37ced8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.member.controller.app.social.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 社交用户 Response VO") +@Data +public class AppSocialUserRespVO { + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + private String openid; + + @Schema(description = "社交用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String nickname; + + @Schema(description = "社交用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String avatar; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserUnbindReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserUnbindReqVO.java new file mode 100644 index 0000000..7409ab2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserUnbindReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.app.social.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 APP - 取消社交绑定 Request VO") +@Data +public class AppSocialUserUnbindReqVO { + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + @NotEmpty(message = "社交用户的 openid 不能为空") + private String openid; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.http b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.http new file mode 100644 index 0000000..745556f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.http @@ -0,0 +1,4 @@ +### 请求 /member/user/profile/get 接口 => 没有权限 +GET {{appApi}}/member/user/get +Authorization: Bearer test245 +tenant-id: {{appTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java new file mode 100644 index 0000000..3a268e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.member.controller.app.user; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.member.controller.app.user.vo.*; +import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 用户个人中心") +@RestController +@RequestMapping("/member/user") +@Validated +@Slf4j +public class AppMemberUserController { + + @Resource + private MemberUserService userService; + @Resource + private MemberLevelService levelService; + + @GetMapping("/get") + @Operation(summary = "获得基本信息") + @PreAuthenticated + public CommonResult getUserInfo() { + MemberUserDO user = userService.getUser(getLoginUserId()); + MemberLevelDO level = levelService.getLevel(user.getLevelId()); + return success(MemberUserConvert.INSTANCE.convert(user, level)); + } + + @PutMapping("/update") + @Operation(summary = "修改基本信息") + @PreAuthenticated + public CommonResult updateUser(@RequestBody @Valid AppMemberUserUpdateReqVO reqVO) { + userService.updateUser(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-mobile") + @Operation(summary = "修改用户手机") + @PreAuthenticated + public CommonResult updateUserMobile(@RequestBody @Valid AppMemberUserUpdateMobileReqVO reqVO) { + userService.updateUserMobile(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-mobile-by-weixin") + @Operation(summary = "基于微信小程序的授权码,修改用户手机") + @PreAuthenticated + public CommonResult updateUserMobileByWeixin(@RequestBody @Valid AppMemberUserUpdateMobileByWeixinReqVO reqVO) { + userService.updateUserMobileByWeixin(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-password") + @Operation(summary = "修改用户密码", description = "用户修改密码时使用") + @PreAuthenticated + public CommonResult updateUserPassword(@RequestBody @Valid AppMemberUserUpdatePasswordReqVO reqVO) { + userService.updateUserPassword(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/reset-password") + @Operation(summary = "重置密码", description = "用户忘记密码时使用") + public CommonResult resetUserPassword(@RequestBody @Valid AppMemberUserResetPasswordReqVO reqVO) { + userService.resetUserPassword(reqVO); + return success(true); + } + +} + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java new file mode 100644 index 0000000..fa05e16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "用户 APP - 用户个人信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AppMemberUserInfoRespVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "用户手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + private String mobile; + + @Schema(description = "用户性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sex; + + @Schema(description = "积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer point; + + @Schema(description = "经验值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer experience; + + @Schema(description = "用户等级") + private Level level; + + @Schema(description = "是否成为推广员", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean brokerageEnabled; + + @Schema(description = "用户 App - 会员等级") + @Data + public static class Level { + + @Schema(description = "等级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "等级名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String name; + + @Schema(description = "等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer level; + + @Schema(description = "等级图标", example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserResetPasswordReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserResetPasswordReqVO.java new file mode 100644 index 0000000..22cbf55 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserResetPasswordReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 重置密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppMemberUserResetPasswordReqVO { + + @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") + @NotEmpty(message = "新密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + + @Schema(description = "手机号",requiredMode = Schema.RequiredMode.REQUIRED,example = "15878962356") + @NotBlank(message = "手机号不能为空") + @Mobile + private String mobile; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileByWeixinReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileByWeixinReqVO.java new file mode 100644 index 0000000..0ba49a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileByWeixinReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "用户 APP - 基于微信小程序的授权码,修改手机 Request VO") +@Data +public class AppMemberUserUpdateMobileByWeixinReqVO { + + @Schema(description = "手机 code,小程序通过 wx.getPhoneNumber 方法获得", + requiredMode = Schema.RequiredMode.REQUIRED, example = "hello") + @NotEmpty(message = "手机 code 不能为空") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileReqVO.java new file mode 100644 index 0000000..a722365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateMobileReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 修改手机 Request VO") +@Data +public class AppMemberUserUpdateMobileReqVO { + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + + @Schema(description = "手机号",requiredMode = Schema.RequiredMode.REQUIRED, example = "15823654487") + @NotBlank(message = "手机号不能为空") + @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") + @Mobile + private String mobile; + + @Schema(description = "原手机验证码", example = "1024") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String oldCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdatePasswordReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdatePasswordReqVO.java new file mode 100644 index 0000000..cc78ca8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdatePasswordReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 修改密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AppMemberUserUpdatePasswordReqVO { + + @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") + @NotEmpty(message = "新密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java new file mode 100644 index 0000000..cca08e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.member.controller.app.user.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +@Schema(description = "用户 App - 会员用户更新 Request VO") +@Data +public class AppMemberUserUpdateReqVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String nickname; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/x.png") + @URL(message = "头像必须是 URL 格式") + private String avatar; + + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sex; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/package-info.java new file mode 100644 index 0000000..9e2888c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.member.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java new file mode 100644 index 0000000..39dc9fa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.member.convert.address; + +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; +import cn.iocoder.yudao.module.member.controller.admin.address.vo.AddressRespVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 用户收件地址 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface AddressConvert { + + AddressConvert INSTANCE = Mappers.getMapper(AddressConvert.class); + + MemberAddressDO convert(AppAddressCreateReqVO bean); + + MemberAddressDO convert(AppAddressUpdateReqVO bean); + + @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName") + AppAddressRespVO convert(MemberAddressDO bean); + + List convertList(List list); + + MemberAddressRespDTO convert02(MemberAddressDO bean); + + @Named("convertAreaIdToAreaName") + default String convertAreaIdToAreaName(Integer areaId) { + return AreaUtils.format(areaId); + } + + List convertList2(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java new file mode 100644 index 0000000..29e8f4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.convert.auth; + +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; +import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface AuthConvert { + + AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); + + SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialLoginReqVO reqVO); + SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO); + + SmsCodeSendReqDTO convert(AppAuthSmsSendReqVO reqVO); + SmsCodeUseReqDTO convert(AppMemberUserResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); + SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); + + AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean, String openid); + + SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); + + SocialWxJsapiSignatureRespDTO convert(SocialWxJsapiSignatureRespDTO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/config/MemberConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/config/MemberConfigConvert.java new file mode 100644 index 0000000..9847645 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/config/MemberConfigConvert.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.member.convert.config; + +import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO; +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigRespVO; +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 会员配置 Convert + * + * @author QingX + */ +@Mapper +public interface MemberConfigConvert { + + MemberConfigConvert INSTANCE = Mappers.getMapper(MemberConfigConvert.class); + + MemberConfigRespVO convert(MemberConfigDO bean); + + MemberConfigDO convert(MemberConfigSaveReqVO bean); + + MemberConfigRespDTO convert01(MemberConfigDO config); +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/group/MemberGroupConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/group/MemberGroupConvert.java new file mode 100644 index 0000000..06f49d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/group/MemberGroupConvert.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.convert.group; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupRespVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupSimpleRespVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 用户分组 Convert + * + * @author owen + */ +@Mapper +public interface MemberGroupConvert { + + MemberGroupConvert INSTANCE = Mappers.getMapper(MemberGroupConvert.class); + + MemberGroupDO convert(MemberGroupCreateReqVO bean); + + MemberGroupDO convert(MemberGroupUpdateReqVO bean); + + MemberGroupRespVO convert(MemberGroupDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertSimpleList(List list); +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberExperienceRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberExperienceRecordConvert.java new file mode 100644 index 0000000..93f864f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberExperienceRecordConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.member.convert.level; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordRespVO; +import cn.iocoder.yudao.module.member.controller.app.level.vo.experience.AppMemberExperienceRecordRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 会员经验记录 Convert + * + * @author owen + */ +@Mapper +public interface MemberExperienceRecordConvert { + + MemberExperienceRecordConvert INSTANCE = Mappers.getMapper(MemberExperienceRecordConvert.class); + + MemberExperienceRecordRespVO convert(MemberExperienceRecordDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + MemberExperienceRecordDO convert(Long userId, Integer experience, Integer totalExperience, + String bizId, Integer bizType, + String title, String description); + + PageResult convertPage02(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelConvert.java new file mode 100644 index 0000000..f228281 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelConvert.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.member.convert.level; + +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelRespVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelSimpleRespVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.app.level.vo.level.AppMemberLevelRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 会员等级 Convert + * + * @author owen + */ +@Mapper +public interface MemberLevelConvert { + + MemberLevelConvert INSTANCE = Mappers.getMapper(MemberLevelConvert.class); + + MemberLevelDO convert(MemberLevelCreateReqVO bean); + + MemberLevelDO convert(MemberLevelUpdateReqVO bean); + + MemberLevelRespVO convert(MemberLevelDO bean); + + List convertList(List list); + + List convertSimpleList(List list); + + List convertList02(List list); + + MemberLevelRespDTO convert02(MemberLevelDO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelRecordConvert.java new file mode 100644 index 0000000..d01f1b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/level/MemberLevelRecordConvert.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.member.convert.level; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 会员等级记录 Convert + * + * @author owen + */ +@Mapper +public interface MemberLevelRecordConvert { + + MemberLevelRecordConvert INSTANCE = Mappers.getMapper(MemberLevelRecordConvert.class); + + MemberLevelRecordRespVO convert(MemberLevelRecordDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default MemberLevelRecordDO copyTo(MemberLevelDO from, MemberLevelRecordDO to) { + if (from != null) { + to.setLevelId(from.getId()); + to.setLevel(from.getLevel()); + to.setDiscountPercent(from.getDiscountPercent()); + to.setExperience(from.getExperience()); + } + return to; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/package-info.java new file mode 100644 index 0000000..6523a66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.member.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointRecordConvert.java new file mode 100644 index 0000000..896ae35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/point/MemberPointRecordConvert.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.member.convert.point; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordRespVO; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 用户积分记录 Convert + * + * @author QingX + */ +@Mapper +public interface MemberPointRecordConvert { + + MemberPointRecordConvert INSTANCE = Mappers.getMapper(MemberPointRecordConvert.class); + + default PageResult convertPage(PageResult pageResult, List users) { + PageResult voPageResult = convertPage(pageResult); + // user 拼接 + Map userMap = convertMap(users, MemberUserDO::getId); + voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(), + memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname()))); + return voPageResult; + } + PageResult convertPage(PageResult pageResult); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInConfigConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInConfigConvert.java new file mode 100644 index 0000000..5acd871 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInConfigConvert.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.member.convert.signin; + +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigRespVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.config.AppMemberSignInConfigRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 签到规则 Convert + * + * @author QingX + */ +@Mapper +public interface MemberSignInConfigConvert { + + MemberSignInConfigConvert INSTANCE = Mappers.getMapper(MemberSignInConfigConvert.class); + + MemberSignInConfigDO convert(MemberSignInConfigCreateReqVO bean); + + MemberSignInConfigDO convert(MemberSignInConfigUpdateReqVO bean); + + MemberSignInConfigRespVO convert(MemberSignInConfigDO bean); + + List convertList(List list); + + List convertList02(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java new file mode 100644 index 0000000..9da5927 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.member.convert.signin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * 签到记录 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface MemberSignInRecordConvert { + + MemberSignInRecordConvert INSTANCE = Mappers.getMapper(MemberSignInRecordConvert.class); + + default PageResult convertPage(PageResult pageResult, List users) { + PageResult voPageResult = convertPage(pageResult); + // user 拼接 + Map userMap = convertMap(users, MemberUserDO::getId); + voPageResult.getList().forEach(record -> MapUtils.findAndThen(userMap, record.getUserId(), + memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname()))); + return voPageResult; + } + + PageResult convertPage(PageResult pageResult); + + PageResult convertPage02(PageResult pageResult); + + AppMemberSignInRecordRespVO coverRecordToAppRecordVo(MemberSignInRecordDO memberSignInRecordDO); + + default MemberSignInRecordDO convert(Long userId, MemberSignInRecordDO lastRecord, List configs) { + // 1. 计算是第几天签到 + configs.sort(Comparator.comparing(MemberSignInConfigDO::getDay)); + MemberSignInConfigDO lastConfig = CollUtil.getLast(configs); // 最大签到天数配置 + // 1.2. 计算今天是第几天签到 (只有连续签到才加否则重置为 1) + int day = 1; + if (lastRecord != null && DateUtils.isYesterday(lastRecord.getCreateTime())) { + day = lastRecord.getDay() + 1; + } + // 1.3 判断是否超出了最大签到配置 + if (day > lastConfig.getDay()) { + day = 1; // 超过最大配置的天数,重置到第一天。(也就是说开启下一轮签到) + } + + // 2.1 初始化签到信息 + MemberSignInRecordDO record = new MemberSignInRecordDO().setUserId(userId) + .setDay(day).setPoint(0).setExperience(0); + // 2.2 获取签到对应的积分 + MemberSignInConfigDO config = CollUtil.findOne(configs, item -> ObjUtil.equal(item.getDay(), record.getDay())); + if (config == null) { + return record; + } + record.setPoint(config.getPoint()); + record.setExperience(config.getExperience()); + return record; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/tag/MemberTagConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/tag/MemberTagConvert.java new file mode 100644 index 0000000..9d3a41f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/tag/MemberTagConvert.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.member.convert.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagRespVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 会员标签 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface MemberTagConvert { + + MemberTagConvert INSTANCE = Mappers.getMapper(MemberTagConvert.class); + + MemberTagDO convert(MemberTagCreateReqVO bean); + + MemberTagDO convert(MemberTagUpdateReqVO bean); + + MemberTagRespVO convert(MemberTagDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java new file mode 100644 index 0000000..aae9a76 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.member.convert.user; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserInfoRespVO; +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +@Mapper(uses = {AddressConvert.class}) +public interface MemberUserConvert { + + MemberUserConvert INSTANCE = Mappers.getMapper(MemberUserConvert.class); + + AppMemberUserInfoRespVO convert(MemberUserDO bean); + + @Mapping(source = "level", target = "level") + @Mapping(source = "bean.experience", target = "experience") + AppMemberUserInfoRespVO convert(MemberUserDO bean, MemberLevelDO level); + + MemberUserRespDTO convert2(MemberUserDO bean); + + List convertList2(List list); + + MemberUserDO convert(MemberUserUpdateReqVO bean); + + PageResult convertPage(PageResult page); + + @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName") + MemberUserRespVO convert03(MemberUserDO bean); + + default PageResult convertPage(PageResult pageResult, + List tags, + List levels, + List groups) { + PageResult result = convertPage(pageResult); + // 处理关联数据 + Map tagMap = convertMap(tags, MemberTagDO::getId, MemberTagDO::getName); + Map levelMap = convertMap(levels, MemberLevelDO::getId, MemberLevelDO::getName); + Map groupMap = convertMap(groups, MemberGroupDO::getId, MemberGroupDO::getName); + // 填充关联数据 + result.getList().forEach(user -> { + user.setTagNames(convertList(user.getTagIds(), tagMap::get)); + user.setLevelName(levelMap.get(user.getLevelId())); + user.setGroupName(groupMap.get(user.getGroupId())); + }); + return result; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java new file mode 100644 index 0000000..f2e43b5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.address; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 用户收件地址 DO + * + * @author 芋道源码 + */ +@TableName("member_address") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberAddressDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 收件人名称 + */ + private String name; + /** + * 手机号 + */ + private String mobile; + /** + * 地区编号 + */ + private Long areaId; + /** + * 收件详细地址 + */ + private String detailAddress; + /** + * 是否默认 + * + * true - 默认收件地址 + */ + private Boolean defaultStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/config/MemberConfigDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/config/MemberConfigDO.java new file mode 100644 index 0000000..6efb4a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/config/MemberConfigDO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.config; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 会员配置 DO + * + * @author QingX + */ +@TableName(value = "member_config", autoResultMap = true) +@KeySequence("member_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberConfigDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 积分抵扣开关 + */ + private Boolean pointTradeDeductEnable; + /** + * 积分抵扣,单位:分 + * + * 1 积分抵扣多少分 + */ + private Integer pointTradeDeductUnitPrice; + /** + * 积分抵扣最大值 + */ + private Integer pointTradeDeductMaxPrice; + /** + * 1 元赠送多少分 + */ + private Integer pointTradeGivePoint; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/group/MemberGroupDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/group/MemberGroupDO.java new file mode 100644 index 0000000..c9a82ab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/group/MemberGroupDO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.group; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 用户分组 DO + * + * @author owen + */ +@TableName("member_group") +@KeySequence("member_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberGroupDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 名称 + */ + private String name; + /** + * 备注 + */ + private String remark; + /** + * 状态 + *

+ * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberExperienceRecordDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberExperienceRecordDO.java new file mode 100644 index 0000000..d7c06d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberExperienceRecordDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.level; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 会员经验记录 DO + * + * @author owen + */ +@TableName("member_experience_record") +@KeySequence("member_experience_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberExperienceRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 {@link MemberUserDO#getId()} 字段 + */ + private Long userId; + /** + * 业务类型 + *

+ * 枚举 {@link MemberExperienceBizTypeEnum} + */ + private Integer bizType; + /** + * 业务编号 + */ + private String bizId; + /** + * 标题 + */ + private String title; + /** + * 描述 + */ + private String description; + /** + * 经验 + */ + private Integer experience; + /** + * 变更后的经验 + */ + private Integer totalExperience; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelDO.java new file mode 100644 index 0000000..05035ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelDO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.level; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 会员等级 DO + * + * 配置每个等级需要的积分 + * + * @author owen + */ +@TableName("member_level") +@KeySequence("member_level_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberLevelDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 等级名称 + */ + private String name; + /** + * 等级 + */ + private Integer level; + /** + * 升级经验 + */ + private Integer experience; + /** + * 享受折扣 + */ + private Integer discountPercent; + + /** + * 等级图标 + */ + private String icon; + /** + * 等级背景图 + */ + private String backgroundUrl; + /** + * 状态 + *

+ * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java new file mode 100644 index 0000000..8b5451d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.level; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 会员等级记录 DO + * + * 用户每次等级发生变更时,记录一条日志 + * + * @author owen + */ +@TableName("member_level_record") +@KeySequence("member_level_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberLevelRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 {@link MemberUserDO#getId()} 字段 + */ + private Long userId; + /** + * 等级编号 + * + * 关联 {@link MemberLevelDO#getId()} 字段 + */ + private Long levelId; + /** + * 会员等级 + * + * 冗余 {@link MemberLevelDO#getLevel()} 字段 + */ + private Integer level; + /** + * 享受折扣 + */ + private Integer discountPercent; + /** + * 升级经验 + */ + private Integer experience; + /** + * 会员此时的经验 + */ + private Integer userExperience; + /** + * 备注 + */ + private String remark; + /** + * 描述 + */ + private String description; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/point/MemberPointRecordDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/point/MemberPointRecordDO.java new file mode 100644 index 0000000..f884f08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/point/MemberPointRecordDO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.point; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 用户积分记录 DO + * + * @author QingX + */ +@TableName("member_point_record") +@KeySequence("member_point_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberPointRecordDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 对应 MemberUserDO 的 id 属性 + */ + private Long userId; + + /** + * 业务编码 + */ + private String bizId; + /** + * 业务类型 + * + * 枚举 {@link MemberPointBizTypeEnum} + */ + private Integer bizType; + + /** + * 积分标题 + */ + private String title; + /** + * 积分描述 + */ + private String description; + + /** + * 变动积分 + * + * 1、正数表示获得积分 + * 2、负数表示消耗积分 + */ + private Integer point; + /** + * 变动后的积分 + */ + private Integer totalPoint; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInConfigDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInConfigDO.java new file mode 100644 index 0000000..76d55c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInConfigDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.signin; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 签到规则 DO + * + * @author QingX + */ +@TableName("member_sign_in_config") +@KeySequence("member_sign_in_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberSignInConfigDO extends BaseDO { + + /** + * 规则自增主键 + */ + @TableId + private Long id; + /** + * 签到第 x 天 + */ + private Integer day; + /** + * 奖励积分 + */ + private Integer point; + /** + * 奖励经验 + */ + private Integer experience; + + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInRecordDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInRecordDO.java new file mode 100644 index 0000000..b07b5ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/signin/MemberSignInRecordDO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.signin; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 签到记录 DO + * + * @author 芋道源码 + */ +@TableName("member_sign_in_record") +@KeySequence("member_sign_in_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberSignInRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 签到用户 + */ + private Long userId; + /** + * 第几天签到 + */ + private Integer day; + /** + * 签到的积分 + */ + private Integer point; + /** + * 签到的经验 + */ + private Integer experience; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/tag/MemberTagDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/tag/MemberTagDO.java new file mode 100644 index 0000000..b984064 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/tag/MemberTagDO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.tag; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 会员标签 DO + * + * @author 芋道源码 + */ +@TableName("member_tag") +@KeySequence("member_tag_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberTagDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 标签名称 + */ + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java new file mode 100644 index 0000000..97ddc19 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.member.dal.dataobject.user; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 会员用户 DO + * + * uk_mobile 索引:基于 {@link #mobile} 字段 + * + * @author 芋道源码 + */ +@TableName(value = "member_user", autoResultMap = true) +@KeySequence("member_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberUserDO extends TenantBaseDO { + + // ========== 账号信息 ========== + + /** + * 用户ID + */ + @TableId + private Long id; + /** + * 手机 + */ + private String mobile; + /** + * 加密后的密码 + * + * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐 + */ + private String password; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 注册 IP + */ + private String registerIp; + /** + * 注册终端 + * 枚举 {@link TerminalEnum} + */ + private Integer registerTerminal; + /** + * 最后登录IP + */ + private String loginIp; + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + + // ========== 基础信息 ========== + + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户头像 + */ + private String avatar; + + /** + * 真实名字 + */ + private String name; + /** + * 性别 + * + * 枚举 {@link SexEnum} + */ + private Integer sex; + /** + * 出生日期 + */ + private LocalDateTime birthday; + /** + * 所在地 + * + * 关联 {@link Area#getId()} 字段 + */ + private Integer areaId; + /** + * 用户备注 + */ + private String mark; + + // ========== 其它信息 ========== + + /** + * 积分 + */ + private Integer point; + // TODO 疯狂:增加一个 totalPoint;个人信息接口要返回 + + /** + * 会员标签列表,以逗号分隔 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List tagIds; + + /** + * 会员级别编号 + * + * 关联 {@link MemberLevelDO#getId()} 字段 + */ + private Long levelId; + /** + * 会员经验 + */ + private Integer experience; + /** + * 用户分组编号 + * + * 关联 {@link MemberGroupDO#getId()} 字段 + */ + private Long groupId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/MemberAddressMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/MemberAddressMapper.java new file mode 100644 index 0000000..3df68c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/MemberAddressMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.member.dal.mysql.address; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MemberAddressMapper extends BaseMapperX { + + default MemberAddressDO selectByIdAndUserId(Long id, Long userId) { + return selectOne(MemberAddressDO::getId, id, MemberAddressDO::getUserId, userId); + } + + default List selectListByUserIdAndDefaulted(Long userId, Boolean defaulted) { + return selectList(new LambdaQueryWrapperX().eq(MemberAddressDO::getUserId, userId) + .eqIfPresent(MemberAddressDO::getDefaultStatus, defaulted)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/config/MemberConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/config/MemberConfigMapper.java new file mode 100644 index 0000000..e039383 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/config/MemberConfigMapper.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.member.dal.mysql.config; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 积分设置 Mapper + * + * @author QingX + */ +@Mapper +public interface MemberConfigMapper extends BaseMapperX { +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/group/MemberGroupMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/group/MemberGroupMapper.java new file mode 100644 index 0000000..da4f7b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/group/MemberGroupMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.dal.mysql.group; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户分组 Mapper + * + * @author owen + */ +@Mapper +public interface MemberGroupMapper extends BaseMapperX { + + default PageResult selectPage(MemberGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MemberGroupDO::getName, reqVO.getName()) + .eqIfPresent(MemberGroupDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(MemberGroupDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MemberGroupDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(MemberGroupDO::getStatus, status); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberExperienceRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberExperienceRecordMapper.java new file mode 100644 index 0000000..4e5f6f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberExperienceRecordMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.dal.mysql.level; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 会员经验记录 Mapper + * + * @author owen + */ +@Mapper +public interface MemberExperienceRecordMapper extends BaseMapperX { + + default PageResult selectPage(MemberExperienceRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MemberExperienceRecordDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MemberExperienceRecordDO::getBizId, reqVO.getBizId()) + .eqIfPresent(MemberExperienceRecordDO::getBizType, reqVO.getBizType()) + .eqIfPresent(MemberExperienceRecordDO::getTitle, reqVO.getTitle()) + .betweenIfPresent(MemberExperienceRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MemberExperienceRecordDO::getId)); + } + + default PageResult selectPage(Long userId, PageParam pageParam) { + return selectPage(pageParam, new LambdaQueryWrapper() + .eq(MemberExperienceRecordDO::getUserId, userId) + .orderByDesc(MemberExperienceRecordDO::getId)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelMapper.java new file mode 100644 index 0000000..d2dcb6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.member.dal.mysql.level; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelListReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 会员等级 Mapper + * + * @author owen + */ +@Mapper +public interface MemberLevelMapper extends BaseMapperX { + + default List selectList(MemberLevelListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(MemberLevelDO::getName, reqVO.getName()) + .eqIfPresent(MemberLevelDO::getStatus, reqVO.getStatus()) + .orderByAsc(MemberLevelDO::getLevel)); + } + + + default List selectListByStatus(Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(MemberLevelDO::getStatus, status) + .orderByAsc(MemberLevelDO::getLevel)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelRecordMapper.java new file mode 100644 index 0000000..6808b95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/level/MemberLevelRecordMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.member.dal.mysql.level; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 会员等级记录 Mapper + * + * @author owen + */ +@Mapper +public interface MemberLevelRecordMapper extends BaseMapperX { + + default PageResult selectPage(MemberLevelRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MemberLevelRecordDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MemberLevelRecordDO::getLevelId, reqVO.getLevelId()) + .betweenIfPresent(MemberLevelRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MemberLevelRecordDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/point/MemberPointRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/point/MemberPointRecordMapper.java new file mode 100644 index 0000000..d0e2452 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/point/MemberPointRecordMapper.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.member.dal.mysql.point; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Set; + +/** + * 用户积分记录 Mapper + * + * @author QingX + */ +@Mapper +public interface MemberPointRecordMapper extends BaseMapperX { + + default PageResult selectPage(MemberPointRecordPageReqVO reqVO, Set userIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .inIfPresent(MemberPointRecordDO::getUserId, userIds) + .eqIfPresent(MemberPointRecordDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MemberPointRecordDO::getBizType, reqVO.getBizType()) + .likeIfPresent(MemberPointRecordDO::getTitle, reqVO.getTitle()) + .orderByDesc(MemberPointRecordDO::getId)); + } + + default PageResult selectPage(Long userId, AppMemberPointRecordPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(MemberPointRecordDO::getUserId, userId) + .betweenIfPresent(MemberPointRecordDO::getCreateTime, pageReqVO.getCreateTime()) + .gt(Boolean.TRUE.equals(pageReqVO.getAddStatus()), + MemberPointRecordDO::getPoint, 0) + .lt(Boolean.FALSE.equals(pageReqVO.getAddStatus()), + MemberPointRecordDO::getPoint, 0) + .orderByDesc(MemberPointRecordDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInConfigMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInConfigMapper.java new file mode 100644 index 0000000..211ead3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInConfigMapper.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.member.dal.mysql.signin; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 签到规则 Mapper + * + * @author QingX + */ +@Mapper +public interface MemberSignInConfigMapper extends BaseMapperX { + + default MemberSignInConfigDO selectByDay(Integer day) { + return selectOne(MemberSignInConfigDO::getDay, day); + } + + default List selectListByStatus(Integer status) { + return selectList(MemberSignInConfigDO::getStatus, status); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java new file mode 100644 index 0000000..36400b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.member.dal.mysql.signin; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Set; + +/** + * 签到记录 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MemberSignInRecordMapper extends BaseMapperX { + + default PageResult selectPage(MemberSignInRecordPageReqVO reqVO, Set userIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .inIfPresent(MemberSignInRecordDO::getUserId, userIds) + .eqIfPresent(MemberSignInRecordDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MemberSignInRecordDO::getDay, reqVO.getDay()) + .betweenIfPresent(MemberSignInRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MemberSignInRecordDO::getId)); + } + + default PageResult selectPage(Long userId, PageParam pageParam) { + return selectPage(pageParam, new LambdaQueryWrapperX() + .eq(MemberSignInRecordDO::getUserId, userId) + .orderByDesc(MemberSignInRecordDO::getId)); + } + + /** + * 获取用户最近的签到记录信息,根据签到时间倒序 + * + * @param userId 用户编号 + * @return 签到记录列表 + */ + default MemberSignInRecordDO selectLastRecordByUserId(Long userId) { + return selectOne(new QueryWrapper() + .eq("user_id", userId) + .orderByDesc("create_time") + .last("limit 1")); + } + + default Long selectCountByUserId(Long userId) { + return selectCount(MemberSignInRecordDO::getUserId, userId); + } + + /** + * 获取用户的签到记录列表信息 + * + * @param userId 用户编号 + * @return 签到记录信息 + */ + default List selectListByUserId(Long userId) { + return selectList(MemberSignInRecordDO::getUserId, userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/tag/MemberTagMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/tag/MemberTagMapper.java new file mode 100644 index 0000000..f4723e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/tag/MemberTagMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.member.dal.mysql.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 会员标签 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MemberTagMapper extends BaseMapperX { + + default PageResult selectPage(MemberTagPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MemberTagDO::getName, reqVO.getName()) + .betweenIfPresent(MemberTagDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MemberTagDO::getId)); + } + + default MemberTagDO selelctByName(String name) { + return selectOne(MemberTagDO::getName, name); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java new file mode 100644 index 0000000..3f87102 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.member.dal.mysql.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 会员 User Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MemberUserMapper extends BaseMapperX { + + default MemberUserDO selectByMobile(String mobile) { + return selectOne(MemberUserDO::getMobile, mobile); + } + + default List selectListByNicknameLike(String nickname) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(MemberUserDO::getNickname, nickname)); + } + + default PageResult selectPage(MemberUserPageReqVO reqVO) { + // 处理 tagIds 过滤条件 + String tagIdSql = ""; + if (CollUtil.isNotEmpty(reqVO.getTagIds())) { + tagIdSql = reqVO.getTagIds().stream() + .map(tagId -> "FIND_IN_SET(" + tagId + ", tag_ids)") + .collect(Collectors.joining(" OR ")); + } + // 分页查询 + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MemberUserDO::getMobile, reqVO.getMobile()) + .betweenIfPresent(MemberUserDO::getLoginDate, reqVO.getLoginDate()) + .likeIfPresent(MemberUserDO::getNickname, reqVO.getNickname()) + .betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(MemberUserDO::getLevelId, reqVO.getLevelId()) + .eqIfPresent(MemberUserDO::getGroupId, reqVO.getGroupId()) + .apply(StrUtil.isNotEmpty(tagIdSql), tagIdSql) + .orderByDesc(MemberUserDO::getId)); + } + + default Long selectCountByGroupId(Long groupId) { + return selectCount(MemberUserDO::getGroupId, groupId); + } + + default Long selectCountByLevelId(Long levelId) { + return selectCount(MemberUserDO::getLevelId, levelId); + } + + default Long selectCountByTagId(Long tagId) { + return selectCount(new LambdaQueryWrapperX() + .apply("FIND_IN_SET({0}, tag_ids)", tagId)); + } + + /** + * 更新用户积分(增加) + * + * @param id 用户编号 + * @param incrCount 增加积分(正数) + */ + default void updatePointIncr(Long id, Integer incrCount) { + Assert.isTrue(incrCount > 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" point = point + " + incrCount) + .eq(MemberUserDO::getId, id); + update(null, lambdaUpdateWrapper); + } + + /** + * 更新用户积分(减少) + * + * @param id 用户编号 + * @param incrCount 增加积分(负数) + * @return 更新行数 + */ + default int updatePointDecr(Long id, Integer incrCount) { + Assert.isTrue(incrCount < 0); + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" point = point + " + incrCount) // 负数,所以使用 + 号 + .eq(MemberUserDO::getId, id); + return update(null, lambdaUpdateWrapper); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java new file mode 100644 index 0000000..a45c2a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/package-info.java @@ -0,0 +1,9 @@ +/** + * DAL = Data Access Layer 数据访问层 + * 1. data object:数据对象 + * 2. redis:Redis 的 CRUD 操作 + * 3. mysql:MySQL 的 CRUD 操作 + * + * 其中,MySQL 的表以 member_ 作为前缀 + */ +package cn.iocoder.yudao.module.member.dal; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java new file mode 100644 index 0000000..8dfa9fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/redis/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,后续有类后,可以删除,避免 package 无法提交到 Git 上 + */ +package cn.iocoder.yudao.module.member.dal.redis; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/package-info.java new file mode 100644 index 0000000..7e9ca95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 member 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.member.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java new file mode 100644 index 0000000..82c7003 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/MemberWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.member.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * member 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class MemberWebConfiguration { + + /** + * member 模块的 API 分组 + */ + @Bean + public GroupedOpenApi memberGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("member"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/package-info.java new file mode 100644 index 0000000..3a964cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * member 模块的 web 配置 + */ +package cn.iocoder.yudao.module.member.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/consumer/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/consumer/package-info.java new file mode 100644 index 0000000..521f60b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/consumer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消费者 + */ +package cn.iocoder.yudao.module.member.mq.consumer; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/package-info.java new file mode 100644 index 0000000..6489394 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package cn.iocoder.yudao.module.member.mq.message; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/package-info.java new file mode 100644 index 0000000..dff4c99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的生产者 + */ +package cn.iocoder.yudao.module.member.mq.producer; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/MemberUserProducer.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/MemberUserProducer.java new file mode 100644 index 0000000..8687bb0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/MemberUserProducer.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.member.mq.producer.user; + +import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 会员用户 Producer + * + * @author owen + */ +@Slf4j +@Component +public class MemberUserProducer { + + @Resource + private ApplicationContext applicationContext; + + /** + * 发送 {@link MemberUserCreateMessage} 消息 + * + * @param userId 用户编号 + */ + public void sendUserCreateMessage(Long userId) { + applicationContext.publishEvent(new MemberUserCreateMessage().setUserId(userId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/package-info.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/package-info.java new file mode 100644 index 0000000..405aa4c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/package-info.java @@ -0,0 +1,8 @@ +/** + * member 模块,我们放会员业务。 + * 例如说:会员中心等等 + * + * 1. Controller URL:以 /member/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 member_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.member; diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressService.java new file mode 100644 index 0000000..099c49c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressService.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.member.service.address; + +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 用户收件地址 Service 接口 + * + * @author 芋道源码 + */ +public interface AddressService { + + /** + * 创建用户收件地址 + * + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAddress(Long userId, @Valid AppAddressCreateReqVO createReqVO); + + /** + * 更新用户收件地址 + * + * @param userId 用户编号 + * @param updateReqVO 更新信息 + */ + void updateAddress(Long userId, @Valid AppAddressUpdateReqVO updateReqVO); + + /** + * 删除用户收件地址 + * + * @param userId 用户编号 + * @param id 编号 + */ + void deleteAddress(Long userId, Long id); + + /** + * 获得用户收件地址 + * + * @param id 编号 + * @return 用户收件地址 + */ + MemberAddressDO getAddress(Long userId, Long id); + + /** + * 获得用户收件地址列表 + * + * @param userId 用户编号 + * @return 用户收件地址列表 + */ + List getAddressList(Long userId); + + /** + * 获得用户默认的收件地址 + * + * @param userId 用户编号 + * @return 用户收件地址 + */ + MemberAddressDO getDefaultUserAddress(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java new file mode 100644 index 0000000..901f1b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.member.service.address; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import cn.iocoder.yudao.module.member.dal.mysql.address.MemberAddressMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.ADDRESS_NOT_EXISTS; + +/** + * 用户收件地址 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class AddressServiceImpl implements AddressService { + + @Resource + private MemberAddressMapper memberAddressMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createAddress(Long userId, AppAddressCreateReqVO createReqVO) { + // 如果添加的是默认收件地址,则将原默认地址修改为非默认 + if (Boolean.TRUE.equals(createReqVO.getDefaultStatus())) { + List addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true); + addresses.forEach(address -> memberAddressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false))); + } + + // 插入 + MemberAddressDO address = AddressConvert.INSTANCE.convert(createReqVO); + address.setUserId(userId); + memberAddressMapper.insert(address); + // 返回 + return address.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateAddress(Long userId, AppAddressUpdateReqVO updateReqVO) { + // 校验存在,校验是否能够操作 + validAddressExists(userId, updateReqVO.getId()); + + // 如果修改的是默认收件地址,则将原默认地址修改为非默认 + if (Boolean.TRUE.equals(updateReqVO.getDefaultStatus())) { + List addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true); + addresses.stream().filter(u -> !u.getId().equals(updateReqVO.getId())) // 排除自己 + .forEach(address -> memberAddressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false))); + } + + // 更新 + MemberAddressDO updateObj = AddressConvert.INSTANCE.convert(updateReqVO); + memberAddressMapper.updateById(updateObj); + } + + @Override + public void deleteAddress(Long userId, Long id) { + // 校验存在,校验是否能够操作 + validAddressExists(userId, id); + // 删除 + memberAddressMapper.deleteById(id); + } + + private void validAddressExists(Long userId, Long id) { + MemberAddressDO addressDO = getAddress(userId, id); + if (addressDO == null) { + throw exception(ADDRESS_NOT_EXISTS); + } + } + + @Override + public MemberAddressDO getAddress(Long userId, Long id) { + return memberAddressMapper.selectByIdAndUserId(id, userId); + } + + @Override + public List getAddressList(Long userId) { + return memberAddressMapper.selectListByUserIdAndDefaulted(userId, null); + } + + @Override + public MemberAddressDO getDefaultUserAddress(Long userId) { + List addresses = memberAddressMapper.selectListByUserIdAndDefaulted(userId, true); + return CollUtil.getFirst(addresses); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java new file mode 100644 index 0000000..8afc09e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.member.service.auth; + +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; + +import javax.validation.Valid; + +/** + * 会员的认证 Service 接口 + * + * 提供用户的账号密码登录、token 的校验等认证相关的功能 + * + * @author 芋道源码 + */ +public interface MemberAuthService { + + /** + * 手机 + 密码登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AppAuthLoginRespVO login(@Valid AppAuthLoginReqVO reqVO); + + /** + * 基于 token 退出登录 + * + * @param token token + */ + void logout(String token); + + /** + * 手机 + 验证码登陆 + * + * @param reqVO 登陆信息 + * @return 登录结果 + */ + AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO); + + /** + * 社交登录,使用 code 授权码 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AppAuthLoginRespVO socialLogin(@Valid AppAuthSocialLoginReqVO reqVO); + + /** + * 微信小程序的一键登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO); + + /** + * 获得社交认证 URL + * + * @param type 社交平台类型 + * @param redirectUri 跳转地址 + * @return 认证 URL + */ + String getSocialAuthorizeUrl(Integer type, String redirectUri); + + /** + * 给用户发送短信验证码 + * + * @param userId 用户编号 + * @param reqVO 发送信息 + */ + void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); + + /** + * 校验短信验证码是否正确 + * + * @param userId 用户编号 + * @param reqVO 校验信息 + */ + void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO); + + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 登录结果 + */ + AppAuthLoginRespVO refreshToken(String refreshToken); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java new file mode 100644 index 0000000..e1a8ec5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -0,0 +1,286 @@ +package cn.iocoder.yudao.module.member.service.auth; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.SocialUserApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; + +/** + * 会员的认证 Service 接口 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class MemberAuthServiceImpl implements MemberAuthService { + + @Resource + private MemberUserService userService; + @Resource + private SmsCodeApi smsCodeApi; + @Resource + private LoginLogApi loginLogApi; + @Resource + private SocialUserApi socialUserApi; + @Resource + private SocialClientApi socialClientApi; + @Resource + private OAuth2TokenApi oauth2TokenApi; + + @Override + public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) { + // 使用手机 + 密码,进行登录。 + MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); + + // 如果 socialType 非空,说明需要绑定社交用户 + String openid = null; + if (reqVO.getSocialType() != null) { + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, openid); + } + + @Override + @Transactional + public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) { + // 校验验证码 + String userIp = getClientIP(); + smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); + + // 获得获得注册用户 + MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, getTerminal()); + Assert.notNull(user, "获取用户失败,结果为空"); + + // 校验是否禁用 + if (CommonStatusEnum.isDisable(user.getStatus())) { + createLoginLog(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, LoginResultEnum.USER_DISABLED); + throw exception(AUTH_LOGIN_USER_DISABLED); + } + + // 如果 socialType 非空,说明需要绑定社交用户 + String openid = null; + if (reqVO.getSocialType() != null) { + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, openid); + } + + @Override + @Transactional + public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { + // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), + reqVO.getCode(), reqVO.getState()); + if (socialUser == null) { + throw exception(AUTH_SOCIAL_USER_NOT_FOUND); + } + + // 情况一:已绑定,直接读取用户信息 + MemberUserDO user; + if (socialUser.getUserId() != null) { + user = userService.getUser(socialUser.getUserId()); + // 情况二:未绑定,注册用户 + 绑定用户 + } else { + user = userService.createUser(socialUser.getNickname(), socialUser.getAvatar(), getClientIP(), getTerminal()); + socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getType(), reqVO.getCode(), reqVO.getState())); + } + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, socialUser.getOpenid()); + } + + @Override + public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) { + // 获得对应的手机号信息 + SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo( + UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode()); + Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空"); + + // 获得获得注册用户 + MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), + getClientIP(), TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal()); + Assert.notNull(user, "获取用户失败,结果为空"); + + // 绑定社交用户 + String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState())); + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid); + } + + private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, + LoginLogTypeEnum logType, String openid) { + // 插入登陆日志 + createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); + // 创建 Token 令牌 + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO() + .setUserId(user.getId()).setUserType(getUserType().getValue()) + .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)); + // 构建返回结果 + return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid); + } + + @Override + public String getSocialAuthorizeUrl(Integer type, String redirectUri) { + return socialClientApi.getAuthorizeUrl(type, UserTypeEnum.MEMBER.getValue(), redirectUri); + } + + private MemberUserDO login0(String mobile, String password) { + final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE; + // 校验账号是否存在 + MemberUserDO user = userService.getUserByMobile(mobile); + if (user == null) { + createLoginLog(null, mobile, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + if (!userService.isPasswordMatch(password, user.getPassword())) { + createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + // 校验是否禁用 + if (CommonStatusEnum.isDisable(user.getStatus())) { + createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED); + throw exception(AUTH_LOGIN_USER_DISABLED); + } + return user; + } + + private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) { + // 插入登录日志 + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(logType.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(mobile); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(loginResult.getResult()); + loginLogApi.createLoginLog(reqDTO); + // 更新最后登录时间 + if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { + userService.updateUserLogin(userId, getClientIP()); + } + } + + @Override + public void logout(String token) { + // 删除访问令牌 + OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.removeAccessToken(token); + if (accessTokenRespDTO == null) { + return; + } + // 删除成功,则记录登出日志 + createLogoutLog(accessTokenRespDTO.getUserId()); + } + + @Override + public void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO) { + // 情况 1:如果是修改手机场景,需要校验新手机号是否已经注册,说明不能使用该手机了 + if (Objects.equals(reqVO.getScene(), SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene())) { + MemberUserDO user = userService.getUserByMobile(reqVO.getMobile()); + if (user != null && !Objects.equals(user.getId(), userId)) { + throw exception(AUTH_MOBILE_USED); + } + } + // 情况 2:如果是重置密码场景,需要校验手机号是存在的 + if (Objects.equals(reqVO.getScene(), SmsSceneEnum.MEMBER_RESET_PASSWORD.getScene())) { + MemberUserDO user = userService.getUserByMobile(reqVO.getMobile()); + if (user == null) { + throw exception(USER_MOBILE_NOT_EXISTS); + } + } + // 情况 3:如果是修改密码场景,需要查询手机号,无需前端传递 + if (Objects.equals(reqVO.getScene(), SmsSceneEnum.MEMBER_UPDATE_PASSWORD.getScene())) { + MemberUserDO user = userService.getUser(userId); + // TODO 芋艿:后续 member user 手机非强绑定,这块需要做下调整; + reqVO.setMobile(user.getMobile()); + } + + // 执行发送 + smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); + } + + @Override + public void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO) { + smsCodeApi.validateSmsCode(AuthConvert.INSTANCE.convert(reqVO)); + } + + @Override + public AppAuthLoginRespVO refreshToken(String refreshToken) { + OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, + OAuth2ClientConstants.CLIENT_ID_DEFAULT); + return AuthConvert.INSTANCE.convert(accessTokenDO, null); + } + + private void createLogoutLog(Long userId) { + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(LoginLogTypeEnum.LOGOUT_SELF.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(getMobile(userId)); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(getClientIP()); + reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); + loginLogApi.createLoginLog(reqDTO); + } + + private String getMobile(Long userId) { + if (userId == null) { + return null; + } + MemberUserDO user = userService.getUser(userId); + return user != null ? user.getMobile() : null; + } + + private UserTypeEnum getUserType() { + return UserTypeEnum.MEMBER; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigService.java new file mode 100644 index 0000000..fc45454 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigService.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.member.service.config; + +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO; + +import javax.validation.Valid; + +/** + * 会员配置 Service 接口 + * + * @author QingX + */ +public interface MemberConfigService { + + /** + * 保存会员配置 + * + * @param saveReqVO 更新信息 + */ + void saveConfig(@Valid MemberConfigSaveReqVO saveReqVO); + + /** + * 获得会员配置 + * + * @return 积分配置 + */ + MemberConfigDO getConfig(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigServiceImpl.java new file mode 100644 index 0000000..be56f8a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/config/MemberConfigServiceImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.member.service.config; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.member.controller.admin.config.vo.MemberConfigSaveReqVO; +import cn.iocoder.yudao.module.member.convert.config.MemberConfigConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.config.MemberConfigDO; +import cn.iocoder.yudao.module.member.dal.mysql.config.MemberConfigMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 会员配置 Service 实现类 + * + * @author QingX + */ +@Service +@Validated +public class MemberConfigServiceImpl implements MemberConfigService { + + @Resource + private MemberConfigMapper memberConfigMapper; + + @Override + public void saveConfig(MemberConfigSaveReqVO saveReqVO) { + // 存在,则进行更新 + MemberConfigDO dbConfig = getConfig(); + if (dbConfig != null) { + memberConfigMapper.updateById(MemberConfigConvert.INSTANCE.convert(saveReqVO).setId(dbConfig.getId())); + return; + } + // 不存在,则进行插入 + memberConfigMapper.insert(MemberConfigConvert.INSTANCE.convert(saveReqVO)); + } + + @Override + public MemberConfigDO getConfig() { + List list = memberConfigMapper.selectList(); + return CollectionUtils.getFirst(list); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupService.java new file mode 100644 index 0000000..2a8303e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.member.service.group; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 用户分组 Service 接口 + * + * @author owen + */ +public interface MemberGroupService { + + /** + * 创建用户分组 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createGroup(@Valid MemberGroupCreateReqVO createReqVO); + + /** + * 更新用户分组 + * + * @param updateReqVO 更新信息 + */ + void updateGroup(@Valid MemberGroupUpdateReqVO updateReqVO); + + /** + * 删除用户分组 + * + * @param id 编号 + */ + void deleteGroup(Long id); + + /** + * 获得用户分组 + * + * @param id 编号 + * @return 用户分组 + */ + MemberGroupDO getGroup(Long id); + + /** + * 获得用户分组列表 + * + * @param ids 编号 + * @return 用户分组列表 + */ + List getGroupList(Collection ids); + + /** + * 获得用户分组分页 + * + * @param pageReqVO 分页查询 + * @return 用户分组分页 + */ + PageResult getGroupPage(MemberGroupPageReqVO pageReqVO); + + /** + * 获得指定状态的用户分组列表 + * + * @param status 状态 + * @return 用户分组列表 + */ + List getGroupListByStatus(Integer status); + + /** + * 获得开启状态的用户分组列表 + * + * @return 用户分组列表 + */ + default List getEnableGroupList() { + return getGroupListByStatus(CommonStatusEnum.ENABLE.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImpl.java new file mode 100644 index 0000000..cdf1e4f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImpl.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.member.service.group; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.group.MemberGroupConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_HAS_USER; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_NOT_EXISTS; + +/** + * 用户分组 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberGroupServiceImpl implements MemberGroupService { + + @Resource + private MemberGroupMapper memberGroupMapper; + + @Resource + private MemberUserService memberUserService; + + @Override + public Long createGroup(MemberGroupCreateReqVO createReqVO) { + // 插入 + MemberGroupDO group = MemberGroupConvert.INSTANCE.convert(createReqVO); + memberGroupMapper.insert(group); + // 返回 + return group.getId(); + } + + @Override + public void updateGroup(MemberGroupUpdateReqVO updateReqVO) { + // 校验存在 + validateGroupExists(updateReqVO.getId()); + // 更新 + MemberGroupDO updateObj = MemberGroupConvert.INSTANCE.convert(updateReqVO); + memberGroupMapper.updateById(updateObj); + } + + @Override + public void deleteGroup(Long id) { + // 校验存在 + validateGroupExists(id); + // 校验分组下是否有用户 + validateGroupHasUser(id); + // 删除 + memberGroupMapper.deleteById(id); + } + + void validateGroupExists(Long id) { + if (memberGroupMapper.selectById(id) == null) { + throw exception(GROUP_NOT_EXISTS); + } + } + + void validateGroupHasUser(Long id) { + Long count = memberUserService.getUserCountByGroupId(id); + if (count > 0) { + throw exception(GROUP_HAS_USER); + } + } + + @Override + public MemberGroupDO getGroup(Long id) { + return memberGroupMapper.selectById(id); + } + + @Override + public List getGroupList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return memberGroupMapper.selectBatchIds(ids); + } + + @Override + public PageResult getGroupPage(MemberGroupPageReqVO pageReqVO) { + return memberGroupMapper.selectPage(pageReqVO); + } + + @Override + public List getGroupListByStatus(Integer status) { + return memberGroupMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java new file mode 100644 index 0000000..76470f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; + +/** + * 会员经验记录 Service 接口 + * + * @author owen + */ +public interface MemberExperienceRecordService { + + /** + * 获得会员经验记录 + * + * @param id 编号 + * @return 会员经验记录 + */ + MemberExperienceRecordDO getExperienceRecord(Long id); + + /** + * 【管理员】获得会员经验记录分页 + * + * @param pageReqVO 分页查询 + * @return 会员经验记录分页 + */ + PageResult getExperienceRecordPage(MemberExperienceRecordPageReqVO pageReqVO); + + /** + * 【会员】获得会员经验记录分页 + * + * @param userId 用户编号 + * @param pageParam 分页查询 + * @return 会员经验记录分页 + */ + PageResult getExperienceRecordPage(Long userId, PageParam pageParam); + + /** + * 根据业务类型, 创建 经验变动记录 + * + * @param userId 会员编号 + * @param experience 变动经验值 + * @param totalExperience 会员当前的经验 + * @param bizType 业务类型 + * @param bizId 业务ID + */ + void createExperienceRecord(Long userId, Integer experience, Integer totalExperience, + MemberExperienceBizTypeEnum bizType, String bizId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordServiceImpl.java new file mode 100644 index 0000000..80ecc84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordServiceImpl.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceRecordPageReqVO; +import cn.iocoder.yudao.module.member.convert.level.MemberExperienceRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceRecordDO; +import cn.iocoder.yudao.module.member.dal.mysql.level.MemberExperienceRecordMapper; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 会员经验记录 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberExperienceRecordServiceImpl implements MemberExperienceRecordService { + + @Resource + private MemberExperienceRecordMapper experienceLogMapper; + + @Override + public MemberExperienceRecordDO getExperienceRecord(Long id) { + return experienceLogMapper.selectById(id); + } + + @Override + public PageResult getExperienceRecordPage(MemberExperienceRecordPageReqVO pageReqVO) { + return experienceLogMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getExperienceRecordPage(Long userId, PageParam pageParam) { + return experienceLogMapper.selectPage(userId, pageParam); + } + + @Override + public void createExperienceRecord(Long userId, Integer experience, Integer totalExperience, + MemberExperienceBizTypeEnum bizType, String bizId) { + String description = StrUtil.format(bizType.getDescription(), experience); + MemberExperienceRecordDO record = MemberExperienceRecordConvert.INSTANCE.convert( + userId, experience, totalExperience, + bizId, bizType.getType(), bizType.getTitle(), description); + experienceLogMapper.insert(record); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java new file mode 100644 index 0000000..b5e4f66 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; + +/** + * 会员等级记录 Service 接口 + * + * @author owen + */ +public interface MemberLevelRecordService { + + /** + * 获得会员等级记录 + * + * @param id 编号 + * @return 会员等级记录 + */ + MemberLevelRecordDO getLevelRecord(Long id); + + /** + * 获得会员等级记录分页 + * + * @param pageReqVO 分页查询 + * @return 会员等级记录分页 + */ + PageResult getLevelRecordPage(MemberLevelRecordPageReqVO pageReqVO); + + /** + * 创建会员等级记录 + * + * @param levelRecord 会员等级记录 + */ + void createLevelRecord(MemberLevelRecordDO levelRecord); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordServiceImpl.java new file mode 100644 index 0000000..8109612 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordServiceImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.record.MemberLevelRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; +import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelRecordMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 会员等级记录 Service 实现类 + * + * @author owen + */ +@Service +@Validated +public class MemberLevelRecordServiceImpl implements MemberLevelRecordService { + + @Resource + private MemberLevelRecordMapper levelLogMapper; + + @Override + public MemberLevelRecordDO getLevelRecord(Long id) { + return levelLogMapper.selectById(id); + } + + @Override + public PageResult getLevelRecordPage(MemberLevelRecordPageReqVO pageReqVO) { + return levelLogMapper.selectPage(pageReqVO); + } + + @Override + public void createLevelRecord(MemberLevelRecordDO levelRecord) { + levelLogMapper.insert(levelRecord); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelService.java new file mode 100644 index 0000000..76d46e5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelListReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateLevelReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 会员等级 Service 接口 + * + * @author owen + */ +public interface MemberLevelService { + + /** + * 创建会员等级 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createLevel(@Valid MemberLevelCreateReqVO createReqVO); + + /** + * 更新会员等级 + * + * @param updateReqVO 更新信息 + */ + void updateLevel(@Valid MemberLevelUpdateReqVO updateReqVO); + + /** + * 删除会员等级 + * + * @param id 编号 + */ + void deleteLevel(Long id); + + /** + * 获得会员等级 + * + * @param id 编号 + * @return 会员等级 + */ + MemberLevelDO getLevel(Long id); + + /** + * 获得会员等级列表 + * + * @param ids 编号 + * @return 会员等级列表 + */ + List getLevelList(Collection ids); + + /** + * 获得会员等级列表 + * + * @param listReqVO 查询参数 + * @return 会员等级列表 + */ + List getLevelList(MemberLevelListReqVO listReqVO); + + /** + * 获得指定状态的会员等级列表 + * + * @param status 状态 + * @return 会员等级列表 + */ + List getLevelListByStatus(Integer status); + + /** + * 获得开启状态的会员等级列表 + * + * @return 会员等级列表 + */ + default List getEnableLevelList() { + return getLevelListByStatus(CommonStatusEnum.ENABLE.getStatus()); + } + + /** + * 修改会员的等级 + * + * @param updateReqVO 修改参数 + */ + void updateUserLevel(MemberUserUpdateLevelReqVO updateReqVO); + + /** + * 增加会员经验 + * + * @param userId 会员ID + * @param experience 经验 + * @param bizType 业务类型 + * @param bizId 业务编号 + */ + void addExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java new file mode 100644 index 0000000..7124d2b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java @@ -0,0 +1,299 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelListReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateLevelReqVO; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; +import cn.iocoder.yudao.module.member.convert.level.MemberLevelRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; + +/** + * 会员等级 Service 实现类 + * + * @author owen + */ +@Slf4j +@Service +@Validated +public class MemberLevelServiceImpl implements MemberLevelService { + + @Resource + private MemberLevelMapper memberLevelMapper; + + @Resource + private MemberLevelRecordService memberLevelRecordService; + @Resource + private MemberExperienceRecordService memberExperienceRecordService; + @Resource + private MemberUserService memberUserService; + + @Override + public Long createLevel(MemberLevelCreateReqVO createReqVO) { + // 校验配置是否有效 + validateConfigValid(null, createReqVO.getName(), createReqVO.getLevel(), createReqVO.getExperience()); + + // 插入 + MemberLevelDO level = MemberLevelConvert.INSTANCE.convert(createReqVO); + memberLevelMapper.insert(level); + // 返回 + return level.getId(); + } + + @Override + public void updateLevel(MemberLevelUpdateReqVO updateReqVO) { + // 校验存在 + validateLevelExists(updateReqVO.getId()); + // 校验配置是否有效 + validateConfigValid(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getLevel(), updateReqVO.getExperience()); + + // 更新 + MemberLevelDO updateObj = MemberLevelConvert.INSTANCE.convert(updateReqVO); + memberLevelMapper.updateById(updateObj); + } + + @Override + public void deleteLevel(Long id) { + // 校验存在 + validateLevelExists(id); + // 校验分组下是否有用户 + validateLevelHasUser(id); + // 删除 + memberLevelMapper.deleteById(id); + } + + @VisibleForTesting + MemberLevelDO validateLevelExists(Long id) { + MemberLevelDO levelDO = memberLevelMapper.selectById(id); + if (levelDO == null) { + throw exception(LEVEL_NOT_EXISTS); + } + return levelDO; + } + + @VisibleForTesting + void validateNameUnique(List list, Long id, String name) { + for (MemberLevelDO levelDO : list) { + if (ObjUtil.notEqual(levelDO.getName(), name)) { + continue; + } + if (id == null || !id.equals(levelDO.getId())) { + throw exception(LEVEL_NAME_EXISTS, levelDO.getName()); + } + } + } + + @VisibleForTesting + void validateLevelUnique(List list, Long id, Integer level) { + for (MemberLevelDO levelDO : list) { + if (ObjUtil.notEqual(levelDO.getLevel(), level)) { + continue; + } + + if (id == null || !id.equals(levelDO.getId())) { + throw exception(LEVEL_VALUE_EXISTS, levelDO.getLevel(), levelDO.getName()); + } + } + } + + @VisibleForTesting + void validateExperienceOutRange(List list, Long id, Integer level, Integer experience) { + for (MemberLevelDO levelDO : list) { + if (levelDO.getId().equals(id)) { + continue; + } + + if (levelDO.getLevel() < level) { + // 经验大于前一个等级 + if (experience <= levelDO.getExperience()) { + throw exception(LEVEL_EXPERIENCE_MIN, levelDO.getName(), levelDO.getExperience()); + } + } else if (levelDO.getLevel() > level) { + //小于下一个级别 + if (experience >= levelDO.getExperience()) { + throw exception(LEVEL_EXPERIENCE_MAX, levelDO.getName(), levelDO.getExperience()); + } + } + } + } + + @VisibleForTesting + void validateConfigValid(Long id, String name, Integer level, Integer experience) { + List list = memberLevelMapper.selectList(); + // 校验名称唯一 + validateNameUnique(list, id, name); + // 校验等级唯一 + validateLevelUnique(list, id, level); + // 校验升级所需经验是否有效: 大于前一个等级,小于下一个级别 + validateExperienceOutRange(list, id, level, experience); + } + + @VisibleForTesting + void validateLevelHasUser(Long id) { + Long count = memberUserService.getUserCountByLevelId(id); + if (count > 0) { + throw exception(LEVEL_HAS_USER); + } + } + + @Override + public MemberLevelDO getLevel(Long id) { + return id != null && id > 0 ? memberLevelMapper.selectById(id) : null; + } + + @Override + public List getLevelList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return memberLevelMapper.selectBatchIds(ids); + } + + @Override + public List getLevelList(MemberLevelListReqVO listReqVO) { + return memberLevelMapper.selectList(listReqVO); + } + + @Override + public List getLevelListByStatus(Integer status) { + return memberLevelMapper.selectListByStatus(status); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateUserLevel(MemberUserUpdateLevelReqVO updateReqVO) { + MemberUserDO user = memberUserService.getUser(updateReqVO.getId()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + // 等级未发生变化 + if (ObjUtil.equal(user.getLevelId(), updateReqVO.getLevelId())) { + return; + } + + // 1. 记录等级变动 + MemberLevelRecordDO levelRecord = new MemberLevelRecordDO() + .setUserId(user.getId()).setRemark(updateReqVO.getReason()); + MemberLevelDO memberLevel = null; + if (updateReqVO.getLevelId() == null) { + // 取消用户等级时,需要扣减经验 + levelRecord.setExperience(-user.getExperience()); + levelRecord.setUserExperience(0); + levelRecord.setDescription("管理员取消了等级"); + } else { + // 复制等级配置 + memberLevel = validateLevelExists(updateReqVO.getLevelId()); + MemberLevelRecordConvert.INSTANCE.copyTo(memberLevel, levelRecord); + // 变动经验值 = 等级的升级经验 - 会员当前的经验;正数为增加经验,负数为扣减经验 + levelRecord.setExperience(memberLevel.getExperience() - user.getExperience()); + levelRecord.setUserExperience(memberLevel.getExperience()); // 会员当前的经验 = 等级的升级经验 + levelRecord.setDescription("管理员调整为:" + memberLevel.getName()); + } + memberLevelRecordService.createLevelRecord(levelRecord); + + // 2. 记录会员经验变动 + memberExperienceRecordService.createExperienceRecord(user.getId(), + levelRecord.getExperience(), levelRecord.getUserExperience(), + MemberExperienceBizTypeEnum.ADMIN, String.valueOf(MemberExperienceBizTypeEnum.ADMIN.getType())); + + // 3. 更新会员表上的等级编号、经验值 + memberUserService.updateUserLevel(user.getId(), updateReqVO.getLevelId(), + levelRecord.getUserExperience()); + + // 4. 给会员发送等级变动消息 + notifyMemberLevelChange(user.getId(), memberLevel); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) { + if (experience == 0) { + return; + } + if (!bizType.isAdd() && experience > 0) { + experience = -experience; + } + + // 1. 创建经验记录 + MemberUserDO user = memberUserService.getUser(userId); + Integer userExperience = ObjUtil.defaultIfNull(user.getExperience(), 0); + userExperience = NumberUtil.max(userExperience + experience, 0); // 防止扣出负数 + MemberLevelRecordDO levelRecord = new MemberLevelRecordDO().setUserId(user.getId()) + .setExperience(experience).setUserExperience(userExperience).setLevelId(user.getLevelId()); + memberExperienceRecordService.createExperienceRecord(userId, experience, userExperience, + bizType, bizId); + + // 2.1 保存等级变更记录 + MemberLevelDO newLevel = calculateNewLevel(user, userExperience); + if (newLevel != null) { + MemberLevelRecordConvert.INSTANCE.copyTo(newLevel, levelRecord); + memberLevelRecordService.createLevelRecord(levelRecord); + + // 2.2 给会员发送等级变动消息 + notifyMemberLevelChange(userId, newLevel); + } + + // 3. 更新会员表上的等级编号、经验值 + memberUserService.updateUserLevel(user.getId(), Optional.ofNullable(levelRecord.getLevelId()).orElse(user.getLevelId()), userExperience); + } + + /** + * 计算会员等级 + * + * @param user 会员 + * @param userExperience 会员当前的经验值 + * @return 会员新的等级,null表示无变化 + */ + private MemberLevelDO calculateNewLevel(MemberUserDO user, int userExperience) { + List list = getEnableLevelList(); + if (CollUtil.isEmpty(list)) { + log.warn("计算会员等级失败:会员等级配置不存在"); + return null; + } + + MemberLevelDO matchLevel = list.stream() + .filter(level -> userExperience >= level.getExperience()) + .max(Comparator.nullsFirst(Comparator.comparing(MemberLevelDO::getLevel))) + .orElse(null); + if (matchLevel == null) { + log.warn("计算会员等级失败:未找到会员{}经验{}对应的等级配置", user.getId(), userExperience); + return null; + } + + // 等级没有变化 + if (ObjectUtil.equal(matchLevel.getId(), user.getLevelId())) { + return null; + } + + return matchLevel; + } + + private void notifyMemberLevelChange(Long userId, MemberLevelDO level) { + //todo: 给会员发消息 + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordService.java new file mode 100644 index 0000000..7e660d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordService.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.member.service.point; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; + +/** + * 用户积分记录 Service 接口 + * + * @author QingX + */ +public interface MemberPointRecordService { + + /** + * 【管理员】获得积分记录分页 + * + * @param pageReqVO 分页查询 + * @return 签到记录分页 + */ + PageResult getPointRecordPage(MemberPointRecordPageReqVO pageReqVO); + + /** + * 【会员】获得积分记录分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页查询 + * @return 签到记录分页 + */ + PageResult getPointRecordPage(Long userId, AppMemberPointRecordPageReqVO pageReqVO); + + /** + * 创建用户积分记录 + * + * @param userId 用户ID + * @param point 变动积分 + * @param bizType 业务类型 + * @param bizId 业务编号 + */ + void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId); +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java new file mode 100644 index 0000000..d21c7bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/point/MemberPointRecordServiceImpl.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.member.service.point; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.point.vo.recrod.MemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.point.vo.AppMemberPointRecordPageReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.point.MemberPointRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.point.MemberPointRecordMapper; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_POINT_NOT_ENOUGH; + + +/** + * 积分记录 Service 实现类 + * + * @author QingX + */ +@Slf4j +@Service +@Validated +public class MemberPointRecordServiceImpl implements MemberPointRecordService { + + @Resource + private MemberPointRecordMapper memberPointRecordMapper; + + @Resource + private MemberUserService memberUserService; + + @Override + public PageResult getPointRecordPage(MemberPointRecordPageReqVO pageReqVO) { + // 根据用户昵称查询出用户 ids + Set userIds = null; + if (StringUtils.isNotBlank(pageReqVO.getNickname())) { + List users = memberUserService.getUserListByNickname(pageReqVO.getNickname()); + // 如果查询用户结果为空直接返回无需继续查询 + if (CollectionUtils.isEmpty(users)) { + return PageResult.empty(); + } + userIds = convertSet(users, MemberUserDO::getId); + } + // 执行查询 + return memberPointRecordMapper.selectPage(pageReqVO, userIds); + } + + @Override + public PageResult getPointRecordPage(Long userId, AppMemberPointRecordPageReqVO pageReqVO) { + return memberPointRecordMapper.selectPage(userId, pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) { + if (point == 0) { + return; + } + // 1. 校验用户积分余额 + MemberUserDO user = memberUserService.getUser(userId); + Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0); + int totalPoint = userPoint + point; // 用户变动后的积分 + if (totalPoint < 0) { + throw exception(USER_POINT_NOT_ENOUGH); + } + + // 2. 更新用户积分 + boolean success = memberUserService.updateUserPoint(userId, point); + if (!success) { + throw exception(USER_POINT_NOT_ENOUGH); + } + + // 3. 增加积分记录 + MemberPointRecordDO record = new MemberPointRecordDO() + .setUserId(userId).setBizId(bizId).setBizType(bizType.getType()) + .setTitle(bizType.getName()).setDescription(StrUtil.format(bizType.getDescription(), point)) + .setPoint(point).setTotalPoint(totalPoint); + memberPointRecordMapper.insert(record); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigService.java new file mode 100644 index 0000000..b4a9c04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigService.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.member.service.signin; + +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 签到规则 Service 接口 + * + * @author QingX + */ +public interface MemberSignInConfigService { + + /** + * 创建签到规则 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSignInConfig(@Valid MemberSignInConfigCreateReqVO createReqVO); + + /** + * 更新签到规则 + * + * @param updateReqVO 更新信息 + */ + void updateSignInConfig(@Valid MemberSignInConfigUpdateReqVO updateReqVO); + + /** + * 删除签到规则 + * + * @param id 编号 + */ + void deleteSignInConfig(Long id); + + /** + * 获得签到规则 + * + * @param id 编号 + * @return 签到规则 + */ + MemberSignInConfigDO getSignInConfig(Long id); + + /** + * 获得签到规则列表 + * + * @return 签到规则分页 + */ + List getSignInConfigList(); + + /** + * 获得签到规则列表 + * + * @param status 状态 + * @return 签到规则分页 + */ + List getSignInConfigList(Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java new file mode 100644 index 0000000..4e2b04c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.member.service.signin; + +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.config.MemberSignInConfigUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInConfigConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInConfigMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_EXISTS; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_NOT_EXISTS; + +/** + * 签到规则 Service 实现类 + * + * @author QingX + */ +@Service +@Validated +public class MemberSignInConfigServiceImpl implements MemberSignInConfigService { + + @Resource + private MemberSignInConfigMapper memberSignInConfigMapper; + + @Override + public Long createSignInConfig(MemberSignInConfigCreateReqVO createReqVO) { + // 判断是否重复插入签到天数 + validateSignInConfigDayDuplicate(createReqVO.getDay(), null); + + // 插入 + MemberSignInConfigDO signInConfig = MemberSignInConfigConvert.INSTANCE.convert(createReqVO); + memberSignInConfigMapper.insert(signInConfig); + // 返回 + return signInConfig.getId(); + } + + @Override + public void updateSignInConfig(MemberSignInConfigUpdateReqVO updateReqVO) { + // 校验存在 + validateSignInConfigExists(updateReqVO.getId()); + // 判断是否重复插入签到天数 + validateSignInConfigDayDuplicate(updateReqVO.getDay(), updateReqVO.getId()); + + // 判断更新 + MemberSignInConfigDO updateObj = MemberSignInConfigConvert.INSTANCE.convert(updateReqVO); + memberSignInConfigMapper.updateById(updateObj); + } + + @Override + public void deleteSignInConfig(Long id) { + // 校验存在 + validateSignInConfigExists(id); + // 删除 + memberSignInConfigMapper.deleteById(id); + } + + private void validateSignInConfigExists(Long id) { + if (memberSignInConfigMapper.selectById(id) == null) { + throw exception(SIGN_IN_CONFIG_NOT_EXISTS); + } + } + + /** + * 校验 day 是否重复 + * + * @param day 天 + * @param id 编号,只有更新的时候会传递 + */ + private void validateSignInConfigDayDuplicate(Integer day, Long id) { + MemberSignInConfigDO config = memberSignInConfigMapper.selectByDay(day); + // 1. 新增时,config 非空,则说明重复 + if (id == null && config != null) { + throw exception(SIGN_IN_CONFIG_EXISTS); + } + // 2. 更新时,如果 config 非空,且 id 不相等,则说明重复 + if (id != null && config != null && !config.getId().equals(id)) { + throw exception(SIGN_IN_CONFIG_EXISTS); + } + } + + @Override + public MemberSignInConfigDO getSignInConfig(Long id) { + return memberSignInConfigMapper.selectById(id); + } + + @Override + public List getSignInConfigList() { + List list = memberSignInConfigMapper.selectList(); + list.sort(Comparator.comparing(MemberSignInConfigDO::getDay)); + return list; + } + + @Override + public List getSignInConfigList(Integer status) { + List list = memberSignInConfigMapper.selectListByStatus(status); + list.sort(Comparator.comparing(MemberSignInConfigDO::getDay)); + return list; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java new file mode 100644 index 0000000..b22ceed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.member.service.signin; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; + +/** + * 签到记录 Service 接口 + * + * @author 芋道源码 + */ +public interface MemberSignInRecordService { + + /** + * 【管理员】获得签到记录分页 + * + * @param pageReqVO 分页查询 + * @return 签到记录分页 + */ + PageResult getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO); + + /** + * 【会员】获得签到记录分页 + * + * @param userId 用户编号 + * @param pageParam 分页查询 + * @return 签到记录分页 + */ + PageResult getSignRecordPage(Long userId, PageParam pageParam); + + /** + * 创建签到记录 + * + * @param userId 用户编号 + * @return 签到记录 + */ + MemberSignInRecordDO createSignRecord(Long userId); + + /** + * 根据用户编号,获得个人签到统计信息 + * + * @param userId 用户编号 + * @return 个人签到统计信息 + */ + AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId); + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java new file mode 100644 index 0000000..d7c2b87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.member.service.signin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper; +import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; +import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; +import cn.iocoder.yudao.module.member.service.level.MemberLevelService; +import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_RECORD_TODAY_EXISTS; + +/** + * 签到记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MemberSignInRecordServiceImpl implements MemberSignInRecordService { + + @Resource + private MemberSignInRecordMapper signInRecordMapper; + @Resource + private MemberSignInConfigService signInConfigService; + @Resource + private MemberPointRecordService pointRecordService; + @Resource + private MemberLevelService memberLevelService; + + @Resource + private MemberUserService memberUserService; + + @Override + public AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId) { + // 1. 初始化默认返回信息 + AppMemberSignInRecordSummaryRespVO summary = new AppMemberSignInRecordSummaryRespVO(); + summary.setTotalDay(0); + summary.setContinuousDay(0); + summary.setTodaySignIn(false); + + // 2. 获取用户签到的记录数 + Long signCount = signInRecordMapper.selectCountByUserId(userId); + if (ObjUtil.equal(signCount, 0L)) { + return summary; + } + summary.setTotalDay(signCount.intValue()); // 设置总签到天数 + + // 3. 校验当天是否有签到 + MemberSignInRecordDO lastRecord = signInRecordMapper.selectLastRecordByUserId(userId); + if (lastRecord == null) { + return summary; + } + summary.setTodaySignIn(DateUtils.isToday(lastRecord.getCreateTime())); + + // 4.1 检查今天是否未签到且记录不是昨天创建的,如果是则直接返回 + if (!summary.getTodaySignIn() && !DateUtils.isYesterday(lastRecord.getCreateTime())) { + return summary; + } + + // 4.2 要么是今天签到了,要么是昨天的记录,设置连续签到天数 + summary.setContinuousDay(lastRecord.getDay()); + return summary; + } + + @Override + public PageResult getSignInRecordPage(MemberSignInRecordPageReqVO pageReqVO) { + // 根据用户昵称查询出用户ids + Set userIds = null; + if (StringUtils.isNotBlank(pageReqVO.getNickname())) { + List users = memberUserService.getUserListByNickname(pageReqVO.getNickname()); + // 如果查询用户结果为空直接返回无需继续查询 + if (CollUtil.isEmpty(users)) { + return PageResult.empty(); + } + userIds = convertSet(users, MemberUserDO::getId); + } + // 分页查询 + return signInRecordMapper.selectPage(pageReqVO, userIds); + } + + @Override + public PageResult getSignRecordPage(Long userId, PageParam pageParam) { + return signInRecordMapper.selectPage(userId, pageParam); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public MemberSignInRecordDO createSignRecord(Long userId) { + // 1. 获取当前用户最近的签到 + MemberSignInRecordDO lastRecord = signInRecordMapper.selectLastRecordByUserId(userId); + // 1.1. 判断是否重复签到 + validateSigned(lastRecord); + + // 2.1. 获取所有的签到规则 + List signInConfigs = signInConfigService.getSignInConfigList(CommonStatusEnum.ENABLE.getStatus()); + // 2.2. 组合数据 + MemberSignInRecordDO record = MemberSignInRecordConvert.INSTANCE.convert(userId, lastRecord, signInConfigs); + + // 3. 插入签到记录 + signInRecordMapper.insert(record); + + // 4. 增加积分 + if (!ObjectUtils.equalsAny(record.getPoint(), null, 0)) { + pointRecordService.createPointRecord(userId, record.getPoint(), MemberPointBizTypeEnum.SIGN, String.valueOf(record.getId())); + } + // 5. 增加经验 + if (!ObjectUtils.equalsAny(record.getExperience(), null, 0)) { + memberLevelService.addExperience(userId, record.getExperience(), MemberExperienceBizTypeEnum.SIGN_IN, String.valueOf(record.getId())); + } + return record; + } + + private void validateSigned(MemberSignInRecordDO signInRecordDO) { + if (signInRecordDO == null) { + return; + } + if (DateUtils.isToday(signInRecordDO.getCreateTime())) { + throw exception(SIGN_IN_RECORD_TODAY_EXISTS); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagService.java new file mode 100644 index 0000000..5e33933 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.member.service.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 会员标签 Service 接口 + * + * @author 芋道源码 + */ +public interface MemberTagService { + + /** + * 创建会员标签 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTag(@Valid MemberTagCreateReqVO createReqVO); + + /** + * 更新会员标签 + * + * @param updateReqVO 更新信息 + */ + void updateTag(@Valid MemberTagUpdateReqVO updateReqVO); + + /** + * 删除会员标签 + * + * @param id 编号 + */ + void deleteTag(Long id); + + /** + * 获得会员标签 + * + * @param id 编号 + * @return 会员标签 + */ + MemberTagDO getTag(Long id); + + /** + * 获得会员标签列表 + * + * @param ids 编号 + * @return 会员标签列表 + */ + List getTagList(Collection ids); + + /** + * 获得会员标签分页 + * + * @param pageReqVO 分页查询 + * @return 会员标签分页 + */ + PageResult getTagPage(MemberTagPageReqVO pageReqVO); + + /** + * 获取标签列表 + * + * @return 标签列表 + */ + List getTagList(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImpl.java new file mode 100644 index 0000000..b267227 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImpl.java @@ -0,0 +1,125 @@ +package cn.iocoder.yudao.module.member.service.tag; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO; +import cn.iocoder.yudao.module.member.convert.tag.MemberTagConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import cn.iocoder.yudao.module.member.dal.mysql.tag.MemberTagMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; + +/** + * 会员标签 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MemberTagServiceImpl implements MemberTagService { + + @Resource + private MemberTagMapper memberTagMapper; + + @Resource + private MemberUserService memberUserService; + + @Override + public Long createTag(MemberTagCreateReqVO createReqVO) { + // 校验名称唯一 + validateTagNameUnique(null, createReqVO.getName()); + // 插入 + MemberTagDO tag = MemberTagConvert.INSTANCE.convert(createReqVO); + memberTagMapper.insert(tag); + // 返回 + return tag.getId(); + } + + @Override + public void updateTag(MemberTagUpdateReqVO updateReqVO) { + // 校验存在 + validateTagExists(updateReqVO.getId()); + // 校验名称唯一 + validateTagNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 更新 + MemberTagDO updateObj = MemberTagConvert.INSTANCE.convert(updateReqVO); + memberTagMapper.updateById(updateObj); + } + + @Override + public void deleteTag(Long id) { + // 校验存在 + validateTagExists(id); + // 校验标签下是否有用户 + validateTagHasUser(id); + // 删除 + memberTagMapper.deleteById(id); + } + + private void validateTagExists(Long id) { + if (memberTagMapper.selectById(id) == null) { + throw exception(TAG_NOT_EXISTS); + } + } + + private void validateTagNameUnique(Long id, String name) { + if (StrUtil.isBlank(name)) { + return; + } + MemberTagDO tag = memberTagMapper.selelctByName(name); + if (tag == null) { + return; + } + + // 如果 id 为空,说明不用比较是否为相同 id 的标签 + if (id == null) { + throw exception(TAG_NAME_EXISTS); + } + if (!tag.getId().equals(id)) { + throw exception(TAG_NAME_EXISTS); + } + } + + void validateTagHasUser(Long id) { + Long count = memberUserService.getUserCountByTagId(id); + if (count > 0) { + throw exception(TAG_HAS_USER); + } + } + + @Override + public MemberTagDO getTag(Long id) { + return memberTagMapper.selectById(id); + } + + @Override + public List getTagList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return memberTagMapper.selectBatchIds(ids); + } + + @Override + public PageResult getTagPage(MemberTagPageReqVO pageReqVO) { + return memberTagMapper.selectPage(pageReqVO); + } + + @Override + public List getTagList() { + return memberTagMapper.selectList(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java new file mode 100644 index 0000000..fb2e9cd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.member.service.user; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.*; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 会员用户 Service 接口 + * + * @author 芋道源码 + */ +public interface MemberUserService { + + /** + * 通过手机查询用户 + * + * @param mobile 手机 + * @return 用户对象 + */ + MemberUserDO getUserByMobile(String mobile); + + /** + * 基于用户昵称,模糊匹配用户列表 + * + * @param nickname 用户昵称,模糊匹配 + * @return 用户信息的列表 + */ + List getUserListByNickname(String nickname); + + /** + * 基于手机号创建用户。 + * 如果用户已经存在,则直接进行返回 + * + * @param mobile 手机号 + * @param registerIp 注册 IP + * @param terminal 终端 {@link TerminalEnum} + * @return 用户对象 + */ + MemberUserDO createUserIfAbsent(@Mobile String mobile, String registerIp, Integer terminal); + + /** + * 创建用户 + * 目的:三方登录时,如果未绑定用户时,自动创建对应用户 + * + * @param nickname 昵称 + * @param avtar 头像 + * @param registerIp 注册 IP + * @param terminal 终端 {@link TerminalEnum} + * @return 用户对象 + */ + MemberUserDO createUser(String nickname, String avtar, String registerIp, Integer terminal); + + /** + * 更新用户的最后登陆信息 + * + * @param id 用户编号 + * @param loginIp 登陆 IP + */ + void updateUserLogin(Long id, String loginIp); + + /** + * 通过用户 ID 查询用户 + * + * @param id 用户ID + * @return 用户对象信息 + */ + MemberUserDO getUser(Long id); + + /** + * 通过用户 ID 查询用户们 + * + * @param ids 用户 ID + * @return 用户对象信息数组 + */ + List getUserList(Collection ids); + + /** + * 【会员】修改基本信息 + * + * @param userId 用户编号 + * @param reqVO 基本信息 + */ + void updateUser(Long userId, AppMemberUserUpdateReqVO reqVO); + + /** + * 【会员】修改手机,基于手机验证码 + * + * @param userId 用户编号 + * @param reqVO 请求信息 + */ + void updateUserMobile(Long userId, AppMemberUserUpdateMobileReqVO reqVO); + + /** + * 【会员】修改手机,基于微信小程序的授权码 + * + * @param userId 用户编号 + * @param reqVO 请求信息 + */ + void updateUserMobileByWeixin(Long userId, AppMemberUserUpdateMobileByWeixinReqVO reqVO); + + /** + * 【会员】修改密码 + * + * @param userId 用户编号 + * @param reqVO 请求信息 + */ + void updateUserPassword(Long userId, AppMemberUserUpdatePasswordReqVO reqVO); + + /** + * 【会员】忘记密码 + * + * @param reqVO 请求信息 + */ + void resetUserPassword(AppMemberUserResetPasswordReqVO reqVO); + + /** + * 判断密码是否匹配 + * + * @param rawPassword 未加密的密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + boolean isPasswordMatch(String rawPassword, String encodedPassword); + + /** + * 【管理员】更新会员用户 + * + * @param updateReqVO 更新信息 + */ + void updateUser(@Valid MemberUserUpdateReqVO updateReqVO); + + /** + * 【管理员】获得会员用户分页 + * + * @param pageReqVO 分页查询 + * @return 会员用户分页 + */ + PageResult getUserPage(MemberUserPageReqVO pageReqVO); + + /** + * 更新用户的等级和经验 + * + * @param id 用户编号 + * @param levelId 用户等级 + * @param experience 用户经验 + */ + void updateUserLevel(Long id, Long levelId, Integer experience); + + /** + * 获得指定用户分组下的用户数量 + * + * @param groupId 用户分组编号 + * @return 用户数量 + */ + Long getUserCountByGroupId(Long groupId); + + /** + * 获得指定用户等级下的用户数量 + * + * @param levelId 用户等级编号 + * @return 用户数量 + */ + Long getUserCountByLevelId(Long levelId); + + /** + * 获得指定会员标签下的用户数量 + * + * @param tagId 用户标签编号 + * @return 用户数量 + */ + Long getUserCountByTagId(Long tagId); + + /** + * 更新用户的积分 + * + * @param userId 用户编号 + * @param point 积分数量 + * @return 更新结果 + */ + boolean updateUserPoint(Long userId, Integer point); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java new file mode 100644 index 0000000..f81e9a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java @@ -0,0 +1,317 @@ +package cn.iocoder.yudao.module.member.service.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.*; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; +import cn.iocoder.yudao.module.member.controller.app.user.vo.*; +import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; +import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; + +/** + * 会员 User Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Valid +@Slf4j +public class MemberUserServiceImpl implements MemberUserService { + + @Resource + private MemberUserMapper memberUserMapper; + + @Resource + private SmsCodeApi smsCodeApi; + + @Resource + private SocialClientApi socialClientApi; + + @Resource + private PasswordEncoder passwordEncoder; + + @Resource + private MemberUserProducer memberUserProducer; + + @Override + public MemberUserDO getUserByMobile(String mobile) { + return memberUserMapper.selectByMobile(mobile); + } + + @Override + public List getUserListByNickname(String nickname) { + return memberUserMapper.selectListByNicknameLike(nickname); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public MemberUserDO createUserIfAbsent(String mobile, String registerIp, Integer terminal) { + // 用户已经存在 + MemberUserDO user = memberUserMapper.selectByMobile(mobile); + if (user != null) { + return user; + } + // 用户不存在,则进行创建 + return createUser(mobile, null, null, registerIp, terminal); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public MemberUserDO createUser(String nickname, String avtar, String registerIp, Integer terminal) { + return createUser(null, nickname, avtar, registerIp, terminal); + } + + private MemberUserDO createUser(String mobile, String nickname, String avtar, + String registerIp, Integer terminal) { + // 生成密码 + String password = IdUtil.fastSimpleUUID(); + // 插入用户 + MemberUserDO user = new MemberUserDO(); + user.setMobile(mobile); + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 + user.setPassword(encodePassword(password)); // 加密密码 + user.setRegisterIp(registerIp).setRegisterTerminal(terminal); + user.setNickname(nickname).setAvatar(avtar); // 基础信息 + if (StrUtil.isEmpty(nickname)) { + // 昵称为空时,随机一个名字,避免一些依赖 nickname 的逻辑报错,或者有点丑。例如说,短信发送有昵称时~ + user.setNickname("用户" + RandomUtil.randomNumbers(6)); + } + memberUserMapper.insert(user); + + // 发送 MQ 消息:用户创建 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + memberUserProducer.sendUserCreateMessage(user.getId()); + } + + }); + return user; + } + + @Override + public void updateUserLogin(Long id, String loginIp) { + memberUserMapper.updateById(new MemberUserDO().setId(id) + .setLoginIp(loginIp).setLoginDate(LocalDateTime.now())); + } + + @Override + public MemberUserDO getUser(Long id) { + return memberUserMapper.selectById(id); + } + + @Override + public List getUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return memberUserMapper.selectBatchIds(ids); + } + + @Override + public void updateUser(Long userId, AppMemberUserUpdateReqVO reqVO) { + MemberUserDO updateObj = BeanUtils.toBean(reqVO, MemberUserDO.class).setId(userId); + memberUserMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateUserMobile(Long userId, AppMemberUserUpdateMobileReqVO reqVO) { + // 1.1 检测用户是否存在 + MemberUserDO user = validateUserExists(userId); + // 1.2 校验新手机是否已经被绑定 + validateMobileUnique(null, reqVO.getMobile()); + + // 2.1 校验旧手机和旧验证码 + // 补充说明:从安全性来说,老手机也校验 oldCode 验证码会更安全。但是由于 uni-app 商城界面暂时没做,所以这里不强制校验 + if (StrUtil.isNotEmpty(reqVO.getOldCode())) { + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode()) + .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); + } + // 2.2 使用新验证码 + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode()) + .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); + + // 3. 更新用户手机 + memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build()); + } + + @Override + public void updateUserMobileByWeixin(Long userId, AppMemberUserUpdateMobileByWeixinReqVO reqVO) { + // 1.1 获得对应的手机号信息 + SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo( + UserTypeEnum.MEMBER.getValue(), reqVO.getCode()); + Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空"); + // 1.2 校验新手机是否已经被绑定 + validateMobileUnique(userId, phoneNumberInfo.getPhoneNumber()); + + // 2. 更新用户手机 + memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(phoneNumberInfo.getPhoneNumber()).build()); + } + + @Override + public void updateUserPassword(Long userId, AppMemberUserUpdatePasswordReqVO reqVO) { + // 检测用户是否存在 + MemberUserDO user = validateUserExists(userId); + // 校验验证码 + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getCode()) + .setScene(SmsSceneEnum.MEMBER_UPDATE_PASSWORD.getScene()).setUsedIp(getClientIP())); + + // 更新用户密码 + memberUserMapper.updateById(MemberUserDO.builder().id(userId) + .password(passwordEncoder.encode(reqVO.getPassword())).build()); + } + + @Override + public void resetUserPassword(AppMemberUserResetPasswordReqVO reqVO) { + // 检验用户是否存在 + MemberUserDO user = validateUserExists(reqVO.getMobile()); + + // 使用验证码 + smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD, + getClientIP())); + + // 更新密码 + memberUserMapper.updateById(MemberUserDO.builder().id(user.getId()) + .password(passwordEncoder.encode(reqVO.getPassword())).build()); + } + + private MemberUserDO validateUserExists(String mobile) { + MemberUserDO user = memberUserMapper.selectByMobile(mobile); + if (user == null) { + throw exception(USER_MOBILE_NOT_EXISTS); + } + return user; + } + + @Override + public boolean isPasswordMatch(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 对密码进行加密 + * + * @param password 密码 + * @return 加密后的密码 + */ + private String encodePassword(String password) { + return passwordEncoder.encode(password); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateUser(MemberUserUpdateReqVO updateReqVO) { + // 校验存在 + validateUserExists(updateReqVO.getId()); + // 校验手机唯一 + validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile()); + + // 更新 + MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO); + memberUserMapper.updateById(updateObj); + } + + @VisibleForTesting + MemberUserDO validateUserExists(Long id) { + if (id == null) { + return null; + } + MemberUserDO user = memberUserMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + + @VisibleForTesting + void validateMobileUnique(Long id, String mobile) { + if (StrUtil.isBlank(mobile)) { + return; + } + MemberUserDO user = memberUserMapper.selectByMobile(mobile); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(USER_MOBILE_USED, mobile); + } + if (!user.getId().equals(id)) { + throw exception(USER_MOBILE_USED, mobile); + } + } + + @Override + public PageResult getUserPage(MemberUserPageReqVO pageReqVO) { + return memberUserMapper.selectPage(pageReqVO); + } + + @Override + public void updateUserLevel(Long id, Long levelId, Integer experience) { + // 0 代表无等级:防止UpdateById时,会被过滤掉的问题 + levelId = ObjectUtil.defaultIfNull(levelId, 0L); + memberUserMapper.updateById(new MemberUserDO() + .setId(id) + .setLevelId(levelId).setExperience(experience) + ); + } + + @Override + public Long getUserCountByGroupId(Long groupId) { + return memberUserMapper.selectCountByGroupId(groupId); + } + + @Override + public Long getUserCountByLevelId(Long levelId) { + return memberUserMapper.selectCountByLevelId(levelId); + } + + @Override + public Long getUserCountByTagId(Long tagId) { + return memberUserMapper.selectCountByTagId(tagId); + } + + @Override + public boolean updateUserPoint(Long id, Integer point) { + if (point > 0) { + memberUserMapper.updatePointIncr(id, point); + } else if (point < 0) { + return memberUserMapper.updatePointDecr(id, point) > 0; + } + return true; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/MemberAddressServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/MemberAddressServiceImplTest.java new file mode 100644 index 0000000..f584993 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/MemberAddressServiceImplTest.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.member.service.address; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; +import cn.iocoder.yudao.module.member.dal.mysql.address.MemberAddressMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.ADDRESS_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * {@link AddressServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(AddressServiceImpl.class) +public class MemberAddressServiceImplTest extends BaseDbUnitTest { + + @Resource + private AddressServiceImpl addressService; + + @Resource + private MemberAddressMapper addressMapper; + + @Test + public void testCreateAddress_success() { + // 准备参数 + AppAddressCreateReqVO reqVO = randomPojo(AppAddressCreateReqVO.class); + + // 调用 + Long addressId = addressService.createAddress(randomLongId(), reqVO); + // 断言 + assertNotNull(addressId); + // 校验记录的属性是否正确 + MemberAddressDO address = addressMapper.selectById(addressId); + assertPojoEquals(reqVO, address); + } + + @Test + public void testUpdateAddress_success() { + // mock 数据 + MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class); + addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据 + // 准备参数 + AppAddressUpdateReqVO reqVO = randomPojo(AppAddressUpdateReqVO.class, o -> { + o.setId(dbAddress.getId()); // 设置更新的 ID + }); + + // 调用 + addressService.updateAddress(dbAddress.getUserId(), reqVO); + // 校验是否更新正确 + MemberAddressDO address = addressMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, address); + } + + @Test + public void testUpdateAddress_notExists() { + // 准备参数 + AppAddressUpdateReqVO reqVO = randomPojo(AppAddressUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> addressService.updateAddress(randomLongId(), reqVO), ADDRESS_NOT_EXISTS); + } + + @Test + public void testDeleteAddress_success() { + // mock 数据 + MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class); + addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbAddress.getId(); + + // 调用 + addressService.deleteAddress(dbAddress.getUserId(), id); + // 校验数据不存在了 + assertNull(addressMapper.selectById(id)); + } + + @Test + public void testDeleteAddress_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> addressService.deleteAddress(randomLongId(), id), ADDRESS_NOT_EXISTS); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java new file mode 100644 index 0000000..78ddc56 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.member.service.auth; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.social.SocialUserApi; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.security.crypto.password.PasswordEncoder; + +import javax.annotation.Resource; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; + +// TODO @芋艿:单测的 review,等逻辑都达成一致后 +/** + * {@link MemberAuthService} 的单元测试类 + * + * @author 宋天 + */ +@Import({MemberAuthServiceImpl.class, YudaoRedisAutoConfiguration.class}) +public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest { + + // TODO @芋艿:登录相关的单测,待补全 + + @Resource + private MemberAuthServiceImpl authService; + + @MockBean + private MemberUserService userService; + @MockBean + private SmsCodeApi smsCodeApi; + @MockBean + private LoginLogApi loginLogApi; + @MockBean + private OAuth2TokenApi oauth2TokenApi; + @MockBean + private SocialUserApi socialUserApi; + @MockBean + private PasswordEncoder passwordEncoder; + + @Resource + private MemberUserMapper memberUserMapper; + + // TODO 芋艿:后续重构这个单测 +// @Test +// public void testUpdatePassword_success(){ +// // 准备参数 +// MemberUserDO userDO = randomUserDO(); +// memberUserMapper.insert(userDO); +// +// // 新密码 +// String newPassword = randomString(); +// +// // 请求实体 +// AppMemberUserUpdatePasswordReqVO reqVO = AppMemberUserUpdatePasswordReqVO.builder() +// .oldPassword(userDO.getPassword()) +// .password(newPassword) +// .build(); +// +// // 测试桩 +// // 这两个相等是为了返回ture这个结果 +// when(passwordEncoder.matches(reqVO.getOldPassword(),reqVO.getOldPassword())).thenReturn(true); +// when(passwordEncoder.encode(newPassword)).thenReturn(newPassword); +// +// // 更新用户密码 +// authService.updatePassword(userDO.getId(), reqVO); +// assertEquals(memberUserMapper.selectById(userDO.getId()).getPassword(),newPassword); +// } + + // TODO 芋艿:后续重构这个单测 +// @Test +// public void testResetPassword_success(){ +// // 准备参数 +// MemberUserDO userDO = randomUserDO(); +// memberUserMapper.insert(userDO); +// +// // 随机密码 +// String password = randomNumbers(11); +// // 随机验证码 +// String code = randomNumbers(4); +// +// // mock +// when(passwordEncoder.encode(password)).thenReturn(password); +// +// // 更新用户密码 +// AppMemberUserResetPasswordReqVO reqVO = new AppMemberUserResetPasswordReqVO(); +// reqVO.setMobile(userDO.getMobile()); +// reqVO.setPassword(password); +// reqVO.setCode(code); +// +// authService.resetPassword(reqVO); +// assertEquals(memberUserMapper.selectById(userDO.getId()).getPassword(),password); +// } + + // ========== 随机对象 ========== + + @SafeVarargs + private static MemberUserDO randomUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setPassword(randomString()); + }; + return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers)); + } + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImplTest.java new file mode 100644 index 0000000..6d8e6f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/group/MemberGroupServiceImplTest.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.member.service.group; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; +import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_HAS_USER; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +// TODO 芋艿:完全 review 完,在去 review 单测 +/** + * {@link MemberGroupServiceImpl} 的单元测试类 + * + * @author owen + */ +@Import(MemberGroupServiceImpl.class) +public class MemberGroupServiceImplTest extends BaseDbUnitTest { + + @Resource + private MemberGroupServiceImpl groupService; + + @Resource + private MemberGroupMapper groupMapper; + + @MockBean + private MemberUserService memberUserService; + + @Test + public void testCreateGroup_success() { + // 准备参数 + MemberGroupCreateReqVO reqVO = randomPojo(MemberGroupCreateReqVO.class, + o -> o.setStatus(randomCommonStatus())); + + // 调用 + Long groupId = groupService.createGroup(reqVO); + // 断言 + assertNotNull(groupId); + // 校验记录的属性是否正确 + MemberGroupDO group = groupMapper.selectById(groupId); + assertPojoEquals(reqVO, group); + } + + @Test + public void testUpdateGroup_success() { + // mock 数据 + MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class); + groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MemberGroupUpdateReqVO reqVO = randomPojo(MemberGroupUpdateReqVO.class, o -> { + o.setId(dbGroup.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用 + groupService.updateGroup(reqVO); + // 校验是否更新正确 + MemberGroupDO group = groupMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, group); + } + + @Test + public void testUpdateGroup_notExists() { + // 准备参数 + MemberGroupUpdateReqVO reqVO = randomPojo(MemberGroupUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> groupService.updateGroup(reqVO), GROUP_NOT_EXISTS); + } + + @Test + public void testDeleteGroup_success() { + // mock 数据 + MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class); + groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbGroup.getId(); + + // 调用 + groupService.deleteGroup(id); + // 校验数据不存在了 + assertNull(groupMapper.selectById(id)); + } + + @Test + public void testDeleteGroup_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> groupService.deleteGroup(id), GROUP_NOT_EXISTS); + } + + @Test + public void testDeleteGroup_hasUser() { + // mock 数据 + MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class); + groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbGroup.getId(); + + // mock 会员数据 + when(memberUserService.getUserCountByGroupId(eq(id))).thenReturn(1L); + + // 调用, 并断言异常 + assertServiceException(() -> groupService.deleteGroup(id), GROUP_HAS_USER); + } + + @Test + public void testGetGroupPage() { + String name = randomString(); + int status = CommonStatusEnum.ENABLE.getStatus(); + + // mock 数据 + MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class, o -> { // 等会查询到 + o.setName(name); + o.setStatus(status); + o.setCreateTime(buildTime(2023, 2, 18)); + }); + groupMapper.insert(dbGroup); + // 测试 name 不匹配 + groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setName(""))); + // 测试 status 不匹配 + groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setCreateTime(null))); + // 准备参数 + MemberGroupPageReqVO reqVO = new MemberGroupPageReqVO(); + reqVO.setName(name); + reqVO.setStatus(status); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = groupService.getGroupPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbGroup, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImplTest.java new file mode 100644 index 0000000..4393229 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImplTest.java @@ -0,0 +1,268 @@ +package cn.iocoder.yudao.module.member.service.level; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelListReqVO; +import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; +import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomInt; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; + +// TODO 芋艿:完全 review 完,在去 review 单测 +/** + * {@link MemberLevelServiceImpl} 的单元测试类 + * + * @author owen + */ +@Import(MemberLevelServiceImpl.class) +public class MemberLevelServiceImplTest extends BaseDbUnitTest { + + @Resource + private MemberLevelServiceImpl levelService; + + @Resource + private MemberLevelMapper memberlevelMapper; + + @MockBean + private MemberLevelRecordService memberLevelRecordService; + @MockBean + private MemberExperienceRecordService memberExperienceRecordService; + @MockBean + private MemberUserService memberUserService; + + @Test + public void testCreateLevel_success() { + // 准备参数 + MemberLevelCreateReqVO reqVO = randomPojo(MemberLevelCreateReqVO.class, o -> { + o.setDiscountPercent(randomInt()); + o.setIcon(randomURL()); + o.setBackgroundUrl(randomURL()); + o.setStatus(randomCommonStatus()); + }); + + // 调用 + Long levelId = levelService.createLevel(reqVO); + // 断言 + assertNotNull(levelId); + // 校验记录的属性是否正确 + MemberLevelDO level = memberlevelMapper.selectById(levelId); + assertPojoEquals(reqVO, level); + } + + @Test + public void testUpdateLevel_success() { + // mock 数据 + MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class); + memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MemberLevelUpdateReqVO reqVO = randomPojo(MemberLevelUpdateReqVO.class, o -> { + o.setId(dbLevel.getId()); // 设置更新的 ID + //以下要保持一致 + o.setName(dbLevel.getName()); + o.setLevel(dbLevel.getLevel()); + o.setExperience(dbLevel.getExperience()); + //以下是要修改的字段 + o.setDiscountPercent(randomInt()); + o.setIcon(randomURL()); + o.setBackgroundUrl(randomURL()); + o.setStatus(randomCommonStatus()); + }); + + // 调用 + levelService.updateLevel(reqVO); + // 校验是否更新正确 + MemberLevelDO level = memberlevelMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, level); + } + + @Test + public void testUpdateLevel_notExists() { + // 准备参数 + MemberLevelUpdateReqVO reqVO = randomPojo(MemberLevelUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> levelService.updateLevel(reqVO), LEVEL_NOT_EXISTS); + } + + @Test + public void testDeleteLevel_success() { + // mock 数据 + MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class); + memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbLevel.getId(); + + // 调用 + levelService.deleteLevel(id); + // 校验数据不存在了 + assertNull(memberlevelMapper.selectById(id)); + } + + @Test + public void testDeleteLevel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> levelService.deleteLevel(id), LEVEL_NOT_EXISTS); + } + + @Test + public void testGetLevelList() { + // mock 数据 + MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class, o -> { // 等会查询到 + o.setName("黄金会员"); + o.setStatus(1); + }); + memberlevelMapper.insert(dbLevel); + // 测试 name 不匹配 + memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setName(""))); + // 测试 status 不匹配 + memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setStatus(0))); + // 准备参数 + MemberLevelListReqVO reqVO = new MemberLevelListReqVO(); + reqVO.setName("黄金会员"); + reqVO.setStatus(1); + + // 调用 + List list = levelService.getLevelList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbLevel, list.get(0)); + } + + @Test + public void testCreateLevel_nameUnique() { + // 准备参数 + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> o.setName(name))); + + // 调用,校验异常 + List list = memberlevelMapper.selectList(); + assertServiceException(() -> levelService.validateNameUnique(list, null, name), LEVEL_NAME_EXISTS, name); + } + + @Test + public void testUpdateLevel_nameUnique() { + // 准备参数 + Long id = randomLongId(); + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> o.setName(name))); + + // 调用,校验异常 + List list = memberlevelMapper.selectList(); + assertServiceException(() -> levelService.validateNameUnique(list, id, name), LEVEL_NAME_EXISTS, name); + } + + @Test + public void testCreateLevel_levelUnique() { + // 准备参数 + Integer level = randomInteger(); + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> { + o.setLevel(level); + o.setName(name); + })); + + // 调用,校验异常 + List list = memberlevelMapper.selectList(); + assertServiceException(() -> levelService.validateLevelUnique(list, null, level), LEVEL_VALUE_EXISTS, level, name); + } + + @Test + public void testUpdateLevel_levelUnique() { + // 准备参数 + Long id = randomLongId(); + Integer level = randomInteger(); + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> { + o.setLevel(level); + o.setName(name); + })); + + // 调用,校验异常 + List list = memberlevelMapper.selectList(); + assertServiceException(() -> levelService.validateLevelUnique(list, id, level), LEVEL_VALUE_EXISTS, level, name); + } + + @Test + public void testCreateLevel_experienceOutRange() { + // 准备参数 + int level = 10; + int experience = 10; + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> { + o.setLevel(level); + o.setExperience(experience); + o.setName(name); + })); + List list = memberlevelMapper.selectList(); + + // 调用,校验异常 + assertServiceException(() -> levelService.validateExperienceOutRange(list, null, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level); + // 调用,校验异常 + assertServiceException(() -> levelService.validateExperienceOutRange(list, null, level - 1, experience + 1), LEVEL_EXPERIENCE_MAX, name, level); + } + + @Test + public void testUpdateLevel_experienceOutRange() { + // 准备参数 + int level = 10; + int experience = 10; + Long id = randomLongId(); + String name = randomString(); + + // mock 数据 + memberlevelMapper.insert(randomLevelDO(o -> { + o.setLevel(level); + o.setExperience(experience); + o.setName(name); + })); + List list = memberlevelMapper.selectList(); + + // 调用,校验异常 + assertServiceException(() -> levelService.validateExperienceOutRange(list, id, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level); + // 调用,校验异常 + assertServiceException(() -> levelService.validateExperienceOutRange(list, id, level - 1, experience + 1), LEVEL_EXPERIENCE_MAX, name, level); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static MemberLevelDO randomLevelDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setDiscountPercent(randomInt(0, 100)); + o.setIcon(randomURL()); + o.setBackgroundUrl(randomURL()); + }; + return randomPojo(MemberLevelDO.class, ArrayUtils.append(consumer, consumers)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImplTest.java new file mode 100644 index 0000000..5fd4f7a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/tag/MemberTagServiceImplTest.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.module.member.service.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO; +import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; +import cn.iocoder.yudao.module.member.dal.mysql.tag.MemberTagMapper; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.TAG_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +// TODO 芋艿:完全 review 完,在去 review 单测 +/** + * {@link MemberTagServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(MemberTagServiceImpl.class) +public class MemberTagServiceImplTest extends BaseDbUnitTest { + + @Resource + private MemberTagServiceImpl tagService; + + @Resource + private MemberTagMapper tagMapper; + + @MockBean + private MemberUserService memberUserService; + + @Test + public void testCreateTag_success() { + // 准备参数 + MemberTagCreateReqVO reqVO = randomPojo(MemberTagCreateReqVO.class); + + // 调用 + Long tagId = tagService.createTag(reqVO); + // 断言 + assertNotNull(tagId); + // 校验记录的属性是否正确 + MemberTagDO tag = tagMapper.selectById(tagId); + assertPojoEquals(reqVO, tag); + } + + @Test + public void testUpdateTag_success() { + // mock 数据 + MemberTagDO dbTag = randomPojo(MemberTagDO.class); + tagMapper.insert(dbTag);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MemberTagUpdateReqVO reqVO = randomPojo(MemberTagUpdateReqVO.class, o -> { + o.setId(dbTag.getId()); // 设置更新的 ID + }); + + // 调用 + tagService.updateTag(reqVO); + // 校验是否更新正确 + MemberTagDO tag = tagMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, tag); + } + + @Test + public void testUpdateTag_notExists() { + // 准备参数 + MemberTagUpdateReqVO reqVO = randomPojo(MemberTagUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> tagService.updateTag(reqVO), TAG_NOT_EXISTS); + } + + @Test + public void testDeleteTag_success() { + // mock 数据 + MemberTagDO dbTag = randomPojo(MemberTagDO.class); + tagMapper.insert(dbTag);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTag.getId(); + + // 调用 + tagService.deleteTag(id); + // 校验数据不存在了 + assertNull(tagMapper.selectById(id)); + } + + @Test + public void testDeleteTag_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> tagService.deleteTag(id), TAG_NOT_EXISTS); + } + + @Test + public void testGetTagPage() { + // mock 数据 + MemberTagDO dbTag = randomPojo(MemberTagDO.class, o -> { // 等会查询到 + o.setName("test"); + o.setCreateTime(buildTime(2023, 2, 18)); + }); + tagMapper.insert(dbTag); + // 测试 name 不匹配 + tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setName("ne"))); + // 测试 createTime 不匹配 + tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setCreateTime(null))); + // 准备参数 + MemberTagPageReqVO reqVO = new MemberTagPageReqVO(); + reqVO.setName("test"); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = tagService.getTagPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbTag, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImplTest.java new file mode 100644 index 0000000..85e01d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImplTest.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.member.service.user; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateMobileReqVO; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; +import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.crypto.password.PasswordEncoder; + +import javax.annotation.Resource; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.hutool.core.util.RandomUtil.randomNumbers; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO @芋艿:单测的 review,等逻辑都达成一致后 +/** + * {@link MemberUserServiceImpl} 的单元测试类 + * + * @author 宋天 + */ +@Disabled +@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) +public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest { + + @Resource + private MemberUserServiceImpl memberUserService; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Resource + private MemberUserMapper userMapper; + + @MockBean + private MemberAuthServiceImpl authService; + + @MockBean + private PasswordEncoder passwordEncoder; + + @MockBean + private SmsCodeApi smsCodeApi; + @MockBean + private FileApi fileApi; + + // TODO 芋艿:后续重构这个单测 +// @Test +// public void testUpdateNickName_success(){ +// // mock 数据 +// MemberUserDO userDO = randomUserDO(); +// userMapper.insert(userDO); +// +// // 随机昵称 +// String newNickName = randomString(); +// +// // 调用接口修改昵称 +// memberUserService.updateUser(userDO.getId(),newNickName); +// // 查询新修改后的昵称 +// String nickname = memberUserService.getUser(userDO.getId()).getNickname(); +// // 断言 +// assertEquals(newNickName,nickname); +// } +// +// @Test +// public void testUpdateAvatar_success() throws Exception { +// // mock 数据 +// MemberUserDO dbUser = randomUserDO(); +// userMapper.insert(dbUser); +// +// // 准备参数 +// Long userId = dbUser.getId(); +// byte[] avatarFileBytes = randomBytes(10); +// ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); +// // mock 方法 +// String avatar = randomString(); +// when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar); +// // 调用 +// String str = memberUserService.updateUserAvatar(userId, avatarFile); +// // 断言 +// assertEquals(avatar, str); +// } + + @Test + @Disabled // TODO 芋艿:后续再修复 + public void updateMobile_success(){ + // mock数据 + String oldMobile = randomNumbers(11); + MemberUserDO userDO = randomUserDO(); + userDO.setMobile(oldMobile); + userMapper.insert(userDO); + + // TODO 芋艿:需要修复该单元测试,重构多模块带来的 + // 旧手机和旧验证码 +// SmsCodeDO codeDO = new SmsCodeDO(); + String oldCode = RandomUtil.randomString(4); +// codeDO.setMobile(userDO.getMobile()); +// codeDO.setCode(oldCode); +// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()); +// codeDO.setUsed(Boolean.FALSE); +// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO); + + // 更新手机号 + String newMobile = randomNumbers(11); + String newCode = randomNumbers(4); + AppMemberUserUpdateMobileReqVO reqVO = new AppMemberUserUpdateMobileReqVO(); + reqVO.setMobile(newMobile); + reqVO.setCode(newCode); + reqVO.setOldCode(oldCode); + memberUserService.updateUserMobile(userDO.getId(),reqVO); + + assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static MemberUserDO randomUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + }; + return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..c656a9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,47 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..f972e04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,5 @@ +DELETE FROM "member_user"; +DELETE FROM "member_address"; +DELETE FROM "member_tag"; +DELETE FROM "member_level"; +DELETE FROM "member_group"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..782a818 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-member/yudao-module-member-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,113 @@ +CREATE TABLE IF NOT EXISTS "member_user" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', + "nickname" varchar(30) NOT NULL DEFAULT '' COMMENT '用户昵称', + "name" varchar(30) NULL COMMENT '真实名字', + sex tinyint null comment '性别', + birthday datetime null comment '出生日期', + area_id int null comment '所在地', + mark varchar(255) null comment '用户备注', + point int default 0 null comment '积分', + "avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '头像', + "status" tinyint NOT NULL COMMENT '状态', + "mobile" varchar(11) NOT NULL COMMENT '手机号', + "password" varchar(100) NOT NULL DEFAULT '' COMMENT '密码', + "register_ip" varchar(32) NOT NULL COMMENT '注册 IP', + "login_ip" varchar(50) NULL DEFAULT '' COMMENT '最后登录IP', + "login_date" datetime NULL DEFAULT NULL COMMENT '最后登录时间', + "tag_ids" varchar(255) NULL DEFAULT NULL COMMENT '用户标签编号列表,以逗号分隔', + "level_id" bigint NULL DEFAULT NULL COMMENT '等级编号', + "experience" bigint NULL DEFAULT NULL COMMENT '经验', + "group_id" bigint NULL DEFAULT NULL COMMENT '用户分组编号', + "creator" varchar(64) NULL DEFAULT '' COMMENT '创建者', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + "updater" varchar(64) NULL DEFAULT '' COMMENT '更新者', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + "deleted" bit(1) NOT NULL DEFAULT '0' COMMENT '是否删除', + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '会员表'; + +CREATE TABLE IF NOT EXISTS "member_address" ( + "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint(20) NOT NULL, + "name" varchar(10) NOT NULL, + "mobile" varchar(20) NOT NULL, + "area_id" bigint(20) NOT NULL, + "detail_address" varchar(250) NOT NULL, + "default_status" bit NOT NULL, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "creator" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "updater" varchar(64) DEFAULT '', + PRIMARY KEY ("id") +) COMMENT '用户收件地址'; + +CREATE TABLE IF NOT EXISTS "member_tag" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL default '0', + PRIMARY KEY ("id") +) COMMENT '会员标签'; + +CREATE TABLE IF NOT EXISTS "member_level" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "experience" int NOT NULL, + "level" int NOT NULL, + "discount_percent" int NOT NULL, + "icon" varchar NOT NULL, + "background_url" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + "status" tinyint NOT NULL DEFAULT '0', + PRIMARY KEY ("id") +) COMMENT '会员等级'; + +CREATE TABLE IF NOT EXISTS "member_group" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "remark" varchar NOT NULL, + "status" tinyint NOT NULL DEFAULT '0', + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '用户分组'; +CREATE TABLE IF NOT EXISTS "member_brokerage_record" +( + "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "biz_id" varchar NOT NULL, + "biz_type" varchar NOT NULL, + "title" varchar NOT NULL, + "price" int NOT NULL, + "total_price" int NOT NULL, + "description" varchar NOT NULL, + "status" varchar NOT NULL, + "frozen_days" int NOT NULL, + "unfreeze_time" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '佣金记录'; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/pom.xml b/ruoyi-vue-pro-master/yudao-module-mp/pom.xml new file mode 100644 index 0000000..b339c40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/pom.xml @@ -0,0 +1,24 @@ + + + + yudao + cn.iocoder.boot + ${revision} + + 4.0.0 + + yudao-module-mp + pom + + + wechat 模块,主要实现微信平台的相关业务。 + 例如:微信公众号、企业微信 SCRM 等 + + + yudao-module-mp-api + yudao-module-mp-biz + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/pom.xml new file mode 100644 index 0000000..64b6f50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/pom.xml @@ -0,0 +1,26 @@ + + + + yudao-module-mp + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-mp-api + jar + + ${project.artifactId} + + mp 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..34c94fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.mp.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Mp 错误码枚举类 + * + * mp 系统,使用 1-006-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 公众号账号 1-006-000-000 ============ + ErrorCode ACCOUNT_NOT_EXISTS = new ErrorCode(1_006_000_000, "公众号账号不存在"); + ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1_006_000_001, "生成公众号二维码失败,原因:{}"); + ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1_006_000_002, "清空公众号的 API 配额失败,原因:{}"); + + // ========== 公众号统计 1-006-001-000 ============ + ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1_006_001_000, "获取粉丝增减数据失败,原因:{}"); + ErrorCode STATISTICS_GET_USER_CUMULATE_FAIL = new ErrorCode(1_006_001_001, "获得粉丝累计数据失败,原因:{}"); + ErrorCode STATISTICS_GET_UPSTREAM_MESSAGE_FAIL = new ErrorCode(1_006_001_002, "获得消息发送概况数据失败,原因:{}"); + ErrorCode STATISTICS_GET_INTERFACE_SUMMARY_FAIL = new ErrorCode(1_006_001_003, "获得接口分析数据失败,原因:{}"); + + // ========== 公众号标签 1-006-002-000 ============ + ErrorCode TAG_NOT_EXISTS = new ErrorCode(1_006_002_000, "标签不存在"); + ErrorCode TAG_CREATE_FAIL = new ErrorCode(1_006_002_001, "创建标签失败,原因:{}"); + ErrorCode TAG_UPDATE_FAIL = new ErrorCode(1_006_002_002, "更新标签失败,原因:{}"); + ErrorCode TAG_DELETE_FAIL = new ErrorCode(1_006_002_003, "删除标签失败,原因:{}"); + ErrorCode TAG_GET_FAIL = new ErrorCode(1_006_002_004, "获得标签失败,原因:{}"); + + // ========== 公众号粉丝 1-006-003-000 ============ + ErrorCode USER_NOT_EXISTS = new ErrorCode(1_006_003_000, "粉丝不存在"); + ErrorCode USER_UPDATE_TAG_FAIL = new ErrorCode(1_006_003_001, "更新粉丝标签失败,原因:{}"); + + // ========== 公众号素材 1-006-004-000 ============ + ErrorCode MATERIAL_NOT_EXISTS = new ErrorCode(1_006_004_000, "素材不存在"); + ErrorCode MATERIAL_UPLOAD_FAIL = new ErrorCode(1_006_004_001, "上传素材失败,原因:{}"); + ErrorCode MATERIAL_IMAGE_UPLOAD_FAIL = new ErrorCode(1_006_004_002, "上传图片失败,原因:{}"); + ErrorCode MATERIAL_DELETE_FAIL = new ErrorCode(1_006_004_003, "删除素材失败,原因:{}"); + + // ========== 公众号消息 1-006-005-000 ============ + ErrorCode MESSAGE_SEND_FAIL = new ErrorCode(1_006_005_000, "发送消息失败,原因:{}"); + + // ========== 公众号发布能力 1-006-006-000 ============ + ErrorCode FREE_PUBLISH_LIST_FAIL = new ErrorCode(1_006_006_000, "获得已成功发布列表失败,原因:{}"); + ErrorCode FREE_PUBLISH_SUBMIT_FAIL = new ErrorCode(1_006_006_001, "提交发布失败,原因:{}"); + ErrorCode FREE_PUBLISH_DELETE_FAIL = new ErrorCode(1_006_006_002, "删除发布失败,原因:{}"); + + // ========== 公众号草稿 1-006-007-000 ============ + ErrorCode DRAFT_LIST_FAIL = new ErrorCode(1_006_007_000, "获得草稿列表失败,原因:{}"); + ErrorCode DRAFT_CREATE_FAIL = new ErrorCode(1_006_007_001, "创建草稿失败,原因:{}"); + ErrorCode DRAFT_UPDATE_FAIL = new ErrorCode(1_006_007_002, "更新草稿失败,原因:{}"); + ErrorCode DRAFT_DELETE_FAIL = new ErrorCode(1_006_007_003, "删除草稿失败,原因:{}"); + + // ========== 公众号菜单 1-006-008-000 ============ + ErrorCode MENU_SAVE_FAIL = new ErrorCode(1_006_008_000, "创建菜单失败,原因:{}"); + ErrorCode MENU_DELETE_FAIL = new ErrorCode(1_006_008_001, "删除菜单失败,原因:{}"); + + // ========== 公众号自动回复 1-006-009-000 ============ + ErrorCode AUTO_REPLY_NOT_EXISTS = new ErrorCode(1_006_009_000, "自动回复不存在"); + ErrorCode AUTO_REPLY_ADD_SUBSCRIBE_FAIL_EXISTS = new ErrorCode(1_006_009_001, "操作失败,原因:已存在关注时的回复"); + ErrorCode AUTO_REPLY_ADD_MESSAGE_FAIL_EXISTS = new ErrorCode(1_006_009_002, "操作失败,原因:已存在该消息类型的回复"); + ErrorCode AUTO_REPLY_ADD_KEYWORD_FAIL_EXISTS = new ErrorCode(1_006_009_003, "操作失败,原因:已关在该关键字的回复"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyMatchEnum.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyMatchEnum.java new file mode 100644 index 0000000..a5298db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyMatchEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.mp.enums.message; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 公众号消息自动回复的匹配模式 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MpAutoReplyMatchEnum { + + ALL(1, "完全匹配"), + LIKE(2, "半匹配"), + ; + + /** + * 匹配 + */ + private final Integer match; + /** + * 匹配的名字 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyTypeEnum.java new file mode 100644 index 0000000..300f1f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpAutoReplyTypeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.mp.enums.message; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 公众号消息自动回复的类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MpAutoReplyTypeEnum { + + SUBSCRIBE(1, "关注时回复"), + MESSAGE(2, "收到消息回复"), + KEYWORD(3, "关键词回复"), + ; + + /** + * 来源 + */ + private final Integer type; + /** + * 类型的名字 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpMessageSendFromEnum.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpMessageSendFromEnum.java new file mode 100644 index 0000000..a2af484 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/message/MpMessageSendFromEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.mp.enums.message; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 微信公众号消息的发送来源 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MpMessageSendFromEnum { + + USER_TO_MP(1, "粉丝发送给公众号"), + MP_TO_USER(2, "公众号发给粉丝"), + ; + + /** + * 来源 + */ + private final Integer from; + /** + * 来源的名字 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/package-info.java new file mode 100644 index 0000000..5987180 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/package-info.java @@ -0,0 +1,8 @@ +/** + * mp 模块,我们放微信微信公众号。 + * 例如说:提供微信公众号的账号、菜单、粉丝、标签、消息、自动回复、素材、模板通知、运营数据等功能 + * + * 1. Controller URL:以 /mp/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 mp_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.mp; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/pom.xml new file mode 100644 index 0000000..5e3fefb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/pom.xml @@ -0,0 +1,91 @@ + + + + yudao-module-mp + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-mp-biz + jar + + ${project.artifactId} + + mp 模块,我们放微信微信公众号。 + 例如说:提供微信公众号的账号、菜单、粉丝、标签、消息、自动回复、素材、模板通知、运营数据等功能 + + + + + cn.iocoder.boot + yudao-module-mp-api + ${revision} + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-infra-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-validation + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + + com.github.binarywang + wx-java-mp-spring-boot-starter + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java new file mode 100644 index 0000000..62be175 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.*; +import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号账号") +@RestController +@RequestMapping("/mp/account") +@Validated +public class MpAccountController { + + @Resource + private MpAccountService mpAccountService; + + @PostMapping("/create") + @Operation(summary = "创建公众号账号") + @PreAuthorize("@ss.hasPermission('mp:account:create')") + public CommonResult createAccount(@Valid @RequestBody MpAccountCreateReqVO createReqVO) { + return success(mpAccountService.createAccount(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新公众号账号") + @PreAuthorize("@ss.hasPermission('mp:account:update')") + public CommonResult updateAccount(@Valid @RequestBody MpAccountUpdateReqVO updateReqVO) { + mpAccountService.updateAccount(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除公众号账号") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:account:delete')") + public CommonResult deleteAccount(@RequestParam("id") Long id) { + mpAccountService.deleteAccount(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得公众号账号") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:account:query')") + public CommonResult getAccount(@RequestParam("id") Long id) { + MpAccountDO wxAccount = mpAccountService.getAccount(id); + return success(MpAccountConvert.INSTANCE.convert(wxAccount)); + } + + @GetMapping("/page") + @Operation(summary = "获得公众号账号分页") + @PreAuthorize("@ss.hasPermission('mp:account:query')") + public CommonResult> getAccountPage(@Valid MpAccountPageReqVO pageVO) { + PageResult pageResult = mpAccountService.getAccountPage(pageVO); + return success(MpAccountConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取公众号账号精简信息列表") + @PreAuthorize("@ss.hasPermission('mp:account:query')") + public CommonResult> getSimpleAccounts() { + List list = mpAccountService.getAccountList(); + return success(MpAccountConvert.INSTANCE.convertList02(list)); + } + + @PutMapping("/generate-qr-code") + @Operation(summary = "生成公众号二维码") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:account:qr-code')") + public CommonResult generateAccountQrCode(@RequestParam("id") Long id) { + mpAccountService.generateAccountQrCode(id); + return success(true); + } + + @PutMapping("/clear-quota") + @Operation(summary = "清空公众号 API 配额") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:account:clear-quota')") + public CommonResult clearAccountQuota(@RequestParam("id") Long id) { + mpAccountService.clearAccountQuota(id); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountBaseVO.java new file mode 100644 index 0000000..8f68830 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountBaseVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +/** + * 公众号账号 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author fengdan + */ +@Data +public class MpAccountBaseVO { + + @Schema(description = "公众号名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotEmpty(message = "公众号名称不能为空") + private String name; + + @Schema(description = "公众号微信号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "公众号微信号不能为空") + private String account; + + @Schema(description = "公众号 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx5b23ba7a5589ecbb") + @NotEmpty(message = "公众号 appId 不能为空") + private String appId; + + @Schema(description = "公众号密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "3a7b3b20c537e52e74afd395eb85f61f") + @NotEmpty(message = "公众号密钥不能为空") + private String appSecret; + + @Schema(description = "公众号 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "kangdayuzhen") + @NotEmpty(message = "公众号 token 不能为空") + private String token; + + @Schema(description = "加密密钥", example = "gjN+Ksei") + private String aesKey; + + @Schema(description = "备注", example = "请关注芋道源码,学习技术") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountCreateReqVO.java new file mode 100644 index 0000000..b864f16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 公众号账号创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAccountCreateReqVO extends MpAccountBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountPageReqVO.java new file mode 100644 index 0000000..93093dc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 公众号账号分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAccountPageReqVO extends PageParam { + + @Schema(name = "公众号名称", description = "模糊匹配") + private String name; + + @Schema(name = "公众号账号", description = "模糊匹配") + private String account; + + @Schema(name = "公众号 appid", description = "模糊匹配") + private String appId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountRespVO.java new file mode 100644 index 0000000..0f7ca7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号账号 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAccountRespVO extends MpAccountBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "二维码图片URL", example = "https://www.iocoder.cn/1024.png") + private String qrCodeUrl; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountSimpleRespVO.java new file mode 100644 index 0000000..db4594f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountSimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 公众号账号精简信息 Response VO") +@Data +public class MpAccountSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountUpdateReqVO.java new file mode 100644 index 0000000..e93123e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mp.controller.admin.account.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号账号更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAccountUpdateReqVO extends MpAccountBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.http new file mode 100644 index 0000000..74b8f40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.http @@ -0,0 +1,5 @@ +### 请求 /mp/material/page 接口 => 成功 +GET {{baseUrl}}/mp/material/page?permanent=true&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.java new file mode 100644 index 0000000..ef175d2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/MpMaterialController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.*; +import cn.iocoder.yudao.module.mp.convert.material.MpMaterialConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import cn.iocoder.yudao.module.mp.service.material.MpMaterialService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.io.IOException; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号素材") +@RestController +@RequestMapping("/mp/material") +@Validated +public class MpMaterialController { + + @Resource + private MpMaterialService mpMaterialService; + + @Operation(summary = "上传临时素材") + @PostMapping("/upload-temporary") + @PreAuthorize("@ss.hasPermission('mp:material:upload-temporary')") + public CommonResult uploadTemporaryMaterial( + @Valid MpMaterialUploadTemporaryReqVO reqVO) throws IOException { + MpMaterialDO material = mpMaterialService.uploadTemporaryMaterial(reqVO); + return success(MpMaterialConvert.INSTANCE.convert(material)); + } + + @Operation(summary = "上传永久素材") + @PostMapping("/upload-permanent") + @PreAuthorize("@ss.hasPermission('mp:material:upload-permanent')") + public CommonResult uploadPermanentMaterial( + @Valid MpMaterialUploadPermanentReqVO reqVO) throws IOException { + MpMaterialDO material = mpMaterialService.uploadPermanentMaterial(reqVO); + return success(MpMaterialConvert.INSTANCE.convert(material)); + } + + @Operation(summary = "删除素材") + @DeleteMapping("/delete-permanent") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:material:delete')") + public CommonResult deleteMaterial(@RequestParam("id") Long id) { + mpMaterialService.deleteMaterial(id); + return success(true); + } + + @Operation(summary = "上传图文内容中的图片") + @PostMapping("/upload-news-image") + @PreAuthorize("@ss.hasPermission('mp:material:upload-news-image')") + public CommonResult uploadNewsImage(@Valid MpMaterialUploadNewsImageReqVO reqVO) + throws IOException { + return success(mpMaterialService.uploadNewsImage(reqVO)); + } + + @Operation(summary = "获得素材分页") + @GetMapping("/page") + @PreAuthorize("@ss.hasPermission('mp:material:query')") + public CommonResult> getMaterialPage(@Valid MpMaterialPageReqVO pageReqVO) { + PageResult pageResult = mpMaterialService.getMaterialPage(pageReqVO); + return success(MpMaterialConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialPageReqVO.java new file mode 100644 index 0000000..8a2b60f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号素材的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpMaterialPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "是否永久", example = "true") + private Boolean permanent; + + @Schema(description = "文件类型 参见 WxConsts.MediaFileType 枚举", example = "image") + private String type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialRespVO.java new file mode 100644 index 0000000..5aba24e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialRespVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号素材 Response VO") +@Data +public class MpMaterialRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long accountId; + @Schema(description = "公众号账号的 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890") + private String appId; + + @Schema(description = "素材的 media_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "123") + private String mediaId; + + @Schema(description = "文件类型 参见 WxConsts.MediaFileType 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "image") + private String type; + + @Schema(description = "是否永久 true - 永久;false - 临时", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean permanent; + + @Schema(description = "素材的 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String url; + + + @Schema(description = "名字", example = "yunai.png") + private String name; + + @Schema(description = "公众号文件 URL 只有【永久素材】使用", example = "https://mmbiz.qpic.cn/xxx.mp3") + private String mpUrl; + + @Schema(description = "视频素材的标题 只有【永久素材】使用", example = "我是标题") + private String title; + @Schema(description = "视频素材的描述 只有【永久素材】使用", example = "我是介绍") + private String introduction; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadNewsImageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadNewsImageReqVO.java new file mode 100644 index 0000000..6ede4c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadNewsImageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号素材上传图文内容中的图片 Request VO") +@Data +public class MpMaterialUploadNewsImageReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件不能为空") + @JsonIgnore // 避免被操作日志,进行序列化,导致报错 + private MultipartFile file; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadPermanentReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadPermanentReqVO.java new file mode 100644 index 0000000..9ca8a4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadPermanentReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号素材上传永久 Request VO") +@Data +public class MpMaterialUploadPermanentReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "文件类型 参见 WxConsts.MediaFileType 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "image") + @NotEmpty(message = "文件类型不能为空") + private String type; + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件不能为空") + @JsonIgnore // 避免被操作日志,进行序列化,导致报错 + private MultipartFile file; + + @Schema(description = "名字 如果 name 为空,则使用 file 文件名", example = "wechat.mp") + private String name; + + @Schema(description = "视频素材的标题 文件类型为 video 时,必填", example = "视频素材的标题") + private String title; + @Schema(description = "视频素材的描述 文件类型为 video 时,必填", example = "视频素材的描述") + private String introduction; + + @AssertTrue(message = "标题不能为空") + public boolean isTitleValid() { + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的 + return ObjectUtil.notEqual(type, WxConsts.MediaFileType.VIDEO) + || title != null; + } + + @AssertTrue(message = "描述不能为空") + public boolean isIntroductionValid() { + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的 + return ObjectUtil.notEqual(type, WxConsts.MediaFileType.VIDEO) + || introduction != null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadRespVO.java new file mode 100644 index 0000000..0174cbc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 公众号素材上传结果 Response VO") +@Data +public class MpMaterialUploadRespVO { + + @Schema(description = "素材的 media_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "123") + private String mediaId; + + @Schema(description = "素材的 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") + private String url; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadTemporaryReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadTemporaryReqVO.java new file mode 100644 index 0000000..abd6d06 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/material/vo/MpMaterialUploadTemporaryReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.mp.controller.admin.material.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号素材上传临时 Request VO") +@Data +public class MpMaterialUploadTemporaryReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "文件类型 参见 WxConsts.MediaFileType 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "image") + @NotEmpty(message = "文件类型不能为空") + private String type; + + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "文件不能为空") + @JsonIgnore // 避免被操作日志,进行序列化,导致报错 + private MultipartFile file; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.http new file mode 100644 index 0000000..2276b3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.http @@ -0,0 +1,50 @@ +### 请求 /mp/menu/save 接口 => 成功 +POST {{baseUrl}}/mp/menu/save +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "accountId": "1", + "menus": [ + { + "type":"click", + "name":"今日歌曲", + "menuKey":"V1001_TODAY_MUSIC" + }, + { + "name":"搜索", + "type":"view", + "url":"https://www.soso.com/" + }, + { + "name": "父按钮", + "children": [ + { + "type":"click", + "name":"归去来兮", + "menuKey":"MUSIC" + }, + { + "name":"不说", + "type":"view", + "url":"https://www.soso.com/" + }] + }] +} + +### 请求 /mp/menu/save 接口 => 成功(清空) +POST {{baseUrl}}/mp/menu/save +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "accountId": "1", + "menus": [] +} + +### 请求 /mp/menu/list 接口 => 成功 +GET {{baseUrl}}/mp/menu/list?accountId=1 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.java new file mode 100644 index 0000000..b7c8835 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/MpMenuController.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.mp.controller.admin.menu; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; +import cn.iocoder.yudao.module.mp.convert.menu.MpMenuConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; +import cn.iocoder.yudao.module.mp.service.menu.MpMenuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号菜单") +@RestController +@RequestMapping("/mp/menu") +@Validated +public class MpMenuController { + + @Resource + private MpMenuService mpMenuService; + + @PostMapping("/save") + @Operation(summary = "保存公众号菜单") + @PreAuthorize("@ss.hasPermission('mp:menu:save')") + public CommonResult saveMenu(@Valid @RequestBody MpMenuSaveReqVO createReqVO) { + mpMenuService.saveMenu(createReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除公众号菜单") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "10") + @PreAuthorize("@ss.hasPermission('mp:menu:delete')") + public CommonResult deleteMenu(@RequestParam("accountId") Long accountId) { + mpMenuService.deleteMenuByAccountId(accountId); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获得公众号菜单列表") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "10") + @PreAuthorize("@ss.hasPermission('mp:menu:query')") + public CommonResult> getMenuList(@RequestParam("accountId") Long accountId) { + List list = mpMenuService.getMenuListByAccountId(accountId); + return success(MpMenuConvert.INSTANCE.convertList(list)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuBaseVO.java new file mode 100644 index 0000000..cd0e5b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuBaseVO.java @@ -0,0 +1,115 @@ +package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; + +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; +import org.hibernate.validator.constraints.URL; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +import static cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*; + +/** + * 公众号菜单 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MpMenuBaseVO { + + /** + * 菜单名称 + */ + private String name; + /** + * 菜单标识 + * + * 支持多 DB 类型时,无法直接使用 key + @TableField("menuKey") 来实现转换,原因是 "menuKey" AS key 而存在报错 + */ + private String menuKey; + /** + * 父菜单编号 + */ + private Long parentId; + + // ========== 按钮操作 ========== + + /** + * 按钮类型 + * + * 枚举 {@link WxConsts.MenuButtonType} + */ + private String type; + + @Schema(description = "网页链接", example = "https://www.iocoder.cn/") + @NotEmpty(message = "网页链接不能为空", groups = {ViewButtonGroup.class, MiniProgramButtonGroup.class}) + @URL(message = "网页链接必须是 URL 格式") + private String url; + + @Schema(description = "小程序的 appId", example = "wx1234567890") + @NotEmpty(message = "小程序的 appId 不能为空", groups = MiniProgramButtonGroup.class) + private String miniProgramAppId; + + @Schema(description = "小程序的页面路径", example = "pages/index/index") + @NotEmpty(message = "小程序的页面路径不能为空", groups = MiniProgramButtonGroup.class) + private String miniProgramPagePath; + + @Schema(description ="跳转图文的媒体编号", example = "jCQk93AIIgp8ixClWcW_NXXqBKInNWNmq2XnPeDZl7IMVqWiNeL4FfELtggRXd83") + @NotEmpty(message = "跳转图文的媒体编号不能为空", groups = ViewLimitedButtonGroup.class) + private String articleId; + + // ========== 消息内容 ========== + + @Schema(description = "回复的消息类型 枚举 TEXT、IMAGE、VOICE、VIDEO、NEWS、MUSIC", example = "text") + @NotEmpty(message = "回复的消息类型不能为空", groups = {ClickButtonGroup.class, ScanCodeWaitMsgButtonGroup.class}) + private String replyMessageType; + + @Schema(description = "回复的消息内容", example = "欢迎关注") + @NotEmpty(message = "回复的消息内容不能为空", groups = TextMessageGroup.class) + private String replyContent; + + @Schema(description = "回复的媒体 id", example = "123456") + @NotEmpty(message = "回复的消息 mediaId 不能为空", + groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String replyMediaId; + @Schema(description = "回复的媒体 URL", example = "https://www.iocoder.cn/xxx.jpg") + @NotEmpty(message = "回复的消息 mediaId 不能为空", + groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String replyMediaUrl; + + @Schema(description = "缩略图的媒体 id", example = "123456") + @NotEmpty(message = "回复的消息 thumbMediaId 不能为空", groups = {MusicMessageGroup.class}) + private String replyThumbMediaId; + @Schema(description = "缩略图的媒体 URL",example = "https://www.iocoder.cn/xxx.jpg") + @NotEmpty(message = "回复的消息 thumbMedia 地址不能为空", groups = {MusicMessageGroup.class}) + private String replyThumbMediaUrl; + + @Schema(description = "回复的标题", example = "视频标题") + @NotEmpty(message = "回复的消息标题不能为空", groups = VideoMessageGroup.class) + private String replyTitle; + @Schema(description = "回复的描述", example = "视频描述") + @NotEmpty(message = "消息描述不能为空", groups = VideoMessageGroup.class) + private String replyDescription; + + /** + * 回复的图文消息数组 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @NotNull(message = "回复的图文消息不能为空", groups = {NewsMessageGroup.class, ViewLimitedButtonGroup.class}) + @Valid + private List replyArticles; + + @Schema(description = "回复的音乐链接", example = "https://www.iocoder.cn/xxx.mp3") + @NotEmpty(message = "回复的音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String replyMusicUrl; + @Schema(description = "高质量音乐链接", example = "https://www.iocoder.cn/xxx.mp3") + @NotEmpty(message = "回复的高质量音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String replyHqMusicUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuRespVO.java new file mode 100644 index 0000000..5d54959 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号菜单 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpMenuRespVO extends MpMenuBaseVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long accountId; + + @Schema(description = "公众号 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890ox") + private String appId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuSaveReqVO.java new file mode 100644 index 0000000..580e628 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/menu/vo/MpMenuSaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.mp.controller.admin.menu.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 公众号菜单保存 Request VO") +@Data +public class MpMenuSaveReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @NotEmpty(message = "菜单不能为空") + @Valid + private List

menus; + + @Schema(description = "管理后台 - 公众号菜单保存时的每个菜单") + @Data + public static class Menu extends MpMenuBaseVO { + + /** + * 子菜单数组 + */ + private List children; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.http new file mode 100644 index 0000000..dbb3a7b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.http @@ -0,0 +1,5 @@ +### 请求 /mp/message/page 接口 => 成功 +GET {{baseUrl}}/mp/auto-reply/page?accountId=1&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java new file mode 100644 index 0000000..f6a8b9b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.convert.message.MpAutoReplyConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号自动回复") +@RestController +@RequestMapping("/mp/auto-reply") +@Validated +public class MpAutoReplyController { + + @Resource + private MpAutoReplyService mpAutoReplyService; + + @GetMapping("/page") + @Operation(summary = "获得公众号自动回复分页") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:query')") + public CommonResult> getAutoReplyPage(@Valid MpMessagePageReqVO pageVO) { + PageResult pageResult = mpAutoReplyService.getAutoReplyPage(pageVO); + return success(MpAutoReplyConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/get") + @Operation(summary = "获得公众号自动回复") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:query')") + public CommonResult getAutoReply(@RequestParam("id") Long id) { + MpAutoReplyDO autoReply = mpAutoReplyService.getAutoReply(id); + return success(MpAutoReplyConvert.INSTANCE.convert(autoReply)); + } + + @PostMapping("/create") + @Operation(summary = "创建公众号自动回复") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:create')") + public CommonResult createAutoReply(@Valid @RequestBody MpAutoReplyCreateReqVO createReqVO) { + return success(mpAutoReplyService.createAutoReply(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新公众号自动回复") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:update')") + public CommonResult updateAutoReply(@Valid @RequestBody MpAutoReplyUpdateReqVO updateReqVO) { + mpAutoReplyService.updateAutoReply(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除公众号自动回复") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:auto-reply:delete')") + public CommonResult deleteAutoReply(@RequestParam("id") Long id) { + mpAutoReplyService.deleteAutoReply(id); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.http new file mode 100644 index 0000000..b9f9721 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.http @@ -0,0 +1,33 @@ +### 请求 /mp/message/page 接口 => 成功 +GET {{baseUrl}}/mp/message/page?accountId=1&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/message/send 接口 => 成功(文本) +POST {{baseUrl}}/mp/message/send +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "userId": 3, + "type": "text", + "content": "测试消息" +} + +### 请求 /mp/message/send 接口 => 成功(音乐) +POST {{baseUrl}}/mp/message/send +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "userId": 3, + "type": "music", + "title": "测试音乐标题", + "description": "测试音乐内容", + "musicUrl": "https://www.iocoder.cn/xx.mp3", + "hqMusicUrl": "https://www.iocoder.cn/xx_high.mp3", + "thumbMediaId": "s98Iveeg9vDVFwa9q0u8-zSfdKe3xIzAm7wCrFE4WKGPIo4d9qAhtC-n6qvnyWyH" +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.java new file mode 100644 index 0000000..66befc6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageController.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO; +import cn.iocoder.yudao.module.mp.convert.message.MpMessageConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.service.message.MpMessageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号消息") +@RestController +@RequestMapping("/mp/message") +@Validated +public class MpMessageController { + + @Resource + private MpMessageService mpMessageService; + + @GetMapping("/page") + @Operation(summary = "获得公众号消息分页") + @PreAuthorize("@ss.hasPermission('mp:message:query')") + public CommonResult> getMessagePage(@Valid MpMessagePageReqVO pageVO) { + PageResult pageResult = mpMessageService.getMessagePage(pageVO); + return success(MpMessageConvert.INSTANCE.convertPage(pageResult)); + } + + @PostMapping("/send") + @Operation(summary = "给粉丝发送消息") + @PreAuthorize("@ss.hasPermission('mp:message:send')") + public CommonResult sendMessage(@Valid @RequestBody MpMessageSendReqVO reqVO) { + MpMessageDO message = mpMessageService.sendKefuMessage(reqVO); + return success(MpMessageConvert.INSTANCE.convert(message)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyBaseVO.java new file mode 100644 index 0000000..4b84254 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyBaseVO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; +import org.hibernate.validator.constraints.URL; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 公众号自动回复 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class MpAutoReplyBaseVO { + + @Schema(description = "回复类型 参见 MpAutoReplyTypeEnum 枚举", example = "1") + @NotNull(message = "回复类型不能为空") + private Integer type; + + // ==================== 请求消息 ==================== + + @Schema(description = "请求的关键字 当 type 为 MpAutoReplyTypeEnum#KEYWORD 时,必填", example = "关键字") + private String requestKeyword; + @Schema(description = "请求的匹配方式 当 type 为 MpAutoReplyTypeEnum#KEYWORD 时,必填", example = "1") + private Integer requestMatch; + + @Schema(description = "请求的消息类型 当 type 为 MpAutoReplyTypeEnum#MESSAGE 时,必填", example = "text") + private String requestMessageType; + + // ==================== 响应消息 ==================== + + @Schema(description = "回复的消息类型 枚举 TEXT、IMAGE、VOICE、VIDEO、NEWS、MUSIC", example = "text") + @NotEmpty(message = "回复的消息类型不能为空") + private String responseMessageType; + + @Schema(description = "回复的消息内容", example = "欢迎关注") + @NotEmpty(message = "回复的消息内容不能为空", groups = TextMessageGroup.class) + private String responseContent; + + @Schema(description = "回复的媒体 id", example = "123456") + @NotEmpty(message = "回复的消息 mediaId 不能为空", + groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String responseMediaId; + @Schema(description = "回复的媒体 URL", example = "https://www.iocoder.cn/xxx.jpg") + @NotEmpty(message = "回复的消息 mediaId 不能为空", + groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String responseMediaUrl; + + @Schema(description = "缩略图的媒体 id", example = "123456") + @NotEmpty(message = "回复的消息 thumbMediaId 不能为空", groups = {MusicMessageGroup.class}) + private String responseThumbMediaId; + @Schema(description = "缩略图的媒体 URL",example = "https://www.iocoder.cn/xxx.jpg") + @NotEmpty(message = "回复的消息 thumbMedia 地址不能为空", groups = {MusicMessageGroup.class}) + private String responseThumbMediaUrl; + + @Schema(description = "回复的标题", example = "视频标题") + @NotEmpty(message = "回复的消息标题不能为空", groups = VideoMessageGroup.class) + private String responseTitle; + @Schema(description = "回复的描述", example = "视频描述") + @NotEmpty(message = "消息描述不能为空", groups = VideoMessageGroup.class) + private String responseDescription; + + /** + * 回复的图文消息 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @NotNull(message = "回复的图文消息不能为空", groups = {NewsMessageGroup.class, ViewLimitedButtonGroup.class}) + @Valid + private List responseArticles; + + @Schema(description = "回复的音乐链接", example = "https://www.iocoder.cn/xxx.mp3") + @NotEmpty(message = "回复的音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String responseMusicUrl; + @Schema(description = "高质量音乐链接", example = "https://www.iocoder.cn/xxx.mp3") + @NotEmpty(message = "回复的高质量音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "回复的高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String responseHqMusicUrl; + + @AssertTrue(message = "请求的关键字不能为空") + public boolean isRequestKeywordValid() { + return ObjectUtil.notEqual(type, MpAutoReplyTypeEnum.KEYWORD) + || requestKeyword != null; + } + + @AssertTrue(message = "请求的关键字的匹配不能为空") + public boolean isRequestMatchValid() { + return ObjectUtil.notEqual(type, MpAutoReplyTypeEnum.KEYWORD) + || requestMatch != null; + } + + @AssertTrue(message = "请求的消息类型不能为空") + public boolean isRequestMessageTypeValid() { + return ObjectUtil.notEqual(type, MpAutoReplyTypeEnum.MESSAGE) + || requestMessageType != null; + } + + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java new file mode 100644 index 0000000..5eafb36 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号自动回复的创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAutoReplyCreateReqVO extends MpAutoReplyBaseVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyPageReqVO.java new file mode 100644 index 0000000..a68029e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号自动回复的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAutoReplyPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyRespVO.java new file mode 100644 index 0000000..d1f72f3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号自动回复 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAutoReplyRespVO extends MpAutoReplyBaseVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long accountId; + @Schema(description = "公众号 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890") + private String appId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyUpdateReqVO.java new file mode 100644 index 0000000..92095d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号自动回复的更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAutoReplyUpdateReqVO extends MpAutoReplyBaseVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "主键不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessagePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessagePageReqVO.java new file mode 100644 index 0000000..3ca643c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessagePageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 公众号消息分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpMessagePageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "消息类型 参见 WxConsts.XmlMsgType 枚举", example = "text") + private String type; + + @Schema(description = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String openid; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageRespVO.java new file mode 100644 index 0000000..27c85be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageRespVO.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message; + +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + +@Schema(description = "管理后台 - 公众号消息 Response VO") +@Data +public class MpMessageRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer id; + + @Schema(description = "微信公众号消息 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23953173569869169") + private Long msgId; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long accountId; + @Schema(description = "公众号账号的 appid", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890") + private String appId; + + @Schema(description = "公众号粉丝编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long userId; + @Schema(description = "公众号粉丝标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String openid; + + @Schema(description = "消息类型 参见 WxConsts.XmlMsgType 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "text") + private String type; + @Schema(description = "消息来源 参见 MpMessageSendFromEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sendFrom; + + // ========= 普通消息内容 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html + + @Schema(description = "消息内容 消息类型为 text 时,才有值", example = "你好呀") + private String content; + + @Schema(description = "媒体素材的编号 消息类型为 image、voice、video 时,才有值", example = "1234567890") + private String mediaId; + @Schema(description = "媒体文件的 URL 消息类型为 image、voice、video 时,才有值", example = "https://www.iocoder.cn/xxx.png") + private String mediaUrl; + + @Schema(description = "语音识别后文本 消息类型为 voice 时,才有值", example = "语音识别后文本") + private String recognition; + @Schema(description = "语音格式 消息类型为 voice 时,才有值", example = "amr") + private String format; + + @Schema(description = "标题 消息类型为 video、music、link 时,才有值", example = "我是标题") + private String title; + + @Schema(description = "描述 消息类型为 video、music 时,才有值", example = "我是描述") + private String description; + + @Schema(description = "缩略图的媒体 id 消息类型为 video、music 时,才有值", example = "1234567890") + private String thumbMediaId; + @Schema(description = "缩略图的媒体 URL 消息类型为 video、music 时,才有值", example = "https://www.iocoder.cn/xxx.png") + private String thumbMediaUrl; + + @Schema(description = "点击图文消息跳转链接 消息类型为 link 时,才有值", example = "https://www.iocoder.cn") + private String url; + + @Schema(description = "地理位置维度 消息类型为 location 时,才有值", example = "23.137466") + private Double locationX; + + @Schema(description = "地理位置经度 消息类型为 location 时,才有值", example = "113.352425") + private Double locationY; + + @Schema(description = "地图缩放大小 消息类型为 location 时,才有值", example = "13") + private Double scale; + + @Schema(description = "详细地址 消息类型为 location 时,才有值", example = "杨浦区黄兴路 221-4 号临") + private String label; + + /** + * 图文消息数组 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class) + private List articles; + + @Schema(description = "音乐链接 消息类型为 music 时,才有值", example = "https://www.iocoder.cn/xxx.mp3") + private String musicUrl; + @Schema(description = "高质量音乐链接 消息类型为 music 时,才有值", example = "https://www.iocoder.cn/xxx.mp3") + private String hqMusicUrl; + + // ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html + + @Schema(description = "事件类型 参见 WxConsts.EventType 枚举", example = "subscribe") + private String event; + @Schema(description = "事件 Key 参见 WxConsts.EventType 枚举", example = "qrscene_123456") + private String eventKey; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageSendReqVO.java new file mode 100644 index 0000000..8e833d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessageSendReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.message; + +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 公众号消息发送 Request VO") +@Data +public class MpMessageSendReqVO { + + @Schema(description = "公众号粉丝的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号粉丝的编号不能为空") + private Long userId; + + // ========== 消息内容 ========== + + @Schema(description = "消息类型 TEXT/IMAGE/VOICE/VIDEO/NEWS", requiredMode = Schema.RequiredMode.REQUIRED, example = "text") + @NotEmpty(message = "消息类型不能为空") + public String type; + + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好呀") + @NotEmpty(message = "消息内容不能为空", groups = TextMessageGroup.class) + private String content; + + @Schema(description = "媒体 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "qqc_2Fot30Jse-HDoZmo5RrUDijz2nGUkP") + @NotEmpty(message = "消息内容不能为空", groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String mediaId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "没有标题") + @NotEmpty(message = "消息内容不能为空", groups = VideoMessageGroup.class) + private String title; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + @NotEmpty(message = "消息描述不能为空", groups = VideoMessageGroup.class) + private String description; + + @Schema(description = "缩略图的媒体 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "qqc_2Fot30Jse-HDoZmo5RrUDijz2nGUkP") + @NotEmpty(message = "缩略图的媒体 id 不能为空", groups = MusicMessageGroup.class) + private String thumbMediaId; + + @Schema(description = "图文消息", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid + @NotNull(message = "图文消息不能为空", groups = NewsMessageGroup.class) + private List articles; + + @Schema(description = "音乐链接 消息类型为 MUSIC 时", example = "https://www.iocoder.cn/music.mp3") + private String musicUrl; + + @Schema(description = "高质量音乐链接 消息类型为 MUSIC 时", example = "https://www.iocoder.cn/music.mp3") + private String hqMusicUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.http new file mode 100644 index 0000000..87f9d43 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.http @@ -0,0 +1,54 @@ +### 请求 /mp/draft/page 接口 => 成功 +GET {{baseUrl}}/mp/draft/page?accountId=1&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/draft/create 接口 => 成功 +POST {{baseUrl}}/mp/draft/create?accountId=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "articles": [ + { + "title": "我是标题", + "author": "我是作者", + "digest": "我是摘要", + "content": "我是内容", + "contentSourceUrl": "https://www.iocoder.cn", + "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn" + }, + { + "title": "我是标题 2", + "author": "我是作者 2", + "digest": "我是摘要 2", + "content": "我是内容 2", + "contentSourceUrl": "https://www.iocoder.cn", + "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn" + } + ] +} + +### 请求 /mp/draft/create 接口 => 成功 +PUT {{baseUrl}}/mp/draft/update?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-q-G9pdsmZw0OYG4FzHQkKfpLfEwIH51wy2bxisx8PvW +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +[{ + "title": "我是标题(OOO)", + "author": "我是作者", + "digest": "我是摘要", + "content": "我是内容", + "contentSourceUrl": "https://www.iocoder.cn", + "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn" +}, { + "title": "我是标题(XXX)", + "author": "我是作者", + "digest": "我是摘要", + "content": "我是内容", + "contentSourceUrl": "https://www.iocoder.cn", + "thumbMediaId": "r6ryvl6LrxBU0miaST4Y-pIcmK-zAAId-9TGgy-DrSLhjVuWbuT3ZBjk9K1yQ0Dn" +}] diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.java new file mode 100644 index 0000000..c43d6c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpDraftController.java @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.mp.controller.admin.news; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.module.mp.controller.admin.news.vo.MpDraftPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.material.MpMaterialService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.draft.*; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +@Tag(name = "管理后台 - 公众号草稿") +@RestController +@RequestMapping("/mp/draft") +@Validated +public class MpDraftController { + + @Resource + private MpServiceFactory mpServiceFactory; + + @Resource + private MpMaterialService mpMaterialService; + + @GetMapping("/page") + @Operation(summary = "获得草稿分页") + @PreAuthorize("@ss.hasPermission('mp:draft:query')") + public CommonResult> getDraftPage(MpDraftPageReqVO reqVO) { + // 从公众号查询草稿箱 + WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId()); + WxMpDraftList draftList; + try { + draftList = mpService.getDraftService().listDraft(PageUtils.getStart(reqVO), reqVO.getPageSize()); + } catch (WxErrorException e) { + throw exception(DRAFT_LIST_FAIL, e.getError().getErrorMsg()); + } + // 查询对应的图片地址。目的:解决公众号的图片链接无法在我们后台展示 + setDraftThumbUrl(draftList.getItems()); + + // 返回分页 + return success(new PageResult<>(draftList.getItems(), draftList.getTotalCount().longValue())); + } + + private void setDraftThumbUrl(List items) { + // 1.1 获得 mediaId 数组 + Set mediaIds = new HashSet<>(); + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem -> mediaIds.add(newsItem.getThumbMediaId()))); + if (CollUtil.isEmpty(mediaIds)) { + return; + } + // 1.2 批量查询对应的 Media 素材 + Map materials = CollectionUtils.convertMap(mpMaterialService.getMaterialListByMediaId(mediaIds), + MpMaterialDO::getMediaId); + + // 2. 设置回 WxMpDraftItem 记录 + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem -> + findAndThen(materials, newsItem.getThumbMediaId(), material -> newsItem.setThumbUrl(material.getUrl())))); + } + + @PostMapping("/create") + @Operation(summary = "创建草稿") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:draft:create')") + public CommonResult deleteDraft(@RequestParam("accountId") Long accountId, + @RequestBody WxMpAddDraft draft) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + String mediaId = mpService.getDraftService().addDraft(draft); + return success(mediaId); + } catch (WxErrorException e) { + throw exception(DRAFT_CREATE_FAIL, e.getError().getErrorMsg()); + } + } + + @PutMapping("/update") + @Operation(summary = "更新草稿") + @Parameters({ + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "1024"), + @Parameter(name = "mediaId", description = "草稿素材的编号", required = true, example = "xxx") + }) + @PreAuthorize("@ss.hasPermission('mp:draft:update')") + public CommonResult deleteDraft(@RequestParam("accountId") Long accountId, + @RequestParam("mediaId") String mediaId, + @RequestBody List articles) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + for (int i = 0; i < articles.size(); i++) { + WxMpDraftArticles article = articles.get(i); + mpService.getDraftService().updateDraft(new WxMpUpdateDraft(mediaId, i, article)); + } + return success(true); + } catch (WxErrorException e) { + throw exception(DRAFT_UPDATE_FAIL, e.getError().getErrorMsg()); + } + } + + @DeleteMapping("/delete") + @Operation(summary = "删除草稿") + @Parameters({ + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "1024"), + @Parameter(name = "mediaId", description = "草稿素材的编号", required = true, example = "xxx") + }) + @PreAuthorize("@ss.hasPermission('mp:draft:delete')") + public CommonResult deleteDraft(@RequestParam("accountId") Long accountId, + @RequestParam("mediaId") String mediaId) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + mpService.getDraftService().delDraft(mediaId); + return success(true); + } catch (WxErrorException e) { + throw exception(DRAFT_DELETE_FAIL, e.getError().getErrorMsg()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.http new file mode 100644 index 0000000..1224132 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.http @@ -0,0 +1,13 @@ +### 请求 /mp/free-publish/page 接口 => 成功 +GET {{baseUrl}}/mp/free-publish/page?accountId=1&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/free-publish/submit 接口 => 成功 +POST {{baseUrl}}/mp/free-publish/submit?accountId=1&mediaId=r6ryvl6LrxBU0miaST4Y-vilmd7iS51D8IPddxflWrau0hIQ2ovY8YanO5jlgUcM +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.java new file mode 100644 index 0000000..e36d734 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/MpFreePublishController.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.mp.controller.admin.news; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.module.mp.controller.admin.news.vo.MpFreePublishPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.material.MpMaterialService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishItem; +import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishList; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +@Tag(name = "管理后台 - 公众号发布能力") +@RestController +@RequestMapping("/mp/free-publish") +@Validated +public class MpFreePublishController { + + @Resource + private MpServiceFactory mpServiceFactory; + + @Resource + private MpMaterialService mpMaterialService; + + @GetMapping("/page") + @Operation(summary = "获得已发布的图文分页") + @PreAuthorize("@ss.hasPermission('mp:free-publish:query')") + public CommonResult> getFreePublishPage(MpFreePublishPageReqVO reqVO) { + // 从公众号查询已发布的图文列表 + WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId()); + WxMpFreePublishList publicationRecords; + try { + publicationRecords = mpService.getFreePublishService().getPublicationRecords( + PageUtils.getStart(reqVO), reqVO.getPageSize()); + } catch (WxErrorException e) { + throw exception(FREE_PUBLISH_LIST_FAIL, e.getError().getErrorMsg()); + } + // 查询对应的图片地址。目的:解决公众号的图片链接无法在我们后台展示 + setFreePublishThumbUrl(publicationRecords.getItems()); + + // 返回分页 + return success(new PageResult<>(publicationRecords.getItems(), publicationRecords.getTotalCount().longValue())); + } + + private void setFreePublishThumbUrl(List items) { + // 1.1 获得 mediaId 数组 + Set mediaIds = new HashSet<>(); + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem -> mediaIds.add(newsItem.getThumbMediaId()))); + if (CollUtil.isEmpty(mediaIds)) { + return; + } + // 1.2 批量查询对应的 Media 素材 + Map materials = CollectionUtils.convertMap(mpMaterialService.getMaterialListByMediaId(mediaIds), + MpMaterialDO::getMediaId); + + // 2. 设置回 WxMpFreePublishItem 记录 + items.forEach(item -> item.getContent().getNewsItem().forEach(newsItem -> + findAndThen(materials, newsItem.getThumbMediaId(), material -> newsItem.setThumbUrl(material.getUrl())))); + } + + @PostMapping("/submit") + @Operation(summary = "发布草稿") + @Parameters({ + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "1024"), + @Parameter(name = "mediaId", description = "要发布的草稿的 media_id", required = true, example = "2048") + }) + @PreAuthorize("@ss.hasPermission('mp:free-publish:submit')") + public CommonResult submitFreePublish(@RequestParam("accountId") Long accountId, + @RequestParam("mediaId") String mediaId) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + String publishId = mpService.getFreePublishService().submit(mediaId); + return success(publishId); + } catch (WxErrorException e) { + throw exception(FREE_PUBLISH_SUBMIT_FAIL, e.getError().getErrorMsg()); + } + } + + @DeleteMapping("/delete") + @Operation(summary = "删除草稿") + @Parameters({ + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "1024"), + @Parameter(name = "articleId", description = "发布记录的编号", required = true, example = "2048") + }) + @PreAuthorize("@ss.hasPermission('mp:free-publish:delete')") + public CommonResult deleteFreePublish(@RequestParam("accountId") Long accountId, + @RequestParam("articleId") String articleId) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + mpService.getFreePublishService().deletePushAllArticle(articleId); + return success(true); + } catch (WxErrorException e) { + throw exception(FREE_PUBLISH_DELETE_FAIL, e.getError().getErrorMsg()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpDraftPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpDraftPageReqVO.java new file mode 100644 index 0000000..62bc6f8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpDraftPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mp.controller.admin.news.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号草稿的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpDraftPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpFreePublishPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpFreePublishPageReqVO.java new file mode 100644 index 0000000..da36248 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/news/vo/MpFreePublishPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mp.controller.admin.news.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号已发布列表的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpFreePublishPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java new file mode 100644 index 0000000..47e2392 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.mp.controller.admin.open; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenCheckSignatureReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenHandleMessageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Objects; + +@Tag(name = "管理后台 - 公众号回调") +@RestController +@RequestMapping("/mp/open") +@Validated +@Slf4j +public class MpOpenController { + + @Resource + private MpServiceFactory mpServiceFactory; + + @Resource + private MpAccountService mpAccountService; + + /** + * 接收微信公众号的校验签名 + * + * 对应 文档 + */ + @Operation(summary = "校验签名") // 参见 + @GetMapping(value = "/{appId}", produces = "text/plain;charset=utf-8") + public String checkSignature(@PathVariable("appId") String appId, + MpOpenCheckSignatureReqVO reqVO) { + log.info("[checkSignature][appId({}) 接收到来自微信服务器的认证消息({})]", appId, reqVO); + // 校验请求签名 + WxMpService wxMpService = mpServiceFactory.getRequiredMpService(appId); + // 校验通过 + if (wxMpService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature())) { + return reqVO.getEchostr(); + } + // 校验不通过 + return "非法请求"; + } + + /** + * 接收微信公众号的消息推送 + * + * 文档 + */ + @Operation(summary = "处理消息") + @PostMapping(value = "/{appId}", produces = "application/xml; charset=UTF-8") + public String handleMessage(@PathVariable("appId") String appId, + @RequestBody String content, + MpOpenHandleMessageReqVO reqVO) { + log.info("[handleMessage][appId({}) 推送消息,参数({}) 内容({})]", appId, reqVO, content); + + // 处理 appId + 多租户的上下文 + MpAccountDO account = mpAccountService.getAccountFromCache(appId); + Assert.notNull(account, "公众号 appId({}) 不存在", appId); + try { + MpContextHolder.setAppId(appId); + return TenantUtils.execute(account.getTenantId(), + () -> handleMessage0(appId, content, reqVO)); + } finally { + MpContextHolder.clear(); + } + } + + private String handleMessage0(String appId, String content, MpOpenHandleMessageReqVO reqVO) { + // 校验请求签名 + WxMpService mppService = mpServiceFactory.getRequiredMpService(appId); + Assert.isTrue(mppService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature()), + "非法请求"); + + // 第一步,解析消息 + WxMpXmlMessage inMessage = null; + if (StrUtil.isBlank(reqVO.getEncrypt_type())) { // 明文模式 + inMessage = WxMpXmlMessage.fromXml(content); + } else if (Objects.equals(reqVO.getEncrypt_type(), MpOpenHandleMessageReqVO.ENCRYPT_TYPE_AES)) { // AES 加密模式 + inMessage = WxMpXmlMessage.fromEncryptedXml(content, mppService.getWxMpConfigStorage(), + reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getMsg_signature()); + } + Assert.notNull(inMessage, "消息解析失败,原因:消息为空"); + + // 第二步,处理消息 + WxMpMessageRouter mpMessageRouter = mpServiceFactory.getRequiredMpMessageRouter(appId); + WxMpXmlOutMessage outMessage = mpMessageRouter.route(inMessage); + if (outMessage == null) { + return ""; + } + + // 第三步,返回消息 + if (StrUtil.isBlank(reqVO.getEncrypt_type())) { // 明文模式 + return outMessage.toXml(); + } else if (Objects.equals(reqVO.getEncrypt_type(), MpOpenHandleMessageReqVO.ENCRYPT_TYPE_AES)) { // AES 加密模式 + return outMessage.toEncryptedXml(mppService.getWxMpConfigStorage()); + } + return ""; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenCheckSignatureReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenCheckSignatureReqVO.java new file mode 100644 index 0000000..c0c73a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenCheckSignatureReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.mp.controller.admin.open.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 公众号校验签名 Request VO") +@Data +public class MpOpenCheckSignatureReqVO { + + @Schema(description = "微信加密签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "490eb57f448b87bd5f20ccef58aa4de46aa1908e") + @NotEmpty(message = "微信加密签名不能为空") + private String signature; + + @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "1672587863") + @NotEmpty(message = "时间戳不能为空") + private String timestamp; + + @Schema(description = "随机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1827365808") + @NotEmpty(message = "随机数不能为空") + private String nonce; + + @Schema(description = "随机字符串", requiredMode = Schema.RequiredMode.REQUIRED, example = "2721154047828672511") + @NotEmpty(message = "随机字符串不能为空") + @SuppressWarnings("SpellCheckingInspection") + private String echostr; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenHandleMessageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenHandleMessageReqVO.java new file mode 100644 index 0000000..cb8f9ab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenHandleMessageReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mp.controller.admin.open.vo; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 公众号处理消息 Request VO") +@Data +public class MpOpenHandleMessageReqVO { + + public static final String ENCRYPT_TYPE_AES = "aes"; + + @Schema(description = "微信加密签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "490eb57f448b87bd5f20ccef58aa4de46aa1908e") + @NotEmpty(message = "微信加密签名不能为空") + private String signature; + + @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "1672587863") + @NotEmpty(message = "时间戳不能为空") + private String timestamp; + + @Schema(description = "随机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1827365808") + @NotEmpty(message = "随机数不能为空") + private String nonce; + + @Schema(description = "粉丝 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "oz-Jdtyn-WGm4C4I5Z-nvBMO_ZfY") + @NotEmpty(message = "粉丝 openid 不能为空") + private String openid; + + @Schema(description = "消息加密类型", example = "aes") + private String encrypt_type; + + @Schema(description = "微信签名", example = "QW5kcm9pZCBUaGUgQmFzZTY0IGlzIGEgZ2VuZXJhdGVkIHN0cmluZw==") + private String msg_signature; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/MpStatisticsController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/MpStatisticsController.java new file mode 100644 index 0000000..8a9df53 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/MpStatisticsController.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.*; +import cn.iocoder.yudao.module.mp.convert.statistics.MpStatisticsConvert; +import cn.iocoder.yudao.module.mp.service.statistics.MpStatisticsService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号统计") +@RestController +@RequestMapping("/mp/statistics") +@Validated +public class MpStatisticsController { + + @Resource + private MpStatisticsService mpStatisticsService; + + @GetMapping("/user-summary") + @Operation(summary = "获得粉丝增减数据") + @PreAuthorize("@ss.hasPermission('mp:statistics:query')") + public CommonResult> getUserSummary(MpStatisticsGetReqVO getReqVO) { + List list = mpStatisticsService.getUserSummary( + getReqVO.getAccountId(), getReqVO.getDate()); + return success(MpStatisticsConvert.INSTANCE.convertList01(list)); + } + + @GetMapping("/user-cumulate") + @Operation(summary = "获得粉丝累计数据") + @PreAuthorize("@ss.hasPermission('mp:statistics:query')") + public CommonResult> getUserCumulate(MpStatisticsGetReqVO getReqVO) { + List list = mpStatisticsService.getUserCumulate( + getReqVO.getAccountId(), getReqVO.getDate()); + return success(MpStatisticsConvert.INSTANCE.convertList02(list)); + } + + @GetMapping("/upstream-message") + @Operation(summary = "获取消息发送概况数据") + @PreAuthorize("@ss.hasPermission('mp:statistics:query')") + public CommonResult> getUpstreamMessage(MpStatisticsGetReqVO getReqVO) { + List list = mpStatisticsService.getUpstreamMessage( + getReqVO.getAccountId(), getReqVO.getDate()); + return success(MpStatisticsConvert.INSTANCE.convertList03(list)); + } + + @GetMapping("/interface-summary") + @Operation(summary = "获取消息发送概况数据") + @PreAuthorize("@ss.hasPermission('mp:statistics:query')") + public CommonResult> getInterfaceSummary(MpStatisticsGetReqVO getReqVO) { + List list = mpStatisticsService.getInterfaceSummary( + getReqVO.getAccountId(), getReqVO.getDate()); + return success(MpStatisticsConvert.INSTANCE.convertList04(list)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsGetReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsGetReqVO.java new file mode 100644 index 0000000..f228f72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsGetReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 获得统计数据 Request VO") +@Data +public class MpStatisticsGetReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "查询时间范围", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotNull(message = "查询时间范围不能为空") + private LocalDateTime[] date; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsInterfaceSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsInterfaceSummaryRespVO.java new file mode 100644 index 0000000..c7952f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsInterfaceSummaryRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 某一天的接口分析数据 Response VO") +@Data +public class MpStatisticsInterfaceSummaryRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime refDate; + + @Schema(description = "通过服务器配置地址获得消息后,被动回复粉丝消息的次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer callbackCount; + + @Schema(description = "上述动作的失败次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer failCount; + + @Schema(description = "总耗时,除以 callback_count 即为平均耗时", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer totalTimeCost; + + @Schema(description = "最大耗时", requiredMode = Schema.RequiredMode.REQUIRED, example = "40") + private Integer maxTimeCost; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUpstreamMessageRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUpstreamMessageRespVO.java new file mode 100644 index 0000000..f9bba2c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUpstreamMessageRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 某一天的粉丝增减数据 Response VO") +@Data +public class MpStatisticsUpstreamMessageRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime refDate; + + @Schema(description = "上行发送了(向公众号发送了)消息的粉丝数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer messageUser; + + @Schema(description = "上行发送了消息的消息总数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer messageCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserCumulateRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserCumulateRespVO.java new file mode 100644 index 0000000..6503c07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserCumulateRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 某一天的消息发送概况数据 Response VO") +@Data +public class MpStatisticsUserCumulateRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime refDate; + + @Schema(description = "累计粉丝量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer cumulateUser; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserSummaryRespVO.java new file mode 100644 index 0000000..7a5373c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserSummaryRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 某一天的粉丝增减数据 Response VO") +@Data +public class MpStatisticsUserSummaryRespVO { + + @Schema(description = "日期", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime refDate; + + @Schema(description = "粉丝来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer userSource; + + @Schema(description = "新关注的粉丝数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer newUser; + + @Schema(description = "取消关注的粉丝数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer cancelUser; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.http new file mode 100644 index 0000000..fe79105 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.http @@ -0,0 +1,39 @@ +### 请求 /mp/tag/create 接口 => 成功 +POST {{baseUrl}}/mp/tag/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "accountId": "1", + "name": "测试" +} + +### 请求 /mp/tag/update 接口 => 成功 +PUT {{baseUrl}}/mp/tag/update +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "id": "3", + "name": "测试标签啦" +} + +### 请求 /mp/tag/delete 接口 => 成功 +DELETE {{baseUrl}}/mp/tag/delete?id=3 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/tag/page 接口 => 成功 +GET {{baseUrl}}/mp/tag/page?accountId=1&pageNo=1&pageSize=10 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/tag/sync 接口 => 成功 +POST {{baseUrl}}/mp/tag/sync?accountId=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.java new file mode 100644 index 0000000..96af036 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/MpTagController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.*; +import cn.iocoder.yudao.module.mp.convert.tag.MpTagConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; +import cn.iocoder.yudao.module.mp.service.tag.MpTagService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号标签") +@RestController +@RequestMapping("/mp/tag") +@Validated +public class MpTagController { + + @Resource + private MpTagService mpTagService; + + @PostMapping("/create") + @Operation(summary = "创建公众号标签") + @PreAuthorize("@ss.hasPermission('mp:tag:create')") + public CommonResult createTag(@Valid @RequestBody MpTagCreateReqVO createReqVO) { + return success(mpTagService.createTag(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新公众号标签") + @PreAuthorize("@ss.hasPermission('mp:tag:update')") + public CommonResult updateTag(@Valid @RequestBody MpTagUpdateReqVO updateReqVO) { + mpTagService.updateTag(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除公众号标签") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:tag:delete')") + public CommonResult deleteTag(@RequestParam("id") Long id) { + mpTagService.deleteTag(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获取公众号标签详情") + @PreAuthorize("@ss.hasPermission('mp:tag:query')") + public CommonResult get(@RequestParam("id") Long id) { + MpTagDO mpTagDO = mpTagService.get(id); + return success(MpTagConvert.INSTANCE.convert(mpTagDO)); + } + + @GetMapping("/page") + @Operation(summary = "获取公众号标签分页") + @PreAuthorize("@ss.hasPermission('mp:tag:query')") + public CommonResult> getTagPage(MpTagPageReqVO pageReqVO) { + PageResult pageResult = mpTagService.getTagPage(pageReqVO); + return success(MpTagConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/list-all-simple") + @Operation(summary = "获取公众号账号精简信息列表") + @PreAuthorize("@ss.hasPermission('mp:account:query')") + public CommonResult> getSimpleTags() { + List list = mpTagService.getTagList(); + return success(MpTagConvert.INSTANCE.convertList02(list)); + } + + @PostMapping("/sync") + @Operation(summary = "同步公众号标签") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:tag:sync')") + public CommonResult syncTag(@RequestParam("accountId") Long accountId) { + mpTagService.syncTag(accountId); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagBaseVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagBaseVO.java new file mode 100644 index 0000000..dc034e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagBaseVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +/** + * 公众号标签 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author fengdan + */ +@Data +public class MpTagBaseVO { + + @Schema(description = "标签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotEmpty(message = "标签名不能为空") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagCreateReqVO.java new file mode 100644 index 0000000..ba56a02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagCreateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号标签创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpTagCreateReqVO extends MpTagBaseVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagPageReqVO.java new file mode 100644 index 0000000..0666b34 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 公众号标签分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpTagPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotEmpty(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "标签名,模糊匹配", example = "哈哈") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagRespVO.java new file mode 100644 index 0000000..0da562d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号标签 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpTagRespVO extends MpTagBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "此标签下粉丝数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer count; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagSimpleRespVO.java new file mode 100644 index 0000000..ca23be1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 公众号标签精简信息 Response VO") +@Data +public class MpTagSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号的标签编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long tagId; + + @Schema(description = "标签名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "快乐") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagUpdateReqVO.java new file mode 100644 index 0000000..cb61f1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/tag/vo/MpTagUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mp.controller.admin.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号标签更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpTagUpdateReqVO extends MpTagBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.http b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.http new file mode 100644 index 0000000..7c61581 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.http @@ -0,0 +1,18 @@ +### 请求 /mp/user/sync 接口 => 成功 +POST {{baseUrl}}/mp/user/sync?accountId=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /mp/user/update 接口 => 成功 +PUT {{baseUrl}}/mp/user/update +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "id": "3", + "nickname": "test", + "remark": "测试备注", + "tagIds": [103, 104] +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.java new file mode 100644 index 0000000..7098bc5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/MpUserController.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.mp.controller.admin.user; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserUpdateReqVO; +import cn.iocoder.yudao.module.mp.convert.user.MpUserConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.service.user.MpUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号粉丝") +@RestController +@RequestMapping("/mp/user") +@Validated +public class MpUserController { + + @Resource + private MpUserService mpUserService; + + @GetMapping("/page") + @Operation(summary = "获得公众号粉丝分页") + @PreAuthorize("@ss.hasPermission('mp:user:query')") + public CommonResult> getUserPage(@Valid MpUserPageReqVO pageVO) { + PageResult pageResult = mpUserService.getUserPage(pageVO); + return success(MpUserConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/get") + @Operation(summary = "获得公众号粉丝") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:user:query')") + public CommonResult getUser(@RequestParam("id") Long id) { + return success(MpUserConvert.INSTANCE.convert(mpUserService.getUser(id))); + } + + @PutMapping("/update") + @Operation(summary = "更新公众号粉丝") + @PreAuthorize("@ss.hasPermission('mp:user:update')") + public CommonResult updateUser(@Valid @RequestBody MpUserUpdateReqVO updateReqVO) { + mpUserService.updateUser(updateReqVO); + return success(true); + } + + @PostMapping("/sync") + @Operation(summary = "同步公众号粉丝") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:user:sync')") + public CommonResult syncUser(@RequestParam("accountId") Long accountId) { + mpUserService.syncUser(accountId); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java new file mode 100644 index 0000000..93b5ba9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.mp.controller.admin.user.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 公众号粉丝分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpUserPageReqVO extends PageParam { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + + @Schema(description = "公众号粉丝标识,模糊匹配", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String openid; + + @Schema(description = "微信生态唯一标识,模糊匹配", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String unionId; + + @Schema(description = "公众号粉丝昵称,模糊匹配", example = "芋艿") + private String nickname; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserRespVO.java new file mode 100644 index 0000000..95f919a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserRespVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.mp.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 公众号粉丝 Response VO") +@Data +public class MpUserRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公众号粉丝标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String openid; + + @Schema(description = "微信生态唯一标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") + private String unionId; + + @Schema(description = "关注状态 参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer subscribeStatus; + @Schema(description = "关注时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime subscribeTime; + @Schema(description = "取消关注时间") + private LocalDateTime unsubscribeTime; + + @Schema(description = "昵称", example = "芋道") + private String nickname; + @Schema(description = "头像地址", example = "https://www.iocoder.cn/1.png") + private String headImageUrl; + @Schema(description = "语言", example = "zh_CN") + private String language; + @Schema(description = "国家", example = "中国") + private String country; + @Schema(description = "省份", example = "广东省") + private String province; + @Schema(description = "城市", example = "广州市") + private String city; + @Schema(description = "备注", example = "你是一个芋头嘛") + private String remark; + + @Schema(description = "标签编号数组", example = "1,2,3") + private List tagIds; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long accountId; + @Schema(description = "公众号账号的 appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890") + private String appId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserUpdateReqVO.java new file mode 100644 index 0000000..3089ed3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserUpdateReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.mp.controller.admin.user.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 公众号粉丝更新 Request VO") +@Data +public class MpUserUpdateReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "昵称", example = "芋道") + private String nickname; + + @Schema(description = "备注", example = "你是一个芋头嘛") + private String remark; + + @Schema(description = "标签编号数组", example = "1,2,3") + private List tagIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/package-info.java new file mode 100644 index 0000000..31a0577 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.mp.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/account/MpAccountConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/account/MpAccountConvert.java new file mode 100644 index 0000000..5f8fde3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/account/MpAccountConvert.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.mp.convert.account; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountSimpleRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface MpAccountConvert { + + MpAccountConvert INSTANCE = Mappers.getMapper(MpAccountConvert.class); + + MpAccountDO convert(MpAccountCreateReqVO bean); + + MpAccountDO convert(MpAccountUpdateReqVO bean); + + MpAccountRespVO convert(MpAccountDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/material/MpMaterialConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/material/MpMaterialConvert.java new file mode 100644 index 0000000..ca4f69c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/material/MpMaterialConvert.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.mp.convert.material; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadRespVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.io.File; + +@Mapper +public interface MpMaterialConvert { + + MpMaterialConvert INSTANCE = Mappers.getMapper(MpMaterialConvert.class); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(source = "account.id", target = "accountId"), + @Mapping(source = "account.appId", target = "appId"), + @Mapping(source = "name", target = "name") + }) + MpMaterialDO convert(String mediaId, String type, String url, MpAccountDO account, + String name); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(source = "account.id", target = "accountId"), + @Mapping(source = "account.appId", target = "appId"), + @Mapping(source = "name", target = "name") + }) + MpMaterialDO convert(String mediaId, String type, String url, MpAccountDO account, + String name, String title, String introduction, String mpUrl); + + MpMaterialUploadRespVO convert(MpMaterialDO bean); + + default WxMpMaterial convert(String name, File file, String title, String introduction) { + return new WxMpMaterial(name, file, title, introduction); + } + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java new file mode 100644 index 0000000..a5ae32a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/menu/MpMenuConvert.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.mp.convert.menu; + +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import me.chanjar.weixin.common.bean.menu.WxMenuButton; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface MpMenuConvert { + + MpMenuConvert INSTANCE = Mappers.getMapper(MpMenuConvert.class); + + MpMenuRespVO convert(MpMenuDO bean); + + List convertList(List list); + + @Mappings({ + @Mapping(source = "menu.appId", target = "appId"), + @Mapping(source = "menu.replyMessageType", target = "type"), + @Mapping(source = "menu.replyContent", target = "content"), + @Mapping(source = "menu.replyMediaId", target = "mediaId"), + @Mapping(source = "menu.replyThumbMediaId", target = "thumbMediaId"), + @Mapping(source = "menu.replyTitle", target = "title"), + @Mapping(source = "menu.replyDescription", target = "description"), + @Mapping(source = "menu.replyArticles", target = "articles"), + @Mapping(source = "menu.replyMusicUrl", target = "musicUrl"), + @Mapping(source = "menu.replyHqMusicUrl", target = "hqMusicUrl"), + }) + MpMessageSendOutReqBO convert(String openid, MpMenuDO menu); + + List convert(List list); + + @Mappings({ + @Mapping(source = "menuKey", target = "key"), + @Mapping(source = "children", target = "subButtons"), + @Mapping(source = "miniProgramAppId", target = "appId"), + @Mapping(source = "miniProgramPagePath", target = "pagePath"), + }) + WxMenuButton convert(MpMenuSaveReqVO.Menu bean); + + MpMenuDO convert02(MpMenuSaveReqVO.Menu menu); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java new file mode 100644 index 0000000..c7cf890 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mp.convert.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface MpAutoReplyConvert { + + MpAutoReplyConvert INSTANCE = Mappers.getMapper(MpAutoReplyConvert.class); + + @Mappings({ + @Mapping(source = "reply.appId", target = "appId"), + @Mapping(source = "reply.responseMessageType", target = "type"), + @Mapping(source = "reply.responseContent", target = "content"), + @Mapping(source = "reply.responseMediaId", target = "mediaId"), + @Mapping(source = "reply.responseTitle", target = "title"), + @Mapping(source = "reply.responseDescription", target = "description"), + @Mapping(source = "reply.responseArticles", target = "articles"), + }) + MpMessageSendOutReqBO convert(String openid, MpAutoReplyDO reply); + + PageResult convertPage(PageResult page); + + MpAutoReplyRespVO convert(MpAutoReplyDO bean); + + MpAutoReplyDO convert(MpAutoReplyCreateReqVO bean); + + MpAutoReplyDO convert(MpAutoReplyUpdateReqVO bean); +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpMessageConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpMessageConvert.java new file mode 100644 index 0000000..8f31a68 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpMessageConvert.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.mp.convert.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage; +import me.chanjar.weixin.mp.builder.outxml.BaseBuilder; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface MpMessageConvert { + + MpMessageConvert INSTANCE = Mappers.getMapper(MpMessageConvert.class); + + MpMessageRespVO convert(MpMessageDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default MpMessageDO convert(WxMpXmlMessage wxMessage, MpAccountDO account, MpUserDO user) { + MpMessageDO message = convert(wxMessage); + if (account != null) { + message.setAccountId(account.getId()).setAppId(account.getAppId()); + } + if (user != null) { + message.setUserId(user.getId()).setOpenid(user.getOpenid()); + } + return message; + } + @Mappings(value = { + @Mapping(source = "msgType", target = "type"), + @Mapping(target = "createTime", ignore = true), + }) + MpMessageDO convert(WxMpXmlMessage bean); + + default MpMessageDO convert(MpMessageSendOutReqBO sendReqBO, MpAccountDO account, MpUserDO user) { + // 构建消息 + MpMessageDO message = new MpMessageDO(); + message.setType(sendReqBO.getType()); + switch (sendReqBO.getType()) { + case WxConsts.XmlMsgType.TEXT: // 1. 文本 + message.setContent(sendReqBO.getContent()); + break; + case WxConsts.XmlMsgType.IMAGE: // 2. 图片 + case WxConsts.XmlMsgType.VOICE: // 3. 语音 + message.setMediaId(sendReqBO.getMediaId()); + break; + case WxConsts.XmlMsgType.VIDEO: // 4. 视频 + message.setMediaId(sendReqBO.getMediaId()) + .setTitle(sendReqBO.getTitle()).setDescription(sendReqBO.getDescription()); + break; + case WxConsts.XmlMsgType.NEWS: // 5. 图文 + message.setArticles(sendReqBO.getArticles()); + case WxConsts.XmlMsgType.MUSIC: // 6. 音乐 + message.setTitle(sendReqBO.getTitle()).setDescription(sendReqBO.getDescription()) + .setMusicUrl(sendReqBO.getMusicUrl()).setHqMusicUrl(sendReqBO.getHqMusicUrl()) + .setThumbMediaId(sendReqBO.getThumbMediaId()); + break; + default: + throw new IllegalArgumentException("不支持的消息类型:" + message.getType()); + } + + // 其它字段 + if (account != null) { + message.setAccountId(account.getId()).setAppId(account.getAppId()); + } + if (user != null) { + message.setUserId(user.getId()).setOpenid(user.getOpenid()); + } + return message; + } + + default WxMpXmlOutMessage convert02(MpMessageDO message, MpAccountDO account) { + BaseBuilder builder; + // 个性化字段 + switch (message.getType()) { + case WxConsts.XmlMsgType.TEXT: + builder = WxMpXmlOutMessage.TEXT().content(message.getContent()); + break; + case WxConsts.XmlMsgType.IMAGE: + builder = WxMpXmlOutMessage.IMAGE().mediaId(message.getMediaId()); + break; + case WxConsts.XmlMsgType.VOICE: + builder = WxMpXmlOutMessage.VOICE().mediaId(message.getMediaId()); + break; + case WxConsts.XmlMsgType.VIDEO: + builder = WxMpXmlOutMessage.VIDEO().mediaId(message.getMediaId()) + .title(message.getTitle()).description(message.getDescription()); + break; + case WxConsts.XmlMsgType.NEWS: + builder = WxMpXmlOutMessage.NEWS().articles(convertList02(message.getArticles())); + break; + case WxConsts.XmlMsgType.MUSIC: + builder = WxMpXmlOutMessage.MUSIC().title(message.getTitle()).description(message.getDescription()) + .musicUrl(message.getMusicUrl()).hqMusicUrl(message.getHqMusicUrl()) + .thumbMediaId(message.getThumbMediaId()); + break; + default: + throw new IllegalArgumentException("不支持的消息类型:" + message.getType()); + } + // 通用字段 + builder.fromUser(account.getAccount()); + builder.toUser(message.getOpenid()); + return builder.build(); + } + List convertList02(List list); + + default WxMpKefuMessage convert(MpMessageSendReqVO sendReqVO, MpUserDO user) { + me.chanjar.weixin.mp.builder.kefu.BaseBuilder builder; + // 个性化字段 + switch (sendReqVO.getType()) { + case WxConsts.KefuMsgType.TEXT: + builder = WxMpKefuMessage.TEXT().content(sendReqVO.getContent()); + break; + case WxConsts.KefuMsgType.IMAGE: + builder = WxMpKefuMessage.IMAGE().mediaId(sendReqVO.getMediaId()); + break; + case WxConsts.KefuMsgType.VOICE: + builder = WxMpKefuMessage.VOICE().mediaId(sendReqVO.getMediaId()); + break; + case WxConsts.KefuMsgType.VIDEO: + builder = WxMpKefuMessage.VIDEO().mediaId(sendReqVO.getMediaId()) + .title(sendReqVO.getTitle()).description(sendReqVO.getDescription()); + break; + case WxConsts.KefuMsgType.NEWS: + builder = WxMpKefuMessage.NEWS().articles(convertList03(sendReqVO.getArticles())); + break; + case WxConsts.KefuMsgType.MUSIC: + builder = WxMpKefuMessage.MUSIC().title(sendReqVO.getTitle()).description(sendReqVO.getDescription()) + .thumbMediaId(sendReqVO.getThumbMediaId()) + .musicUrl(sendReqVO.getMusicUrl()).hqMusicUrl(sendReqVO.getHqMusicUrl()); + break; + default: + throw new IllegalArgumentException("不支持的消息类型:" + sendReqVO.getType()); + } + // 通用字段 + builder.toUser(user.getOpenid()); + return builder.build(); + } + List convertList03(List list); + + default MpMessageDO convert(WxMpKefuMessage wxMessage, MpAccountDO account, MpUserDO user) { + MpMessageDO message = convert(wxMessage); + if (account != null) { + message.setAccountId(account.getId()).setAppId(account.getAppId()); + } + if (user != null) { + message.setUserId(user.getId()).setOpenid(user.getOpenid()); + } + return message; + } + @Mappings(value = { + @Mapping(source = "msgType", target = "type"), + @Mapping(target = "createTime", ignore = true), + }) + MpMessageDO convert(WxMpKefuMessage bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/statistics/MpStatisticsConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/statistics/MpStatisticsConvert.java new file mode 100644 index 0000000..9d4d7e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/statistics/MpStatisticsConvert.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.mp.convert.statistics; + +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsInterfaceSummaryRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsUpstreamMessageRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsUserCumulateRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsUserSummaryRespVO; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Mapper +public interface MpStatisticsConvert { + + MpStatisticsConvert INSTANCE = Mappers.getMapper(MpStatisticsConvert.class); + + List convertList01(List list); + + List convertList02(List list); + + List convertList03(List list); + + @Mappings({ + @Mapping(target = "refDate", expression = "java(dateFormat0(bean.getRefDate()))"), + @Mapping(source = "msgUser", target = "messageUser"), + @Mapping(source = "msgCount", target = "messageCount"), + }) + MpStatisticsUpstreamMessageRespVO convert(WxDataCubeMsgResult bean); + + List convertList04(List list); + + @Mapping(target = "refDate", expression = "java(dateFormat0(bean.getRefDate()))") + MpStatisticsInterfaceSummaryRespVO convert(WxDataCubeInterfaceResult bean); + + @Named("dateFormat0") + default LocalDateTime dateFormat0(String date) { + return LocalDate.parse(date, DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY)).atStartOfDay(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/tag/MpTagConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/tag/MpTagConvert.java new file mode 100644 index 0000000..727ccd3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/tag/MpTagConvert.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.mp.convert.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagSimpleRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; +import me.chanjar.weixin.mp.bean.tag.WxUserTag; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface MpTagConvert { + + MpTagConvert INSTANCE = Mappers.getMapper(MpTagConvert.class); + + WxUserTag convert(MpTagUpdateReqVO bean); + + MpTagRespVO convert(WxUserTag bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + @Mappings({ + @Mapping(target = "id", ignore = true), + @Mapping(source = "tag.id", target = "tagId"), + @Mapping(source = "tag.name", target = "name"), + @Mapping(source = "tag.count", target = "count"), + @Mapping(source = "account.id", target = "accountId"), + @Mapping(source = "account.appId", target = "appId"), + }) + MpTagDO convert(WxUserTag tag, MpAccountDO account); + + MpTagRespVO convert(MpTagDO mpTagDO); + + List convertList02(List list); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java new file mode 100644 index 0000000..13ed0b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.mp.convert.user; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface MpUserConvert { + + MpUserConvert INSTANCE = Mappers.getMapper(MpUserConvert.class); + + MpUserRespVO convert(MpUserDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + @Mappings(value = { + @Mapping(source = "openId", target = "openid"), + @Mapping(source = "unionId", target = "unionId"), + @Mapping(source = "headImgUrl", target = "headImageUrl"), + @Mapping(target = "subscribeTime", ignore = true), // 单独转换 + }) + MpUserDO convert(WxMpUser wxMpUser); + + default MpUserDO convert(MpAccountDO account, WxMpUser wxMpUser) { + MpUserDO user = convert(wxMpUser); + user.setSubscribeStatus(wxMpUser.getSubscribe() ? CommonStatusEnum.ENABLE.getStatus() + : CommonStatusEnum.DISABLE.getStatus()); + user.setSubscribeTime(LocalDateTimeUtil.of(wxMpUser.getSubscribeTime() * 1000L)); + if (account != null) { + user.setAccountId(account.getId()); + user.setAppId(account.getAppId()); + } + return user; + } + + default List convertList(MpAccountDO account, List wxUsers) { + return CollectionUtils.convertList(wxUsers, wxUser -> convert(account, wxUser)); + } + + MpUserDO convert(MpUserUpdateReqVO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java new file mode 100644 index 0000000..eddf87b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/account/MpAccountDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.account; + +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 公众号账号 DO + * + * @author 芋道源码 + */ +@TableName("mp_account") +@KeySequence("mp_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MpAccountDO extends TenantBaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 公众号名称 + */ + private String name; + /** + * 公众号账号 + */ + private String account; + /** + * 公众号 appid + */ + private String appId; + /** + * 公众号密钥 + */ + private String appSecret; + /** + * 公众号token + */ + private String token; + /** + * 消息加解密密钥 + */ + private String aesKey; + /** + * 二维码图片 URL + */ + private String qrCodeUrl; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/material/MpMaterialDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/material/MpMaterialDO.java new file mode 100644 index 0000000..735235e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/material/MpMaterialDO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.material; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import me.chanjar.weixin.common.api.WxConsts; + +/** + * 公众号素材 DO + * + * 1. 临时素材 + * 2. 永久素材 + * + * @author 芋道源码 + */ +@TableName("mp_material") +@KeySequence("mp_material_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MpMaterialDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + + /** + * 公众号素材 id + */ + private String mediaId; + /** + * 文件类型 + * + * 枚举 {@link WxConsts.MediaFileType} + */ + private String type; + /** + * 是否永久 + * + * true - 永久素材 + * false - 临时素材 + */ + private Boolean permanent; + /** + * 文件服务器的 URL + */ + private String url; + + /** + * 名字 + * + * 永久素材:非空 + * 临时素材:可能为空。 + * 1. 为空的情况:粉丝主动发送的图片、语音等 + * 2. 非空的情况:主动发送给粉丝的图片、语音等 + */ + private String name; + + /** + * 公众号文件 URL + * + * 只有【永久素材】使用 + */ + private String mpUrl; + + /** + * 视频素材的标题 + * + * 只有【永久素材】使用 + */ + private String title; + /** + * 视频素材的描述 + * + * 只有【永久素材】使用 + */ + private String introduction; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/menu/MpMenuDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/menu/MpMenuDO.java new file mode 100644 index 0000000..2e6aa73 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/menu/MpMenuDO.java @@ -0,0 +1,184 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.menu; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +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 lombok.ToString; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.api.WxConsts.MenuButtonType; + +import java.util.List; + +/** + * 公众号菜单 DO + * + * @author 芋道源码 + */ +@TableName(value = "mp_menu", autoResultMap = true) +@KeySequence("mp_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpMenuDO extends BaseDO { + + /** + * 编号 - 顶级菜单 + */ + public static final Long ID_ROOT = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + + /** + * 菜单名称 + */ + private String name; + /** + * 菜单标识 + * + * 支持多 DB 类型时,无法直接使用 key + @TableField("menuKey") 来实现转换,原因是 "menuKey" AS key 而存在报错 + */ + private String menuKey; + /** + * 父菜单编号 + */ + private Long parentId; + + // ========== 按钮操作 ========== + + /** + * 按钮类型 + * + * 枚举 {@link MenuButtonType} + */ + private String type; + + /** + * 网页链接 + * + * 粉丝点击菜单可打开链接,不超过 1024 字节 + * + * 类型为 {@link WxConsts.XmlMsgType} 的 VIEW、MINIPROGRAM + */ + private String url; + + /** + * 小程序的 appId + * + * 类型为 {@link MenuButtonType} 的 MINIPROGRAM + */ + private String miniProgramAppId; + /** + * 小程序的页面路径 + * + * 类型为 {@link MenuButtonType} 的 MINIPROGRAM + */ + private String miniProgramPagePath; + + /** + * 跳转图文的媒体编号 + */ + private String articleId; + + // ========== 消息内容 ========== + + /** + * 消息类型 + * + * 当 {@link #type} 为 CLICK、SCANCODE_WAITMSG + * + * 枚举 {@link WxConsts.XmlMsgType} 中的 TEXT、IMAGE、VOICE、VIDEO、NEWS、MUSIC + */ + private String replyMessageType; + + /** + * 回复的消息内容 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT + */ + private String replyContent; + + /** + * 回复的媒体 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO + */ + private String replyMediaId; + /** + * 回复的媒体 URL + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO + */ + private String replyMediaUrl; + + /** + * 回复的标题 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + private String replyTitle; + /** + * 回复的描述 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + private String replyDescription; + + /** + * 回复的缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String replyThumbMediaId; + /** + * 回复的缩略图的媒体 URL + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String replyThumbMediaUrl; + + /** + * 回复的图文消息数组 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class) + private List replyArticles; + + /** + * 回复的音乐链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String replyMusicUrl; + /** + * 回复的高质量音乐链接 + * + * WIFI 环境优先使用该链接播放音乐 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String replyHqMusicUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpAutoReplyDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpAutoReplyDO.java new file mode 100644 index 0000000..52f4539 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpAutoReplyDO.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.message; + +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +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 lombok.ToString; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.api.WxConsts.XmlMsgType; + +import java.util.List; +import java.util.Set; + +/** + * 公众号消息自动回复 DO + * + * @author 芋道源码 + */ +@TableName(value = "mp_auto_reply", autoResultMap = true) +@KeySequence("mp_auto_reply_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpAutoReplyDO extends BaseDO { + + public static Set REQUEST_MESSAGE_TYPE = SetUtils.asSet(WxConsts.XmlMsgType.TEXT, WxConsts.XmlMsgType.IMAGE, + WxConsts.XmlMsgType.VOICE, WxConsts.XmlMsgType.VIDEO, WxConsts.XmlMsgType.SHORTVIDEO, + WxConsts.XmlMsgType.LOCATION, WxConsts.XmlMsgType.LINK); + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + + /** + * 回复类型 + * + * 枚举 {@link MpAutoReplyTypeEnum} + */ + private Integer type; + + // ==================== 请求消息 ==================== + + /** + * 请求的关键字 + * + * 当 {@link #type} 为 {@link MpAutoReplyTypeEnum#KEYWORD} + */ + private String requestKeyword; + /** + * 请求的关键字的匹配 + * + * 当 {@link #type} 为 {@link MpAutoReplyTypeEnum#KEYWORD} + * + * 枚举 {@link MpAutoReplyMatchEnum} + */ + private Integer requestMatch; + + /** + * 请求的消息类型 + * + * 当 {@link #type} 为 {@link MpAutoReplyTypeEnum#MESSAGE} + * + * 枚举 {@link XmlMsgType} 中的 {@link #REQUEST_MESSAGE_TYPE} + */ + private String requestMessageType; + + // ==================== 响应消息 ==================== + + /** + * 回复的消息类型 + * + * 枚举 {@link XmlMsgType} 中的 TEXT、IMAGE、VOICE、VIDEO、NEWS + */ + private String responseMessageType; + + /** + * 回复的消息内容 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT + */ + private String responseContent; + + /** + * 回复的媒体 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO + */ + private String responseMediaId; + /** + * 回复的媒体 URL + */ + private String responseMediaUrl; + + /** + * 回复的标题 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + private String responseTitle; + /** + * 回复的描述 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + private String responseDescription; + + /** + * 回复的缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String responseThumbMediaId; + /** + * 回复的缩略图的媒体 URL + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String responseThumbMediaUrl; + + /** + * 回复的图文消息 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @TableField(typeHandler = MpMessageDO.ArticleTypeHandler.class) + private List responseArticles; + + /** + * 回复的音乐链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String responseMusicUrl; + /** + * 回复的高质量音乐链接 + * + * WIFI 环境优先使用该链接播放音乐 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String responseHqMusicUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageDO.java new file mode 100644 index 0000000..cb14010 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageDO.java @@ -0,0 +1,255 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.message; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import lombok.*; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.builder.kefu.NewsBuilder; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; +import java.util.List; + +/** + * 公众号消息 DO + * + * @author 芋道源码 + */ +@TableName(value = "mp_message", autoResultMap = true) +@KeySequence("mp_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MpMessageDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 微信公众号消息 id + */ + private Long msgId; + /** + * 公众号账号的 ID + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appid + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + /** + * 公众号粉丝的编号 + * + * 关联 {@link MpUserDO#getId()} + */ + private Long userId; + /** + * 公众号粉丝标志 + * + * 冗余 {@link MpUserDO#getOpenid()} + */ + private String openid; + + /** + * 消息类型 + * + * 枚举 {@link WxConsts.XmlMsgType} + */ + private String type; + /** + * 消息来源 + * + * 枚举 {@link MpMessageSendFromEnum} + */ + private Integer sendFrom; + + // ========= 普通消息内容 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html + + /** + * 消息内容 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT + */ + private String content; + + /** + * 媒体文件的编号 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO + */ + private String mediaId; + /** + * 媒体文件的 URL + */ + private String mediaUrl; + /** + * 语音识别后文本 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VOICE + */ + private String recognition; + /** + * 语音格式,如 amr,speex 等 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VOICE + */ + private String format; + /** + * 标题 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO、MUSIC、LINK + */ + private String title; + /** + * 描述 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO、MUSIC + */ + private String description; + + /** + * 缩略图的媒体 id,通过素材管理中的接口上传多媒体文件,得到的 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String thumbMediaId; + /** + * 缩略图的媒体 URL + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC、VIDEO + */ + private String thumbMediaUrl; + + /** + * 点击图文消息跳转链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 LINK + */ + private String url; + + /** + * 地理位置维度 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION + */ + private Double locationX; + /** + * 地理位置经度 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION + */ + private Double locationY; + /** + * 地图缩放大小 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION + */ + private Double scale; + /** + * 详细地址 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 LOCATION + * + * 例如说杨浦区黄兴路 221-4 号临 + */ + private String label; + + /** + * 图文消息数组 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @TableField(typeHandler = ArticleTypeHandler.class) + private List
articles; + + /** + * 音乐链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String musicUrl; + /** + * 高质量音乐链接 + * + * WIFI 环境优先使用该链接播放音乐 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + private String hqMusicUrl; + + // ========= 事件推送 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html + + /** + * 事件类型 + * + * 枚举 {@link WxConsts.EventType} + */ + private String event; + /** + * 事件 Key + * + * 1. {@link WxConsts.EventType} 的 SCAN:qrscene_ 为前缀,后面为二维码的参数值 + * 2. {@link WxConsts.EventType} 的 CLICK:与自定义菜单接口中 KEY 值对应 + */ + private String eventKey; + + /** + * 文章 + */ + @Data + public static class Article implements Serializable { + + /** + * 图文消息标题 + */ + @NotEmpty(message = "图文消息标题不能为空", groups = NewsBuilder.class) + private String title; + /** + * 图文消息描述 + */ + @NotEmpty(message = "图文消息描述不能为空", groups = NewsBuilder.class) + private String description; + /** + * 图片链接 + * + * 支持 JPG、PNG 格式,较好的效果为大图 360*200,小图 200*200 + */ + @NotEmpty(message = "图片链接不能为空", groups = NewsBuilder.class) + private String picUrl; + /** + * 点击图文消息跳转链接 + */ + @NotEmpty(message = "点击图文消息跳转链接不能为空", groups = NewsBuilder.class) + private String url; + + } + + // TODO @芋艿:可以找一些新的思路 + public static class ArticleTypeHandler extends AbstractJsonTypeHandler> { + + @Override + protected List
parse(String json) { + return JsonUtils.parseArray(json, Article.class); + } + + @Override + protected String toJson(List
obj) { + return JsonUtils.toJsonString(obj); + } + + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/tag/MpTagDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/tag/MpTagDO.java new file mode 100644 index 0000000..8a5b9f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/tag/MpTagDO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.tag; + +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import lombok.*; + +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import me.chanjar.weixin.mp.bean.tag.WxUserTag; + +/** + * 公众号标签 DO + * + * @author 芋道源码 + */ +@TableName("mp_tag") +@KeySequence("mp_tag_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MpTagDO extends BaseDO { + + /** + * 主键 + */ + @TableId(type = IdType.INPUT) + private Long id; + /** + * 公众号标签 id + */ + private Long tagId; + /** + * 标签名 + */ + private String name; + /** + * 此标签下粉丝数 + * + * 冗余:{@link WxUserTag#getCount()} 字段,需要管理员点击【同步】后,更新该字段 + */ + private Integer count; + + /** + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/user/MpUserDO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/user/MpUserDO.java new file mode 100644 index 0000000..418e96f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/user/MpUserDO.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.user; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 微信公众号粉丝 DO + * + * @author 芋道源码 + */ +@TableName(value = "mp_user", autoResultMap = true) +@KeySequence("mp_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MpUserDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 粉丝标识 + */ + private String openid; + /** + * 微信生态唯一标识 + */ + private String unionId; + /** + * 关注状态 + * + * 枚举 {@link CommonStatusEnum} + * 1. 开启 - 已关注 + * 2. 禁用 - 取消关注 + */ + private Integer subscribeStatus; + /** + * 关注时间 + */ + private LocalDateTime subscribeTime; + /** + * 取消关注时间 + */ + private LocalDateTime unsubscribeTime; + /** + * 昵称 + * + * 注意,2021-12-27 公众号接口不再返回头像和昵称,只能通过微信公众号的网页登录获取 + */ + private String nickname; + /** + * 头像地址 + * + * 注意,2021-12-27 公众号接口不再返回头像和昵称,只能通过微信公众号的网页登录获取 + */ + private String headImageUrl; + /** + * 语言 + */ + private String language; + /** + * 国家 + */ + private String country; + /** + * 省份 + */ + private String province; + /** + * 城市 + */ + private String city; + /** + * 备注 + */ + private String remark; + /** + * 标签编号数组 + * + * 注意,对应的是 {@link MpTagDO#getTagId()} 字段 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List tagIds; + + /** + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} + */ + private String appId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java new file mode 100644 index 0000000..30c54fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.account; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; + +@Mapper +public interface MpAccountMapper extends BaseMapperX { + + default PageResult selectPage(MpAccountPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MpAccountDO::getName, reqVO.getName()) + .likeIfPresent(MpAccountDO::getAccount, reqVO.getAccount()) + .likeIfPresent(MpAccountDO::getAppId, reqVO.getAppId()) + .orderByDesc(MpAccountDO::getId)); + } + + default MpAccountDO selectByAppId(String appId) { + return selectOne(MpAccountDO::getAppId, appId); + } + + @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}") + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/material/MpMaterialMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/material/MpMaterialMapper.java new file mode 100644 index 0000000..ca3c6b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/material/MpMaterialMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.material; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface MpMaterialMapper extends BaseMapperX { + + default MpMaterialDO selectByAccountIdAndMediaId(Long accountId, String mediaId) { + return selectOne(MpMaterialDO::getAccountId, accountId, + MpMaterialDO::getMediaId, mediaId); + } + + default PageResult selectPage(MpMaterialPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(MpMaterialDO::getAccountId, pageReqVO.getAccountId()) + .eqIfPresent(MpMaterialDO::getPermanent, pageReqVO.getPermanent()) + .eqIfPresent(MpMaterialDO::getType, pageReqVO.getType()) + .orderByDesc(MpMaterialDO::getId)); + } + + default List selectListByMediaId(Collection mediaIds) { + return selectList(MpMaterialDO::getMediaId, mediaIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/menu/MpMenuMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/menu/MpMenuMapper.java new file mode 100644 index 0000000..fccd7f2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/menu/MpMenuMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.menu; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MpMenuMapper extends BaseMapperX { + + default MpMenuDO selectByAppIdAndMenuKey(String appId, String menuKey) { + return selectOne(MpMenuDO::getAppId, appId, + MpMenuDO::getMenuKey, menuKey); + } + + default List selectListByAccountId(Long accountId) { + return selectList(MpMenuDO::getAccountId, accountId); + } + + default void deleteByAccountId(Long accountId) { + delete(new LambdaQueryWrapperX().eq(MpMenuDO::getAccountId, accountId)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java new file mode 100644 index 0000000..c8260e8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyMatchEnum; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MpAutoReplyMapper extends BaseMapperX { + + default PageResult selectPage(MpMessagePageReqVO pageVO) { + return selectPage(pageVO, new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAccountId, pageVO.getAccountId()) + .eqIfPresent(MpAutoReplyDO::getType, pageVO.getType())); + } + + default List selectListByAppIdAndKeywordAll(String appId, String requestKeyword) { + return selectList(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAppId, appId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.KEYWORD.getType()) + .eq(MpAutoReplyDO::getRequestMatch, MpAutoReplyMatchEnum.ALL.getMatch()) + .eq(MpAutoReplyDO::getRequestKeyword, requestKeyword)); + } + + default List selectListByAppIdAndKeywordLike(String appId, String requestKeyword) { + return selectList(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAppId, appId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.KEYWORD.getType()) + .eq(MpAutoReplyDO::getRequestMatch, MpAutoReplyMatchEnum.LIKE.getMatch()) + .like(MpAutoReplyDO::getRequestKeyword, requestKeyword)); + } + + default List selectListByAppIdAndMessage(String appId, String requestMessageType) { + return selectList(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAppId, appId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType()) + .eq(MpAutoReplyDO::getRequestMessageType, requestMessageType)); + } + + default List selectListByAppIdAndSubscribe(String appId) { + return selectList(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAppId, appId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType())); + } + + default MpAutoReplyDO selectByAccountIdAndSubscribe(Long accountId) { + return selectOne(MpAutoReplyDO::getAccountId, accountId, + MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType()); + } + + default MpAutoReplyDO selectByAccountIdAndMessage(Long accountId, String requestMessageType) { + return selectOne(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAccountId, accountId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType()) + .eq(MpAutoReplyDO::getRequestMessageType, requestMessageType)); + } + + default MpAutoReplyDO selectByAccountIdAndKeyword(Long accountId, String requestKeyword) { + return selectOne(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAccountId, accountId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.KEYWORD.getType()) + .eq(MpAutoReplyDO::getRequestKeyword, requestKeyword)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageMapper.java new file mode 100644 index 0000000..72ba566 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MpMessageMapper extends BaseMapperX { + + default PageResult selectPage(MpMessagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MpMessageDO::getAccountId, reqVO.getAccountId()) + .eqIfPresent(MpMessageDO::getType, reqVO.getType()) + .eqIfPresent(MpMessageDO::getOpenid, reqVO.getOpenid()) + .betweenIfPresent(MpMessageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MpMessageDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/tag/MpTagMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/tag/MpTagMapper.java new file mode 100644 index 0000000..760f53a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/tag/MpTagMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MpTagMapper extends BaseMapperX { + + default PageResult selectPage(MpTagPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MpTagDO::getAccountId, reqVO.getAccountId()) + .likeIfPresent(MpTagDO::getName, reqVO.getName()) + .orderByDesc(MpTagDO::getId)); + } + + default List selectListByAccountId(Long accountId) { + return selectList(MpTagDO::getAccountId, accountId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/user/MpUserMapper.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/user/MpUserMapper.java new file mode 100644 index 0000000..bd13f92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/user/MpUserMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.user; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MpUserMapper extends BaseMapperX { + + default PageResult selectPage(MpUserPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MpUserDO::getOpenid, reqVO.getOpenid()) + .likeIfPresent(MpUserDO::getNickname, reqVO.getNickname()) + .eqIfPresent(MpUserDO::getAccountId, reqVO.getAccountId()) + .orderByDesc(MpUserDO::getId)); + } + + default MpUserDO selectByAppIdAndOpenid(String appId, String openid) { + return selectOne(MpUserDO::getAppId, appId, + MpUserDO::getOpenid, openid); + } + + default List selectListByAppIdAndOpenid(String appId, List openids) { + return selectList(new LambdaQueryWrapperX() + .eq(MpUserDO::getAppId, appId) + .in(MpUserDO::getOpenid, openids)); + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java new file mode 100644 index 0000000..c908660 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/MpConfiguration.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.mp.framework.mp.config; + +import cn.iocoder.yudao.module.mp.framework.mp.core.DefaultMpServiceFactory; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.handler.menu.MenuHandler; +import cn.iocoder.yudao.module.mp.service.handler.message.MessageReceiveHandler; +import cn.iocoder.yudao.module.mp.service.handler.message.MessageAutoReplyHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.KfSessionHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.NullHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.ScanHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.StoreCheckNotifyHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.LocationHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.SubscribeHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.UnsubscribeHandler; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * 微信公众号的配置类 + * + * @author 芋道源码 + */ +@Configuration +public class MpConfiguration { + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public RedisTemplateWxRedisOps redisTemplateWxRedisOps(StringRedisTemplate stringRedisTemplate) { + return new RedisTemplateWxRedisOps(stringRedisTemplate); + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public MpServiceFactory mpServiceFactory(RedisTemplateWxRedisOps redisTemplateWxRedisOps, + WxMpProperties wxMpProperties, + MessageReceiveHandler messageReceiveHandler, + KfSessionHandler kfSessionHandler, + StoreCheckNotifyHandler storeCheckNotifyHandler, + MenuHandler menuHandler, + NullHandler nullHandler, + SubscribeHandler subscribeHandler, + UnsubscribeHandler unsubscribeHandler, + LocationHandler locationHandler, + ScanHandler scanHandler, + MessageAutoReplyHandler messageAutoReplyHandler) { + return new DefaultMpServiceFactory(redisTemplateWxRedisOps, wxMpProperties, + messageReceiveHandler, kfSessionHandler, storeCheckNotifyHandler, menuHandler, + nullHandler, subscribeHandler, unsubscribeHandler, locationHandler, scanHandler, messageAutoReplyHandler); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java new file mode 100644 index 0000000..414f73a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.module.mp.framework.mp.core; + +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.service.handler.menu.MenuHandler; +import cn.iocoder.yudao.module.mp.service.handler.message.MessageReceiveHandler; +import cn.iocoder.yudao.module.mp.service.handler.message.MessageAutoReplyHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.KfSessionHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.NullHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.ScanHandler; +import cn.iocoder.yudao.module.mp.service.handler.other.StoreCheckNotifyHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.LocationHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.SubscribeHandler; +import cn.iocoder.yudao.module.mp.service.handler.user.UnsubscribeHandler; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import com.google.common.collect.Maps; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; +import me.chanjar.weixin.mp.constant.WxMpEventConstants; + +import java.util.List; +import java.util.Map; + +/** + * 默认的 {@link MpServiceFactory} 实现类 + * + * @author 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class DefaultMpServiceFactory implements MpServiceFactory { + + /** + * 微信 appId 与 WxMpService 的映射 + */ + private volatile Map appId2MpServices; + /** + * 公众号账号 id 与 WxMpService 的映射 + */ + private volatile Map id2MpServices; + /** + * 微信 appId 与 WxMpMessageRouter 的映射 + */ + private volatile Map mpMessageRouters; + + private final RedisTemplateWxRedisOps redisTemplateWxRedisOps; + private final WxMpProperties mpProperties; + + // ========== 各种 Handler ========== + + private final MessageReceiveHandler messageReceiveHandler; + private final KfSessionHandler kfSessionHandler; + private final StoreCheckNotifyHandler storeCheckNotifyHandler; + private final MenuHandler menuHandler; + private final NullHandler nullHandler; + private final SubscribeHandler subscribeHandler; + private final UnsubscribeHandler unsubscribeHandler; + private final LocationHandler locationHandler; + private final ScanHandler scanHandler; + private final MessageAutoReplyHandler messageAutoReplyHandler; + + @Override + public void init(List list) { + Map appId2MpServices = Maps.newHashMap(); + Map id2MpServices = Maps.newHashMap(); + Map mpMessageRouters = Maps.newHashMap(); + // 处理 list + list.forEach(account -> { + // 构建 WxMpService 对象 + WxMpService mpService = buildMpService(account); + appId2MpServices.put(account.getAppId(), mpService); + id2MpServices.put(account.getId(), mpService); + // 构建 WxMpMessageRouter 对象 + WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService); + mpMessageRouters.put(account.getAppId(), mpMessageRouter); + }); + + // 设置到缓存 + this.appId2MpServices = appId2MpServices; + this.id2MpServices = id2MpServices; + this.mpMessageRouters = mpMessageRouters; + } + + @Override + public WxMpService getMpService(Long id) { + return id2MpServices.get(id); + } + + @Override + public WxMpService getMpService(String appId) { + return appId2MpServices.get(appId); + } + + @Override + public WxMpMessageRouter getMpMessageRouter(String appId) { + return mpMessageRouters.get(appId); + } + + private WxMpService buildMpService(MpAccountDO account) { + // 第一步,创建 WxMpRedisConfigImpl 对象 + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( + redisTemplateWxRedisOps, mpProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppId(account.getAppId()); + configStorage.setSecret(account.getAppSecret()); + configStorage.setToken(account.getToken()); + configStorage.setAesKey(account.getAesKey()); + + // 第二步,创建 WxMpService 对象 + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + return service; + } + + private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) { + WxMpMessageRouter router = new WxMpMessageRouter(mpService); + // 记录所有事件的日志(异步执行) + router.rule().handler(messageReceiveHandler).next(); + + // 接收客服会话管理事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) + .handler(kfSessionHandler).end(); + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) + .handler(kfSessionHandler) + .end(); + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) + .handler(kfSessionHandler).end(); + + // 门店审核事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxMpEventConstants.POI_CHECK_NOTIFY) + .handler(storeCheckNotifyHandler).end(); + + // 自定义菜单事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end(); + + // 点击菜单连接事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end(); + + // 关注事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler) + .end(); + + // 取消关注事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.EventType.UNSUBSCRIBE) + .handler(unsubscribeHandler).end(); + + // 上报地理位置事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.EventType.LOCATION).handler(locationHandler) + .end(); + + // 接收地理位置消息 + router.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION) + .handler(locationHandler).end(); + + // 扫码事件 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) + .event(WxConsts.EventType.SCAN).handler(scanHandler).end(); + + // 默认 + router.rule().async(false).handler(messageAutoReplyHandler).end(); + return router; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java new file mode 100644 index 0000000..ce017ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.mp.framework.mp.core; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; + +import java.util.List; + +/** + * {@link WxMpService} 工厂接口 + * + * @author 芋道源码 + */ +public interface MpServiceFactory { + + /** + * 基于微信公众号的账号,初始化对应的 WxMpService 与 WxMpMessageRouter 实例 + * + * @param list 公众号的账号列表 + */ + void init(List list); + + /** + * 获得 id 对应的 WxMpService 实例 + * + * @param id 微信公众号的编号 + * @return WxMpService 实例 + */ + WxMpService getMpService(Long id); + + default WxMpService getRequiredMpService(Long id) { + WxMpService wxMpService = getMpService(id); + Assert.notNull(wxMpService, "找到对应 id({}) 的 WxMpService,请核实!", id); + return wxMpService; + } + + /** + * 获得 appId 对应的 WxMpService 实例 + * + * @param appId 微信公众号 appId + * @return WxMpService 实例 + */ + WxMpService getMpService(String appId); + + default WxMpService getRequiredMpService(String appId) { + WxMpService wxMpService = getMpService(appId); + Assert.notNull(wxMpService, "找到对应 appId({}) 的 WxMpService,请核实!", appId); + return wxMpService; + } + + /** + * 获得 appId 对应的 WxMpMessageRouter 实例 + * + * @param appId 微信公众号 appId + * @return WxMpMessageRouter 实例 + */ + WxMpMessageRouter getMpMessageRouter(String appId); + + default WxMpMessageRouter getRequiredMpMessageRouter(String appId) { + WxMpMessageRouter wxMpMessageRouter = getMpMessageRouter(appId); + Assert.notNull(wxMpMessageRouter, "找到对应 appId({}) 的 WxMpMessageRouter,请核实!", appId); + return wxMpMessageRouter; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/context/MpContextHolder.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/context/MpContextHolder.java new file mode 100644 index 0000000..e5c45c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/context/MpContextHolder.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package cn.iocoder.yudao.module.mp.framework.mp.core.context; + +import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenHandleMessageReqVO; +import com.alibaba.ttl.TransmittableThreadLocal; +import lombok.experimental.UtilityClass; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; + +/** + * 微信上下文 Context + * + * 目的:解决微信多公众号的问题,在 {@link WxMpMessageHandler} 实现类中,可以通过 {@link #getAppId()} 获取到当前的 appId + * + * @see cn.iocoder.yudao.module.mp.controller.admin.open.MpOpenController#handleMessage(String, String, MpOpenHandleMessageReqVO) + * + * @author 芋道源码 + */ +public class MpContextHolder { + + /** + * 微信公众号的 appId 上下文 + */ + private static final ThreadLocal APPID = new TransmittableThreadLocal<>(); + + public static void setAppId(String appId) { + APPID.set(appId); + } + + public static String getAppId() { + return APPID.get(); + } + + public static void clear() { + APPID.remove(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/util/MpUtils.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/util/MpUtils.java new file mode 100644 index 0000000..880d8c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/util/MpUtils.java @@ -0,0 +1,167 @@ +package cn.iocoder.yudao.module.mp.framework.mp.core.util; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; + +import javax.validation.Validator; + +/** + * 公众号工具类 + * + * @author 芋道源码 + */ +@Slf4j +public class MpUtils { + + /** + * 校验消息的格式是否符合要求 + * + * @param type 类型 + * @param message 消息 + */ + public static void validateMessage(Validator validator, String type, Object message) { + // 获得对应的校验 group + Class group; + switch (type) { + case WxConsts.XmlMsgType.TEXT: + group = TextMessageGroup.class; + break; + case WxConsts.XmlMsgType.IMAGE: + group = ImageMessageGroup.class; + break; + case WxConsts.XmlMsgType.VOICE: + group = VoiceMessageGroup.class; + break; + case WxConsts.XmlMsgType.VIDEO: + group = VideoMessageGroup.class; + break; + case WxConsts.XmlMsgType.NEWS: + group = NewsMessageGroup.class; + break; + case WxConsts.XmlMsgType.MUSIC: + group = MusicMessageGroup.class; + break; + default: + log.error("[validateMessage][未知的消息类型({})]", message); + throw new IllegalArgumentException("不支持的消息类型:" + type); + } + // 执行校验 + ValidationUtils.validate(validator, message, group); + } + + public static void validateButton(Validator validator, String type, String messageType, Object button) { + if (StrUtil.isBlank(type)) { + return; + } + // 获得对应的校验 group + Class group; + switch (type) { + case WxConsts.MenuButtonType.CLICK: + group = ClickButtonGroup.class; + validateMessage(validator, messageType, button); // 需要额外校验回复的消息格式 + break; + case WxConsts.MenuButtonType.VIEW: + group = ViewButtonGroup.class; + break; + case WxConsts.MenuButtonType.MINIPROGRAM: + group = MiniProgramButtonGroup.class; + break; + case WxConsts.MenuButtonType.SCANCODE_WAITMSG: + group = ScanCodeWaitMsgButtonGroup.class; + validateMessage(validator, messageType, button); // 需要额外校验回复的消息格式 + break; + case "article_" + WxConsts.MenuButtonType.VIEW_LIMITED: + group = ViewLimitedButtonGroup.class; + break; + case WxConsts.MenuButtonType.SCANCODE_PUSH: // 不用校验,直接 return 即可 + case WxConsts.MenuButtonType.PIC_SYSPHOTO: + case WxConsts.MenuButtonType.PIC_PHOTO_OR_ALBUM: + case WxConsts.MenuButtonType.PIC_WEIXIN: + case WxConsts.MenuButtonType.LOCATION_SELECT: + return; + default: + log.error("[validateButton][未知的按钮({})]", button); + throw new IllegalArgumentException("不支持的按钮类型:" + type); + } + // 执行校验 + ValidationUtils.validate(validator, button, group); + } + + /** + * 根据消息类型,获得对应的媒体文件类型 + * + * 注意,不会返回 WxConsts.MediaFileType.THUMB,因为该类型会有明确标注 + * + * @param messageType 消息类型 {@link WxConsts.XmlMsgType} + * @return 媒体文件类型 {@link WxConsts.MediaFileType} + */ + public static String getMediaFileType(String messageType) { + switch (messageType) { + case WxConsts.XmlMsgType.IMAGE: + return WxConsts.MediaFileType.IMAGE; + case WxConsts.XmlMsgType.VOICE: + return WxConsts.MediaFileType.VOICE; + case WxConsts.XmlMsgType.VIDEO: + return WxConsts.MediaFileType.VIDEO; + default: + return WxConsts.MediaFileType.FILE; + } + } + + /** + * Text 类型的消息,参数校验 Group + */ + public interface TextMessageGroup {} + + /** + * Image 类型的消息,参数校验 Group + */ + public interface ImageMessageGroup {} + + /** + * Voice 类型的消息,参数校验 Group + */ + public interface VoiceMessageGroup {} + + /** + * Video 类型的消息,参数校验 Group + */ + public interface VideoMessageGroup {} + + /** + * News 类型的消息,参数校验 Group + */ + public interface NewsMessageGroup {} + + /** + * Music 类型的消息,参数校验 Group + */ + public interface MusicMessageGroup {} + + /** + * Click 类型的按钮,参数校验 Group + */ + public interface ClickButtonGroup {} + + /** + * View 类型的按钮,参数校验 Group + */ + public interface ViewButtonGroup {} + + /** + * MiniProgram 类型的按钮,参数校验 Group + */ + public interface MiniProgramButtonGroup {} + + /** + * SCANCODE_WAITMSG 类型的按钮,参数校验 Group + */ + public interface ScanCodeWaitMsgButtonGroup {} + + /** + * VIEW_LIMITED 类型的按钮,参数校验 Group + */ + public interface ViewLimitedButtonGroup {} +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java new file mode 100644 index 0000000..112ecdd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 mp 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.mp.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/config/MpWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/config/MpWebConfiguration.java new file mode 100644 index 0000000..3e6e1ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/config/MpWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * mp 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class MpWebConfiguration { + + /** + * mp 模块的 API 分组 + */ + @Bean + public GroupedOpenApi mpGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("mp"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/package-info.java new file mode 100644 index 0000000..a103f1c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * mp 模块的 web 配置 + */ +package cn.iocoder.yudao.module.mp.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/package-info.java new file mode 100644 index 0000000..5987180 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/package-info.java @@ -0,0 +1,8 @@ +/** + * mp 模块,我们放微信微信公众号。 + * 例如说:提供微信公众号的账号、菜单、粉丝、标签、消息、自动回复、素材、模板通知、运营数据等功能 + * + * 1. Controller URL:以 /mp/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 mp_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.mp; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java new file mode 100644 index 0000000..e122c6a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountService.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.mp.service.account; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; + +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.ACCOUNT_NOT_EXISTS; + +/** + * 公众号账号 Service 接口 + * + * @author 芋道源码 + */ +public interface MpAccountService { + + /** + * 初始化缓存 + */ + void initLocalCache(); + + /** + * 创建公众号账号 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAccount(@Valid MpAccountCreateReqVO createReqVO); + + /** + * 更新公众号账号 + * + * @param updateReqVO 更新信息 + */ + void updateAccount(@Valid MpAccountUpdateReqVO updateReqVO); + + /** + * 删除公众号账号 + * + * @param id 编号 + */ + void deleteAccount(Long id); + + /** + * 获得公众号账号 + * + * @param id 编号 + * @return 公众号账号 + */ + MpAccountDO getAccount(Long id); + + /** + * 获得公众号账号。若不存在,则抛出业务异常 + * + * @param id 编号 + * @return 公众号账号 + */ + default MpAccountDO getRequiredAccount(Long id) { + MpAccountDO account = getAccount(id); + if (account == null) { + throw exception(ACCOUNT_NOT_EXISTS); + } + return account; + } + + /** + * 从缓存中,获得公众号账号 + * + * @param appId 微信公众号 appId + * @return 公众号账号 + */ + MpAccountDO getAccountFromCache(String appId); + + /** + * 获得公众号账号分页 + * + * @param pageReqVO 分页查询 + * @return 公众号账号分页 + */ + PageResult getAccountPage(MpAccountPageReqVO pageReqVO); + + /** + * 获得公众号账号列表 + * + * @return 公众号账号列表 + */ + List getAccountList(); + + /** + * 生成公众号账号的二维码 + * + * @param id 编号 + */ + void generateAccountQrCode(Long id); + + /** + * 清空公众号账号的 API 配额 + * + * 参考文档:接口调用频次限制说明 + * + * @param id 编号 + */ + void clearAccountQuota(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java new file mode 100644 index 0000000..a8f9b78 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java @@ -0,0 +1,229 @@ +package cn.iocoder.yudao.module.mp.service.account; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountUpdateReqVO; +import cn.iocoder.yudao.module.mp.convert.account.MpAccountConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; +import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import com.google.common.annotations.VisibleForTesting; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS; + +/** + * 公众号账号 Service 实现类 + * + * @author fengdan + */ +@Slf4j +@Service +@Validated +public class MpAccountServiceImpl implements MpAccountService { + + /** + * 账号缓存 + * key:账号编号 {@link MpAccountDO#getAppId()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + @Getter + private volatile Map accountCache; + + @Resource + private MpAccountMapper mpAccountMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Override + @PostConstruct + public void initLocalCache() { + // 注意:忽略自动多租户,因为要全局初始化缓存 + TenantUtils.executeIgnore(() -> { + // 第一步:查询数据 + List accounts = Collections.emptyList(); + try { + accounts = mpAccountMapper.selectList(); + } catch (Throwable ex) { + if (!ex.getMessage().contains("doesn't exist")) { + throw ex; + } + log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]"); + } + log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size()); + + // 第二步:构建缓存。创建或更新支付 Client + mpServiceFactory.init(accounts); + accountCache = convertMap(accounts, MpAccountDO::getAppId); + }); + } + + /** + * 通过定时任务轮询,刷新缓存 + * + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 + */ + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) + public void refreshLocalCache() { + // 注意:忽略自动多租户,因为要全局初始化缓存 + TenantUtils.executeIgnore(() -> { + // 情况一:如果缓存里没有数据,则直接刷新缓存 + if (CollUtil.isEmpty(accountCache)) { + initLocalCache(); + return; + } + + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 + LocalDateTime maxTime = getMaxValue(accountCache.values(), MpAccountDO::getUpdateTime); + if (mpAccountMapper.selectCountByUpdateTimeGt(maxTime) > 0) { + initLocalCache(); + } + }); + } + + @Override + public Long createAccount(MpAccountCreateReqVO createReqVO) { + // 校验 appId 唯一 + validateAppIdUnique(null, createReqVO.getAppId()); + + // 插入 + MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO); + mpAccountMapper.insert(account); + + // 刷新缓存 + initLocalCache(); + return account.getId(); + } + + @Override + public void updateAccount(MpAccountUpdateReqVO updateReqVO) { + // 校验存在 + validateAccountExists(updateReqVO.getId()); + // 校验 appId 唯一 + validateAppIdUnique(updateReqVO.getId(), updateReqVO.getAppId()); + + // 更新 + MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); + mpAccountMapper.updateById(updateObj); + + // 刷新缓存 + initLocalCache(); + } + + @Override + public void deleteAccount(Long id) { + // 校验存在 + validateAccountExists(id); + // 删除 + mpAccountMapper.deleteById(id); + + // 刷新缓存 + initLocalCache(); + } + + private MpAccountDO validateAccountExists(Long id) { + MpAccountDO account = mpAccountMapper.selectById(id); + if (account == null) { + throw ServiceExceptionUtil.exception(ErrorCodeConstants.ACCOUNT_NOT_EXISTS); + } + return account; + } + + @VisibleForTesting + public void validateAppIdUnique(Long id, String appId) { + // 多个租户,appId 是不能重复,否则公众号回调会无法识别 + TenantUtils.executeIgnore(() -> { + MpAccountDO account = mpAccountMapper.selectByAppId(appId); + if (account == null) { + return; + } + // 存在 account 记录的情况下 + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, account.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(USER_USERNAME_EXISTS); + } + }); + } + + @Override + public MpAccountDO getAccount(Long id) { + return mpAccountMapper.selectById(id); + } + + @Override + public MpAccountDO getAccountFromCache(String appId) { + return accountCache.get(appId); + } + + @Override + public PageResult getAccountPage(MpAccountPageReqVO pageReqVO) { + return mpAccountMapper.selectPage(pageReqVO); + } + + @Override + public List getAccountList() { + return mpAccountMapper.selectList(); + } + + @Override + public void generateAccountQrCode(Long id) { + // 校验存在 + MpAccountDO account = validateAccountExists(id); + + // 生成二维码 + WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getAppId()); + String qrCodeUrl; + try { + WxMpQrCodeTicket qrCodeTicket = mpService.getQrcodeService().qrCodeCreateLastTicket("default"); + qrCodeUrl = mpService.getQrcodeService().qrCodePictureUrl(qrCodeTicket.getTicket()); + } catch (WxErrorException e) { + throw exception(ErrorCodeConstants.ACCOUNT_GENERATE_QR_CODE_FAIL, e.getError().getErrorMsg()); + } + + // 保存二维码 + mpAccountMapper.updateById(new MpAccountDO().setId(id).setQrCodeUrl(qrCodeUrl)); + } + + @Override + public void clearAccountQuota(Long id) { + // 校验存在 + MpAccountDO account = validateAccountExists(id); + + // 生成二维码 + WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getAppId()); + try { + mpService.clearQuota(account.getAppId()); + } catch (WxErrorException e) { + throw exception(ErrorCodeConstants.ACCOUNT_CLEAR_QUOTA_FAIL, e.getError().getErrorMsg()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/menu/MenuHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/menu/MenuHandler.java new file mode 100644 index 0000000..0397125 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/menu/MenuHandler.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mp.service.handler.menu; + +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.menu.MpMenuService; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMenuService; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType; + +/** + * 自定义菜单的事件处理器 + * + * 逻辑:粉丝点击菜单时,触发对应的回复 + * + * @author 芋道源码 + */ +@Component +public class MenuHandler implements WxMpMessageHandler { + + @Resource + private MpMenuService mpMenuService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService weixinService, WxSessionManager sessionManager) { + return mpMenuService.reply(MpContextHolder.getAppId(), wxMessage.getEventKey(), wxMessage.getFromUser()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageAutoReplyHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageAutoReplyHandler.java new file mode 100644 index 0000000..30d94a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageAutoReplyHandler.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.mp.service.handler.message; + +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 自动回复消息的事件处理器 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class MessageAutoReplyHandler implements WxMpMessageHandler { + + @Resource + private MpAutoReplyService mpAutoReplyService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService weixinService, WxSessionManager sessionManager) { + // 只处理指定类型的消息 + if (!MpAutoReplyDO.REQUEST_MESSAGE_TYPE.contains(wxMessage.getMsgType())) { + return null; + } + + // 自动回复 + return mpAutoReplyService.replyForMessage(MpContextHolder.getAppId(), wxMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageReceiveHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageReceiveHandler.java new file mode 100644 index 0000000..4e4a4eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message/MessageReceiveHandler.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.mp.service.handler.message; + +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.message.MpMessageService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 保存微信消息的事件处理器 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class MessageReceiveHandler implements WxMpMessageHandler { + + @Resource + private MpMessageService mpMessageService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + log.info("[handle][接收到请求消息,内容:{}]", wxMessage); + mpMessageService.receiveMessage(MpContextHolder.getAppId(), wxMessage); + return null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/KfSessionHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/KfSessionHandler.java new file mode 100644 index 0000000..fca7fab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/KfSessionHandler.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.mp.service.handler.other; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 接收客服会话管理的事件处理器 + * + * @author 芋道源码 + */ +@Component +public class KfSessionHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + throw new UnsupportedOperationException("未实现该处理,请自行重写"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/NullHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/NullHandler.java new file mode 100644 index 0000000..09b3efb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/NullHandler.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.service.handler.other; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 点击菜单连接的事件处理器 + */ +@Component +public class NullHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + throw new UnsupportedOperationException("未实现该处理,请自行重写"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/ScanHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/ScanHandler.java new file mode 100644 index 0000000..54a6bbc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/ScanHandler.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.mp.service.handler.other; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 扫码的事件处理器 + */ +@Component +public class ScanHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map context, + WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException { + throw new UnsupportedOperationException("未实现该处理,请自行重写"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/StoreCheckNotifyHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/StoreCheckNotifyHandler.java new file mode 100644 index 0000000..475b8ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/StoreCheckNotifyHandler.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mp.service.handler.other; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 门店审核事件的事件处理器 + */ +@Component +public class StoreCheckNotifyHandler implements WxMpMessageHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + throw new UnsupportedOperationException("未实现该处理,请自行重写"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/package-info.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/package-info.java new file mode 100644 index 0000000..7fd6622 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/other/package-info.java @@ -0,0 +1,4 @@ +/** + * 本包内的 handler 都是一些不重要的,所以放在 other 其它里 + */ +package cn.iocoder.yudao.module.mp.service.handler.other; diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/LocationHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/LocationHandler.java new file mode 100644 index 0000000..598ebb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/LocationHandler.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.mp.service.handler.user; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 上报地理位置的事件处理器 + * + * 触发操作:打开微信公众号 -> 点击 + 号 -> 选择「语音」 + * + * 逻辑:粉丝上传地理位置时,也可以触发自动回复 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class LocationHandler implements WxMpMessageHandler { + + @Resource + private MpAutoReplyService mpAutoReplyService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService, WxSessionManager sessionManager) { + // 防御性编程:必须是 LOCATION 消息 + if (ObjectUtil.notEqual(wxMessage.getMsgType(), WxConsts.XmlMsgType.LOCATION)) { + return null; + } + log.info("[handle][上报地理位置,纬度({})、经度({})、精度({})", wxMessage.getLatitude(), + wxMessage.getLongitude(), wxMessage.getPrecision()); + + // 自动回复 + return mpAutoReplyService.replyForMessage(MpContextHolder.getAppId(), wxMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java new file mode 100644 index 0000000..5f3c3ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.mp.service.handler.user; + +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService; +import cn.iocoder.yudao.module.mp.service.user.MpUserService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 关注的事件处理器 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class SubscribeHandler implements WxMpMessageHandler { + + @Resource + private MpUserService mpUserService; + @Resource + private MpAutoReplyService mpAutoReplyService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService weixinService, WxSessionManager sessionManager) throws WxErrorException { + // 第一步,从公众号平台,获取粉丝信息 + log.info("[handle][粉丝({}) 关注]", wxMessage.getFromUser()); + WxMpUser wxMpUser = null; + try { + wxMpUser = weixinService.getUserService().userInfo(wxMessage.getFromUser()); + } catch (WxErrorException e) { + log.error("[handle][粉丝({})] 获取粉丝信息失败!", wxMessage.getFromUser(), e); + } + + // 第二步,保存粉丝信息 + mpUserService.saveUser(MpContextHolder.getAppId(), wxMpUser); + + // 第三步,回复关注的欢迎语 + return mpAutoReplyService.replyForSubscribe(MpContextHolder.getAppId(), wxMessage); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/UnsubscribeHandler.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/UnsubscribeHandler.java new file mode 100644 index 0000000..3bf3635 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/UnsubscribeHandler.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.mp.service.handler.user; + +import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder; +import cn.iocoder.yudao.module.mp.service.user.MpUserService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 取消关注的事件处理器 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class UnsubscribeHandler implements WxMpMessageHandler { + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpUserService mpUserService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + log.info("[handle][粉丝({}) 取消关注]", wxMessage.getFromUser()); + mpUserService.updateUserUnsubscribe(MpContextHolder.getAppId(), wxMessage.getFromUser()); + return null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialService.java new file mode 100644 index 0000000..60e4c07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.mp.service.material; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadNewsImageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadPermanentReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadTemporaryReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import me.chanjar.weixin.common.api.WxConsts; + +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +/** + * 公众号素材 Service 接口 + * + * @author 芋道源码 + */ +public interface MpMaterialService { + + /** + * 获得素材的 URL + * + * 该 URL 来自我们自己的文件服务器存储的 URL,不是公众号存储的 URL + * + * @param accountId 公众号账号编号 + * @param mediaId 公众号素材 id + * @param type 文件类型 {@link WxConsts.MediaFileType} + * @return 素材的 URL + */ + String downloadMaterialUrl(Long accountId, String mediaId, String type); + + /** + * 上传临时素材 + * + * @param reqVO 请求 + * @return 素材 + * @throws IOException 文件操作发生异常 + */ + MpMaterialDO uploadTemporaryMaterial(@Valid MpMaterialUploadTemporaryReqVO reqVO) throws IOException; + + /** + * 上传永久素材 + * + * @param reqVO 请求 + * @return 素材 + * @throws IOException 文件操作发生异常 + */ + MpMaterialDO uploadPermanentMaterial(@Valid MpMaterialUploadPermanentReqVO reqVO) throws IOException; + + /** + * 上传图文内容中的图片 + * + * @param reqVO 上传请求 + * @return 图片地址 + */ + String uploadNewsImage(MpMaterialUploadNewsImageReqVO reqVO) throws IOException; + + /** + * 获得素材分页 + * + * @param pageReqVO 分页请求 + * @return 素材分页 + */ + PageResult getMaterialPage(MpMaterialPageReqVO pageReqVO); + + /** + * 获得素材列表 + * + * @param mediaIds 素材 mediaId 列表 + * @return 素材列表 + */ + List getMaterialListByMediaId(Collection mediaIds); + + /** + * 删除素材 + * + * @param id 编号 + */ + void deleteMaterial(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialServiceImpl.java new file mode 100644 index 0000000..9e48a8f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/material/MpMaterialServiceImpl.java @@ -0,0 +1,224 @@ +package cn.iocoder.yudao.module.mp.service.material; + +import cn.hutool.core.io.FileTypeUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadNewsImageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadPermanentReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.material.vo.MpMaterialUploadTemporaryReqVO; +import cn.iocoder.yudao.module.mp.convert.material.MpMaterialConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.material.MpMaterialDO; +import cn.iocoder.yudao.module.mp.dal.mysql.material.MpMaterialMapper; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +/** + * 公众号素材 Service 接口 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MpMaterialServiceImpl implements MpMaterialService { + + @Resource + private MpMaterialMapper mpMaterialMapper; + + @Resource + private FileApi fileApi; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpAccountService mpAccountService; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Override + public String downloadMaterialUrl(Long accountId, String mediaId, String type) { + // 第一步,直接从数据库查询。如果已经下载,直接返回 + MpMaterialDO material = mpMaterialMapper.selectByAccountIdAndMediaId(accountId, mediaId); + if (material != null) { + return material.getUrl(); + } + + // 第二步,尝试从临时素材中下载 + String url = downloadMedia(accountId, mediaId); + if (url == null) { + return null; + } + MpAccountDO account = mpAccountService.getRequiredAccount(accountId); + material = MpMaterialConvert.INSTANCE.convert(mediaId, type, url, account, null) + .setPermanent(false); + mpMaterialMapper.insert(material); + + // 不考虑下载永久素材,因为上传的时候已经保存 + return url; + } + + @Override + public MpMaterialDO uploadTemporaryMaterial(MpMaterialUploadTemporaryReqVO reqVO) throws IOException { + WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId()); + // 第一步,上传到公众号 + File file = null; + WxMediaUploadResult result; + String mediaId; + String url; + try { + // 写入到临时文件 + file = FileUtil.newFile(FileUtil.getTmpDirPath() + reqVO.getFile().getOriginalFilename()); + reqVO.getFile().transferTo(file); + // 上传到公众号 + result = mpService.getMaterialService().mediaUpload(reqVO.getType(), file); + // 上传到文件服务 + mediaId = ObjUtil.defaultIfNull(result.getMediaId(), result.getThumbMediaId()); + url = uploadFile(mediaId, file); + } catch (WxErrorException e) { + throw exception(MATERIAL_UPLOAD_FAIL, e.getError().getErrorMsg()); + } finally { + FileUtil.del(file); + } + + // 第二步,存储到数据库 + MpAccountDO account = mpAccountService.getRequiredAccount(reqVO.getAccountId()); + MpMaterialDO material = MpMaterialConvert.INSTANCE.convert(mediaId, reqVO.getType(), url, account, + reqVO.getFile().getName()).setPermanent(false); + mpMaterialMapper.insert(material); + return material; + } + + @Override + public MpMaterialDO uploadPermanentMaterial(MpMaterialUploadPermanentReqVO reqVO) throws IOException { + WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId()); + // 第一步,上传到公众号 + String name = StrUtil.blankToDefault(reqVO.getName(), reqVO.getFile().getName()); + File file = null; + WxMpMaterialUploadResult result; + String mediaId; + String url; + try { + // 写入到临时文件 + file = FileUtil.newFile(FileUtil.getTmpDirPath() + reqVO.getFile().getOriginalFilename()); + reqVO.getFile().transferTo(file); + // 上传到公众号 + result = mpService.getMaterialService().materialFileUpload(reqVO.getType(), + MpMaterialConvert.INSTANCE.convert(name, file, reqVO.getTitle(), reqVO.getIntroduction())); + // 上传到文件服务 + mediaId = ObjUtil.defaultIfNull(result.getMediaId(), result.getMediaId()); + url = uploadFile(mediaId, file); + } catch (WxErrorException e) { + throw exception(MATERIAL_UPLOAD_FAIL, e.getError().getErrorMsg()); + } finally { + FileUtil.del(file); + } + + // 第二步,存储到数据库 + MpAccountDO account = mpAccountService.getRequiredAccount(reqVO.getAccountId()); + MpMaterialDO material = MpMaterialConvert.INSTANCE.convert(mediaId, reqVO.getType(), url, account, + name, reqVO.getTitle(), reqVO.getIntroduction(), result.getUrl()).setPermanent(true); + mpMaterialMapper.insert(material); + return material; + } + + @Override + public String uploadNewsImage(MpMaterialUploadNewsImageReqVO reqVO) throws IOException { + WxMpService mpService = mpServiceFactory.getRequiredMpService(reqVO.getAccountId()); + File file = null; + try { + // 写入到临时文件 + file = FileUtil.newFile(FileUtil.getTmpDirPath() + reqVO.getFile().getOriginalFilename()); + reqVO.getFile().transferTo(file); + // 上传到公众号 + return mpService.getMaterialService().mediaImgUpload(file).getUrl(); + } catch (WxErrorException e) { + throw exception(MATERIAL_IMAGE_UPLOAD_FAIL, e.getError().getErrorMsg()); + } finally { + FileUtil.del(file); + } + } + + @Override + public PageResult getMaterialPage(MpMaterialPageReqVO pageReqVO) { + return mpMaterialMapper.selectPage(pageReqVO); + } + + @Override + public List getMaterialListByMediaId(Collection mediaIds) { + return mpMaterialMapper.selectListByMediaId(mediaIds); + } + + @Override + public void deleteMaterial(Long id) { + MpMaterialDO material = mpMaterialMapper.selectById(id); + if (material == null) { + throw exception(MATERIAL_NOT_EXISTS); + } + + // 第一步,从公众号删除 + if (material.getPermanent()) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(material.getAppId()); + try { + mpService.getMaterialService().materialDelete(material.getMediaId()); + } catch (WxErrorException e) { + throw exception(MATERIAL_DELETE_FAIL, e.getError().getErrorMsg()); + } + } + + // 第二步,从数据库中删除 + mpMaterialMapper.deleteById(id); + } + + /** + * 下载微信媒体文件的内容,并上传到文件服务 + * + * 为什么要下载?媒体文件在微信后台保存时间为 3 天,即 3 天后 media_id 失效。 + * + * @param accountId 公众号账号的编号 + * @param mediaId 媒体文件编号 + * @return 上传后的 URL + */ + public String downloadMedia(Long accountId, String mediaId) { + WxMpService mpService = mpServiceFactory.getMpService(accountId); + for (int i = 0; i < 3; i++) { + try { + // 第一步,从公众号下载媒体文件 + File file = mpService.getMaterialService().mediaDownload(mediaId); + // 第二步,上传到文件服务 + return uploadFile(mediaId, file); + } catch (WxErrorException e) { + log.error("[mediaDownload][media({}) 第 ({}) 次下载失败]", mediaId, i); + } + } + return null; + } + + private String uploadFile(String mediaId, File file) { + String path = mediaId + "." + FileTypeUtil.getType(file); + return fileApi.createFile(path, FileUtil.readBytes(file)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuService.java new file mode 100644 index 0000000..19f3b14 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuService.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.mp.service.menu; + +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +import javax.validation.Valid; +import java.util.List; + +/** + * 公众号菜单 Service 接口 + * + * @author 芋道源码 + */ +public interface MpMenuService { + + /** + * 保存公众号菜单 + * + * @param createReqVO 创建信息 + */ + void saveMenu(@Valid MpMenuSaveReqVO createReqVO); + + /** + * 删除公众号菜单 + * + * @param accountId 公众号账号的编号 + */ + void deleteMenuByAccountId(Long accountId); + + /** + * 粉丝点击菜单按钮时,回复对应的消息 + * + * @param appId 公众号 AppId + * @param key 菜单按钮的标识 + * @param openid 粉丝的 openid + * @return 消息 + */ + WxMpXmlOutMessage reply(String appId, String key, String openid); + + /** + * 获得公众号菜单列表 + * + * @param accountId 公众号账号的编号 + * @return 公众号菜单列表 + */ + List getMenuListByAccountId(Long accountId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuServiceImpl.java new file mode 100644 index 0000000..eb9ceba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/menu/MpMenuServiceImpl.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.mp.service.menu; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.mp.controller.admin.menu.vo.MpMenuSaveReqVO; +import cn.iocoder.yudao.module.mp.convert.menu.MpMenuConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.menu.MpMenuDO; +import cn.iocoder.yudao.module.mp.dal.mysql.menu.MpMenuMapper; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.message.MpMessageService; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_DELETE_FAIL; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MENU_SAVE_FAIL; + +/** + * 公众号菜单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MpMenuServiceImpl implements MpMenuService { + + @Resource + private MpMessageService mpMessageService; + @Resource + @Lazy // 延迟加载,避免循环引用报错 + private MpAccountService mpAccountService; + + @Resource + @Lazy // 延迟加载,避免循环引用报错 + private MpServiceFactory mpServiceFactory; + + @Resource + private Validator validator; + + @Resource + private MpMenuMapper mpMenuMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveMenu(MpMenuSaveReqVO createReqVO) { + MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId()); + WxMpService mpService = mpServiceFactory.getRequiredMpService(createReqVO.getAccountId()); + + // 参数校验 + createReqVO.getMenus().forEach(this::validateMenu); + + // 第一步,同步公众号 + WxMenu wxMenu = new WxMenu(); + wxMenu.setButtons(MpMenuConvert.INSTANCE.convert(createReqVO.getMenus())); + try { + mpService.getMenuService().menuCreate(wxMenu); + } catch (WxErrorException e) { + throw exception(MENU_SAVE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,存储到数据库 + mpMenuMapper.deleteByAccountId(createReqVO.getAccountId()); + createReqVO.getMenus().forEach(menu -> { + // 先保存顶级菜单 + MpMenuDO menuDO = createMenu(menu, null, account); + // 再保存子菜单 + if (CollUtil.isEmpty(menu.getChildren())) { + return; + } + menu.getChildren().forEach(childMenu -> createMenu(childMenu, menuDO, account)); + }); + } + + /** + * 校验菜单的格式是否正确 + * + * @param menu 菜单 + */ + private void validateMenu(MpMenuSaveReqVO.Menu menu) { + MpUtils.validateButton(validator, menu.getType(), menu.getReplyMessageType(), menu); + // 子菜单 + if (CollUtil.isEmpty(menu.getChildren())) { + return; + } + menu.getChildren().forEach(this::validateMenu); + } + + /** + * 创建菜单,并存储到数据库 + * + * @param wxMenu 菜单信息 + * @param parentMenu 父菜单 + * @param account 公众号账号 + * @return 创建后的菜单 + */ + private MpMenuDO createMenu(MpMenuSaveReqVO.Menu wxMenu, MpMenuDO parentMenu, MpAccountDO account) { + // 创建菜单 + MpMenuDO menu = CollUtil.isNotEmpty(wxMenu.getChildren()) + ? new MpMenuDO().setName(wxMenu.getName()) + : MpMenuConvert.INSTANCE.convert02(wxMenu); + // 设置菜单的公众号账号信息 + if (account != null) { + menu.setAccountId(account.getId()).setAppId(account.getAppId()); + } + // 设置父编号 + if (parentMenu != null) { + menu.setParentId(parentMenu.getId()); + } else { + menu.setParentId(MpMenuDO.ID_ROOT); + } + + // 插入到数据库 + mpMenuMapper.insert(menu); + return menu; + } + + @Override + public void deleteMenuByAccountId(Long accountId) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + // 第一步,同步公众号 + try { + mpService.getMenuService().menuDelete(); + } catch (WxErrorException e) { + throw exception(MENU_DELETE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,存储到数据库 + mpMenuMapper.deleteByAccountId(accountId); + } + + @Override + public WxMpXmlOutMessage reply(String appId, String key, String openid) { + // 第一步,获得菜单 + MpMenuDO menu = mpMenuMapper.selectByAppIdAndMenuKey(appId, key); + if (menu == null) { + log.error("[reply][appId({}) key({}) 找不到对应的菜单]", appId, key); + return null; + } + // 按钮必须要有消息类型,不然后续无法回复消息 + if (StrUtil.isEmpty(menu.getReplyMessageType())) { + log.error("[reply][menu({}) 不存在对应的消息类型]", menu); + return null; + } + + // 第二步,回复消息 + MpMessageSendOutReqBO sendReqBO = MpMenuConvert.INSTANCE.convert(openid, menu); + return mpMessageService.sendOutMessage(sendReqBO); + } + + @Override + public List getMenuListByAccountId(Long accountId) { + return mpMenuMapper.selectListByAccountId(accountId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java new file mode 100644 index 0000000..fc125d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.mp.service.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +/** + * 公众号的自动回复 Service 接口 + * + * @author 芋道源码 + */ +public interface MpAutoReplyService { + + /** + * 获得公众号自动回复分页 + * + * @param pageVO 分页请求 + * @return 自动回复分页结果 + */ + PageResult getAutoReplyPage(MpMessagePageReqVO pageVO); + + /** + * 获得公众号自动回复 + * + * @param id 编号 + * @return 自动回复 + */ + MpAutoReplyDO getAutoReply(Long id); + + + /** + * 创建公众号自动回复 + * + * @param createReqVO 创建请求 + * @return 自动回复的编号 + */ + Long createAutoReply(MpAutoReplyCreateReqVO createReqVO); + + /** + * 更新公众号自动回复 + * + * @param updateReqVO 更新请求 + */ + void updateAutoReply(MpAutoReplyUpdateReqVO updateReqVO); + + /** + * 删除公众号自动回复 + * + * @param id 自动回复的编号 + */ + void deleteAutoReply(Long id); + + /** + * 当收到消息时,自动回复 + * + * @param appId 微信公众号 appId + * @param wxMessage 消息 + * @return 回复的消息 + */ + WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage); + + /** + * 当粉丝关注时,自动回复 + * + * @param appId 微信公众号 appId + * @param wxMessage 消息 + * @return 回复的消息 + */ + WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java new file mode 100644 index 0000000..b90b82e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java @@ -0,0 +1,202 @@ +package cn.iocoder.yudao.module.mp.service.message; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.convert.message.MpAutoReplyConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; +import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper; +import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +/** + * 公众号的自动回复 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MpAutoReplyServiceImpl implements MpAutoReplyService { + + @Resource + private MpMessageService mpMessageService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private MpAccountService mpAccountService; + + @Resource + private Validator validator; + + @Resource + private MpAutoReplyMapper mpAutoReplyMapper; + + @Override + public PageResult getAutoReplyPage(MpMessagePageReqVO pageVO) { + return mpAutoReplyMapper.selectPage(pageVO); + } + + @Override + public MpAutoReplyDO getAutoReply(Long id) { + return mpAutoReplyMapper.selectById(id); + } + + @Override + public Long createAutoReply(MpAutoReplyCreateReqVO createReqVO) { + // 第一步,校验数据 + if (createReqVO.getResponseMessageType() != null) { + MpUtils.validateMessage(validator, createReqVO.getResponseMessageType(), createReqVO); + } + validateAutoReplyConflict(null, createReqVO.getAccountId(), createReqVO.getType(), + createReqVO.getRequestKeyword(), createReqVO.getRequestMessageType()); + + // 第二步,插入数据 + MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId()); + MpAutoReplyDO autoReply = MpAutoReplyConvert.INSTANCE.convert(createReqVO) + .setAppId(account.getAppId()); + mpAutoReplyMapper.insert(autoReply); + return autoReply.getId(); + } + + @Override + public void updateAutoReply(MpAutoReplyUpdateReqVO updateReqVO) { + // 第一步,校验数据 + if (updateReqVO.getResponseMessageType() != null) { + MpUtils.validateMessage(validator, updateReqVO.getResponseMessageType(), updateReqVO); + } + MpAutoReplyDO autoReply = validateAutoReplyExists(updateReqVO.getId()); + validateAutoReplyConflict(updateReqVO.getId(), autoReply.getAccountId(), updateReqVO.getType(), + updateReqVO.getRequestKeyword(), updateReqVO.getRequestMessageType()); + + // 第二步,更新数据 + MpAutoReplyDO updateObj = MpAutoReplyConvert.INSTANCE.convert(updateReqVO) + .setAccountId(null).setAppId(null); // 避免前端传递,更新着两个字段 + mpAutoReplyMapper.updateById(updateObj); + } + + /** + * 校验自动回复是否冲突 + * + * 不同的 type,会有不同的逻辑: + * 1. type = SUBSCRIBE 时,不允许有其他的自动回复 + * 2. type = MESSAGE 时,校验 requestMessageType 已经存在自动回复 + * 3. type = KEYWORD 时,校验 keyword 已经存在自动回复 + * + * @param id 自动回复编号 + * @param accountId 公众号账号的编号 + * @param type 类型 + * @param requestKeyword 请求关键词 + * @param requestMessageType 请求消息类型 + */ + private void validateAutoReplyConflict(Long id, Long accountId, Integer type, + String requestKeyword, String requestMessageType) { + // 获得已经存在的自动回复 + MpAutoReplyDO autoReply = null; + ErrorCode errorCode = null; + if (MpAutoReplyTypeEnum.SUBSCRIBE.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndSubscribe(accountId); + errorCode = AUTO_REPLY_ADD_SUBSCRIBE_FAIL_EXISTS; + } else if (MpAutoReplyTypeEnum.MESSAGE.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndMessage(accountId, requestMessageType); + errorCode = AUTO_REPLY_ADD_MESSAGE_FAIL_EXISTS; + } else if (MpAutoReplyTypeEnum.KEYWORD.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndKeyword(accountId, requestKeyword); + errorCode = AUTO_REPLY_ADD_KEYWORD_FAIL_EXISTS; + } + if (autoReply == null) { + return; + } + + // 存在冲突,抛出业务异常 + if (id == null // 情况一,新增(id == null),存在记录,说明冲突 + || ObjUtil.notEqual(id, autoReply.getId())) { // 情况二,修改(id != null),id 不匹配,说明冲突 + throw exception(errorCode); + } + } + + @Override + public void deleteAutoReply(Long id) { + // 校验粉丝存在 + validateAutoReplyExists(id); + + // 删除自动回复 + mpAutoReplyMapper.deleteById(id); + } + + private MpAutoReplyDO validateAutoReplyExists(Long id) { + MpAutoReplyDO autoReply = mpAutoReplyMapper.selectById(id); + if (autoReply == null) { + throw exception(AUTO_REPLY_NOT_EXISTS); + } + return autoReply; + } + + @Override + public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) { + // 第一步,匹配自动回复 + List replies = null; + // 1.1 关键字 + if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.TEXT)) { + // 完全匹配 + replies = mpAutoReplyMapper.selectListByAppIdAndKeywordAll(appId, wxMessage.getContent()); + if (CollUtil.isEmpty(replies)) { + // 模糊匹配 + replies = mpAutoReplyMapper.selectListByAppIdAndKeywordLike(appId, wxMessage.getContent()); + } + } + // 1.2 消息类型 + if (CollUtil.isEmpty(replies)) { + replies = mpAutoReplyMapper.selectListByAppIdAndMessage(appId, wxMessage.getMsgType()); + } + if (CollUtil.isEmpty(replies)) { + return null; + } + MpAutoReplyDO reply = CollUtil.getFirst(replies); + + // 第二步,基于自动回复,创建消息 + MpMessageSendOutReqBO sendReqBO = MpAutoReplyConvert.INSTANCE.convert(wxMessage.getFromUser(), reply); + return mpMessageService.sendOutMessage(sendReqBO); + } + + @Override + public WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage) { + // 第一步,匹配自动回复 + List replies = mpAutoReplyMapper.selectListByAppIdAndSubscribe(appId); + MpAutoReplyDO reply = CollUtil.isNotEmpty(replies) ? CollUtil.getFirst(replies) + : buildDefaultSubscribeAutoReply(appId); // 如果不存在,提供一个默认末班 + + // 第二步,基于自动回复,创建消息 + MpMessageSendOutReqBO sendReqBO = MpAutoReplyConvert.INSTANCE.convert(wxMessage.getFromUser(), reply); + return mpMessageService.sendOutMessage(sendReqBO); + } + + private MpAutoReplyDO buildDefaultSubscribeAutoReply(String appId) { + MpAccountDO account = mpAccountService.getAccountFromCache(appId); + Assert.notNull(account, "公众号账号({}) 不存在", appId); + // 构建默认的【关注】自动回复 + return new MpAutoReplyDO().setAppId(appId).setAccountId(account.getId()) + .setType(MpAutoReplyTypeEnum.SUBSCRIBE.getType()) + .setResponseMessageType(WxConsts.XmlMsgType.TEXT).setResponseContent("感谢关注"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageService.java new file mode 100644 index 0000000..01c691a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageService.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.mp.service.message; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +import javax.validation.Valid; + +/** + * 公众号消息 Service 接口 + * + * @author 芋道源码 + */ +public interface MpMessageService { + + /** + * 获得公众号消息分页 + * + * @param pageReqVO 分页查询 + * @return 公众号消息分页 + */ + PageResult getMessagePage(MpMessagePageReqVO pageReqVO); + + /** + * 从公众号,接收到粉丝消息 + * + * @param appId 微信公众号 appId + * @param wxMessage 消息 + */ + void receiveMessage(String appId, WxMpXmlMessage wxMessage); + + /** + * 使用公众号,给粉丝回复消息 + * + * 例如说:自动回复、客服消息、菜单回复消息等场景 + * + * 注意,该方法只是返回 WxMpXmlOutMessage 对象,不会真的发送消息 + * + * @param sendReqBO 消息内容 + * @return 微信回复消息 XML + */ + WxMpXmlOutMessage sendOutMessage(@Valid MpMessageSendOutReqBO sendReqBO); + + /** + * 使用公众号,给粉丝发送【客服】消息 + * + * 注意,该方法会真实发送消息 + * + * @param sendReqVO 消息内容 + * @return 消息 + */ + MpMessageDO sendKefuMessage(MpMessageSendReqVO sendReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java new file mode 100644 index 0000000..07553c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageServiceImpl.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.module.mp.service.message; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessageSendReqVO; +import cn.iocoder.yudao.module.mp.convert.message.MpMessageConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.dal.mysql.message.MpMessageMapper; +import cn.iocoder.yudao.module.mp.enums.message.MpMessageSendFromEnum; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.material.MpMaterialService; +import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; +import cn.iocoder.yudao.module.mp.service.user.MpUserService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Validator; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MESSAGE_SEND_FAIL; + +/** + * 粉丝消息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MpMessageServiceImpl implements MpMessageService { + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private MpAccountService mpAccountService; + @Resource + private MpUserService mpUserService; + @Resource + private MpMaterialService mpMaterialService; + + @Resource + private MpMessageMapper mpMessageMapper; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Resource + private Validator validator; + + @Override + public PageResult getMessagePage(MpMessagePageReqVO pageReqVO) { + return mpMessageMapper.selectPage(pageReqVO); + } + + @Override + public void receiveMessage(String appId, WxMpXmlMessage wxMessage) { + // 获得关联信息 + MpAccountDO account = mpAccountService.getAccountFromCache(appId); + Assert.notNull(account, "公众号账号({}) 不存在", appId); + + // 订阅事件不记录,因为此时公众号粉丝表中还没有此粉丝的数据 + // TODO @芋艿:这个修复,后续看看还有啥问题 + if (ObjUtil.equal(wxMessage.getEvent(), WxConsts.EventType.SUBSCRIBE)) { + return; + } + + MpUserDO user = mpUserService.getUser(appId, wxMessage.getFromUser()); + Assert.notNull(user, "公众号粉丝({}/{}) 不存在", appId, wxMessage.getFromUser()); + + // 记录消息 + MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user) + .setSendFrom(MpMessageSendFromEnum.USER_TO_MP.getFrom()); + downloadMessageMedia(message); + mpMessageMapper.insert(message); + } + + @Override + public WxMpXmlOutMessage sendOutMessage(MpMessageSendOutReqBO sendReqBO) { + // 校验消息格式 + MpUtils.validateMessage(validator, sendReqBO.getType(), sendReqBO); + + // 获得关联信息 + MpAccountDO account = mpAccountService.getAccountFromCache(sendReqBO.getAppId()); + Assert.notNull(account, "公众号账号({}) 不存在", sendReqBO.getAppId()); + MpUserDO user = mpUserService.getUser(sendReqBO.getAppId(), sendReqBO.getOpenid()); + Assert.notNull(user, "公众号粉丝({}/{}) 不存在", sendReqBO.getAppId(), sendReqBO.getOpenid()); + + // 记录消息 + MpMessageDO message = MpMessageConvert.INSTANCE.convert(sendReqBO, account, user). + setSendFrom(MpMessageSendFromEnum.MP_TO_USER.getFrom()); + downloadMessageMedia(message); + mpMessageMapper.insert(message); + + // 转换返回 WxMpXmlOutMessage 对象 + return MpMessageConvert.INSTANCE.convert02(message, account); + } + + @Override + public MpMessageDO sendKefuMessage(MpMessageSendReqVO sendReqVO) { + // 校验消息格式 + MpUtils.validateMessage(validator, sendReqVO.getType(), sendReqVO); + + // 获得关联信息 + MpUserDO user = mpUserService.getRequiredUser(sendReqVO.getUserId()); + MpAccountDO account = mpAccountService.getRequiredAccount(user.getAccountId()); + + // 发送客服消息 + WxMpKefuMessage wxMessage = MpMessageConvert.INSTANCE.convert(sendReqVO, user); + WxMpService mpService = mpServiceFactory.getRequiredMpService(user.getAppId()); + try { + mpService.getKefuService().sendKefuMessageWithResponse(wxMessage); + } catch (WxErrorException e) { + throw exception(MESSAGE_SEND_FAIL, e.getError().getErrorMsg()); + } + + // 记录消息 + MpMessageDO message = MpMessageConvert.INSTANCE.convert(wxMessage, account, user) + .setSendFrom(MpMessageSendFromEnum.MP_TO_USER.getFrom()); + downloadMessageMedia(message); + mpMessageMapper.insert(message); + return message; + } + + /** + * 下载消息使用到的媒体文件,并上传到文件服务 + * + * @param message 消息 + */ + private void downloadMessageMedia(MpMessageDO message) { + if (StrUtil.isNotEmpty(message.getMediaId())) { + message.setMediaUrl(mpMaterialService.downloadMaterialUrl(message.getAccountId(), + message.getMediaId(), MpUtils.getMediaFileType(message.getType()))); + } + if (StrUtil.isNotEmpty(message.getThumbMediaId())) { + message.setThumbMediaUrl(mpMaterialService.downloadMaterialUrl(message.getAccountId(), + message.getThumbMediaId(), WxConsts.MediaFileType.THUMB)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/bo/MpMessageSendOutReqBO.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/bo/MpMessageSendOutReqBO.java new file mode 100644 index 0000000..9da7090 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/bo/MpMessageSendOutReqBO.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.mp.service.message.bo; + +import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageDO; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils.*; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; +import org.hibernate.validator.constraints.URL; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 公众号消息发送 Request BO + * + * 为什么要有该 BO 呢?在自动回复、客服消息、菜单回复消息等场景,都涉及到 MP 给粉丝发送消息,所以使用该 BO 统一承接 + * + * @author 芋道源码 + */ +@Data +public class MpMessageSendOutReqBO { + + /** + * 公众号 appId + */ + @NotEmpty(message = "公众号 appId 不能为空") + private String appId; + /** + * 公众号粉丝 openid + */ + @NotEmpty(message = "公众号粉丝 openid 不能为空") + private String openid; + + // ========== 消息内容 ========== + /** + * 消息类型 + * + * 枚举 {@link WxConsts.XmlMsgType} 中的 TEXT、IMAGE、VOICE、VIDEO、NEWS、MUSIC + */ + @NotEmpty(message = "消息类型不能为空") + public String type; + + /** + * 消息内容 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 TEXT + */ + @NotEmpty(message = "消息内容不能为空", groups = TextMessageGroup.class) + private String content; + + /** + * 媒体 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 IMAGE、VOICE、VIDEO + */ + @NotEmpty(message = "消息 mediaId 不能为空", groups = {ImageMessageGroup.class, VoiceMessageGroup.class, VideoMessageGroup.class}) + private String mediaId; + + /** + * 缩略图的媒体 id + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO、MUSIC + */ + @NotEmpty(message = "消息 thumbMediaId 不能为空", groups = {MusicMessageGroup.class}) + private String thumbMediaId; + + /** + * 标题 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + @NotEmpty(message = "消息标题不能为空", groups = VideoMessageGroup.class) + private String title; + /** + * 描述 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 VIDEO + */ + @NotEmpty(message = "消息描述不能为空", groups = VideoMessageGroup.class) + private String description; + + /** + * 图文消息 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 NEWS + */ + @Valid + @NotNull(message = "图文消息不能为空", groups = NewsMessageGroup.class) + private List articles; + + /** + * 音乐链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + @NotEmpty(message = "音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String musicUrl; + + /** + * 高质量音乐链接 + * + * 消息类型为 {@link WxConsts.XmlMsgType} 的 MUSIC + */ + @NotEmpty(message = "高质量音乐链接不能为空", groups = MusicMessageGroup.class) + @URL(message = "高质量音乐链接格式不正确", groups = MusicMessageGroup.class) + private String hqMusicUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsService.java new file mode 100644 index 0000000..08e5c35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.mp.service.statistics; + +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 公众号统计 Service 接口 + * + * @author 芋道源码 + */ +public interface MpStatisticsService { + + /** + * 获取粉丝增减数据 + * + * @param accountId 公众号账号编号 + * @param date 时间区间 + * @return 粉丝增减数据 + */ + List getUserSummary(Long accountId, LocalDateTime[] date); + + /** + * 获取粉丝累计数据 + * + * @param accountId 公众号账号编号 + * @param date 时间区间 + * @return 粉丝累计数据 + */ + List getUserCumulate(Long accountId, LocalDateTime[] date); + + /** + * 获取消息发送概况数据 + * + * @param accountId 公众号账号编号 + * @param date 时间区间 + * @return 消息发送概况数据 + */ + List getUpstreamMessage(Long accountId, LocalDateTime[] date); + + /** + * 获取接口分析数据 + * + * @param accountId 公众号账号编号 + * @param date 时间区间 + * @return 接口分析数据 + */ + List getInterfaceSummary(Long accountId, LocalDateTime[] date); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsServiceImpl.java new file mode 100644 index 0000000..4c3b374 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsServiceImpl.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.mp.service.statistics; + +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +/** + * 公众号统计 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class MpStatisticsServiceImpl implements MpStatisticsService { + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Override + public List getUserSummary(Long accountId, LocalDateTime[] date) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + return mpService.getDataCubeService().getUserSummary( + DateUtil.date(date[0]), DateUtil.date(date[1])); + } catch (WxErrorException e) { + throw exception(STATISTICS_GET_USER_SUMMARY_FAIL, e.getError().getErrorMsg()); + } + } + + @Override + public List getUserCumulate(Long accountId, LocalDateTime[] date) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + return mpService.getDataCubeService().getUserCumulate( + DateUtil.date(date[0]), DateUtil.date(date[1])); + } catch (WxErrorException e) { + throw exception(STATISTICS_GET_USER_CUMULATE_FAIL, e.getError().getErrorMsg()); + } + } + + @Override + public List getUpstreamMessage(Long accountId, LocalDateTime[] date) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + return mpService.getDataCubeService().getUpstreamMsg( + DateUtil.date(date[0]), DateUtil.date(date[1])); + } catch (WxErrorException e) { + throw exception(STATISTICS_GET_UPSTREAM_MESSAGE_FAIL, e.getError().getErrorMsg()); + } + } + + @Override + public List getInterfaceSummary(Long accountId, LocalDateTime[] date) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + try { + return mpService.getDataCubeService().getInterfaceSummary( + DateUtil.date(date[0]), DateUtil.date(date[1])); + } catch (WxErrorException e) { + throw exception(STATISTICS_GET_INTERFACE_SUMMARY_FAIL, e.getError().getErrorMsg()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagService.java new file mode 100644 index 0000000..77dbf33 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagService.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.mp.service.tag; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 公众号标签 Service 接口 + * + * @author fengdan + */ +public interface MpTagService { + + /** + * 创建公众号标签 + * + * @param createReqVO 创建标签信息 + * @return 标签编号 + */ + Long createTag(@Valid MpTagCreateReqVO createReqVO); + + /** + * 更新公众号标签 + * + * @param updateReqVO 更新标签信息 + */ + void updateTag(@Valid MpTagUpdateReqVO updateReqVO); + + /** + * 删除公众号标签 + * + * @param id 编号 + */ + void deleteTag(Long id); + + /** + * 获得公众号标签分页 + * + * @param pageReqVO 分页查询 + * @return 公众号标签分页 + */ + PageResult getTagPage(MpTagPageReqVO pageReqVO); + + /** + * 获得公众号标签详情 + * @param id id查询 + * @return 公众号标签详情 + */ + MpTagDO get(Long id); + + List getTagList(); + + /** + * 同步公众号标签 + * + * @param accountId 公众号账号的编号 + */ + void syncTag(Long accountId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagServiceImpl.java new file mode 100644 index 0000000..a4fa509 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/tag/MpTagServiceImpl.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.mp.service.tag; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.tag.vo.MpTagUpdateReqVO; +import cn.iocoder.yudao.module.mp.convert.tag.MpTagConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.tag.MpTagDO; +import cn.iocoder.yudao.module.mp.dal.mysql.tag.MpTagMapper; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.tag.WxUserTag; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +/** + * 公众号标签 Service 实现类 + * + * @author fengdan + */ +@Slf4j +@Service +@Validated +public class MpTagServiceImpl implements MpTagService { + + @Resource + private MpTagMapper mpTagMapper; + + @Resource + private MpAccountService mpAccountService; + + @Resource + @Lazy // 延迟加载,为了解决延迟加载 + private MpServiceFactory mpServiceFactory; + + @Override + public Long createTag(MpTagCreateReqVO createReqVO) { + // 获得公众号账号 + MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId()); + + // 第一步,新增标签到公众号平台。标签名的唯一,交给公众号平台 + WxMpService mpService = mpServiceFactory.getRequiredMpService(createReqVO.getAccountId()); + WxUserTag wxTag; + try { + wxTag = mpService.getUserTagService().tagCreate(createReqVO.getName()); + } catch (WxErrorException e) { + throw exception(TAG_CREATE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,新增标签到数据库 + MpTagDO tag = MpTagConvert.INSTANCE.convert(wxTag, account); + mpTagMapper.insert(tag); + return tag.getId(); + } + + @Override + public void updateTag(MpTagUpdateReqVO updateReqVO) { + // 校验标签存在 + MpTagDO tag = validateTagExists(updateReqVO.getId()); + + // 第一步,更新标签到公众号平台。标签名的唯一,交给公众号平台 + WxMpService mpService = mpServiceFactory.getRequiredMpService(tag.getAccountId()); + try { + mpService.getUserTagService().tagUpdate(tag.getTagId(), updateReqVO.getName()); + } catch (WxErrorException e) { + throw exception(TAG_UPDATE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,更新标签到数据库 + mpTagMapper.updateById(new MpTagDO().setId(tag.getId()).setName(updateReqVO.getName())); + } + + @Override + public void deleteTag(Long id) { + // 校验标签存在 + MpTagDO tag = validateTagExists(id); + + // 第一步,删除标签到公众号平台。 + WxMpService mpService = mpServiceFactory.getRequiredMpService(tag.getAccountId()); + try { + mpService.getUserTagService().tagDelete(tag.getTagId()); + } catch (WxErrorException e) { + throw exception(TAG_DELETE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,删除标签到数据库 + mpTagMapper.deleteById(tag.getId()); + } + + private MpTagDO validateTagExists(Long id) { + MpTagDO tag = mpTagMapper.selectById(id); + if (tag == null) { + throw exception(TAG_NOT_EXISTS); + } + return tag; + } + + @Override + public PageResult getTagPage(MpTagPageReqVO pageReqVO) { + return mpTagMapper.selectPage(pageReqVO); + } + + @Override + public MpTagDO get(Long id) { + return mpTagMapper.selectById(id); + } + + @Override + public List getTagList() { + return mpTagMapper.selectList(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncTag(Long accountId) { + MpAccountDO account = mpAccountService.getRequiredAccount(accountId); + + // 第一步,从公众号平台获取最新的标签列表 + WxMpService mpService = mpServiceFactory.getRequiredMpService(accountId); + List wxTags; + try { + wxTags = mpService.getUserTagService().tagGet(); + } catch (WxErrorException e) { + throw exception(TAG_GET_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,合并更新回自己的数据库;由于标签只有 100 个,所以直接 for 循环操作 + Map tagMap = convertMap(mpTagMapper.selectListByAccountId(accountId), + MpTagDO::getTagId); + wxTags.forEach(wxTag -> { + MpTagDO tag = tagMap.remove(wxTag.getId()); + // 情况一,不存在,新增 + if (tag == null) { + tag = MpTagConvert.INSTANCE.convert(wxTag, account); + mpTagMapper.insert(tag); + return; + } + // 情况二,存在,则更新 + mpTagMapper.updateById(new MpTagDO().setId(tag.getId()) + .setName(wxTag.getName()).setCount(wxTag.getCount())); + }); + // 情况三,部分标签已经不存在了,删除 + if (CollUtil.isNotEmpty(tagMap)) { + mpTagMapper.deleteBatchIds(convertList(tagMap.values(), MpTagDO::getId)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserService.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserService.java new file mode 100644 index 0000000..bdefc0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.mp.service.user; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserUpdateReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import me.chanjar.weixin.mp.bean.result.WxMpUser; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.USER_NOT_EXISTS; + +/** + * 公众号粉丝 Service 接口 + * + * @author 芋道源码 + */ +public interface MpUserService { + + /** + * 获得公众号粉丝 + * + * @param id 编号 + * @return 公众号粉丝 + */ + MpUserDO getUser(Long id); + + /** + * 使用 appId + openId,获得公众号粉丝 + * + * @param appId 公众号 appId + * @param openId 公众号 openId + * @return 公众号粉丝 + */ + MpUserDO getUser(String appId, String openId); + + /** + * 获得公众号粉丝 + * + * @param id 编号 + * @return 公众号粉丝 + */ + default MpUserDO getRequiredUser(Long id) { + MpUserDO user = getUser(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + + /** + * 获得公众号粉丝列表 + * + * @param ids 编号 + * @return 公众号粉丝列表 + */ + List getUserList(Collection ids); + + /** + * 获得公众号粉丝分页 + * + * @param pageReqVO 分页查询 + * @return 公众号粉丝分页 + */ + PageResult getUserPage(MpUserPageReqVO pageReqVO); + + /** + * 保存公众号粉丝 + * + * 新增或更新,根据是否存在数据库中 + * + * @param appId 公众号 appId + * @param wxMpUser 公众号粉丝的信息 + * @return 公众号粉丝 + */ + MpUserDO saveUser(String appId, WxMpUser wxMpUser); + + /** + * 同步一个公众号粉丝 + * + * @param accountId 公众号账号的编号 + */ + void syncUser(Long accountId); + + /** + * 更新公众号粉丝,取消关注 + * + * @param appId 公众号 appId + * @param openId 公众号粉丝的 openid + */ + void updateUserUnsubscribe(String appId, String openId); + + /** + * 更新公众号粉丝 + * + * @param updateReqVO 更新信息 + */ + void updateUser(MpUserUpdateReqVO updateReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserServiceImpl.java new file mode 100644 index 0000000..0cef919 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/user/MpUserServiceImpl.java @@ -0,0 +1,215 @@ +package cn.iocoder.yudao.module.mp.service.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserUpdateReqVO; +import cn.iocoder.yudao.module.mp.convert.user.MpUserConvert; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.dal.mysql.user.MpUserMapper; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.USER_NOT_EXISTS; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.USER_UPDATE_TAG_FAIL; + +/** + * 微信公众号粉丝 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MpUserServiceImpl implements MpUserService { + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpAccountService mpAccountService; + + @Resource + @Lazy // 延迟加载,解决循环依赖的问题 + private MpServiceFactory mpServiceFactory; + + @Resource + private MpUserMapper mpUserMapper; + + @Override + public MpUserDO getUser(Long id) { + return mpUserMapper.selectById(id); + } + + @Override + public MpUserDO getUser(String appId, String openId) { + return mpUserMapper.selectByAppIdAndOpenid(appId, openId); + } + + @Override + public List getUserList(Collection ids) { + return mpUserMapper.selectBatchIds(ids); + } + + @Override + public PageResult getUserPage(MpUserPageReqVO pageReqVO) { + return mpUserMapper.selectPage(pageReqVO); + } + + @Override + public MpUserDO saveUser(String appId, WxMpUser wxMpUser) { + // 构建保存的 MpUserDO 对象 + MpAccountDO account = mpAccountService.getAccountFromCache(appId); + MpUserDO user = MpUserConvert.INSTANCE.convert(account, wxMpUser); + + // 根据情况,插入或更新 + MpUserDO dbUser = mpUserMapper.selectByAppIdAndOpenid(appId, wxMpUser.getOpenId()); + if (dbUser == null) { + mpUserMapper.insert(user); + } else { + user.setId(dbUser.getId()); + mpUserMapper.updateById(user); + } + return user; + } + + @Override + @Async + public void syncUser(Long accountId) { + MpAccountDO account = mpAccountService.getRequiredAccount(accountId); + // for 循环,避免递归出意外问题,导致死循环 + String nextOpenid = null; + for (int i = 0; i < Short.MAX_VALUE; i++) { + log.info("[syncUser][第({}) 次加载公众号粉丝列表,nextOpenid({})]", i, nextOpenid); + try { + nextOpenid = syncUser0(account, nextOpenid); + } catch (WxErrorException e) { + log.error("[syncUser][第({}) 次同步粉丝异常]", i, e); + break; + } + // 如果 nextOpenid 为空,表示已经同步完毕 + if (StrUtil.isEmpty(nextOpenid)) { + break; + } + } + } + + private String syncUser0(MpAccountDO account, String nextOpenid) throws WxErrorException { + // 第一步,从公众号流式加载粉丝 + WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getId()); + WxMpUserList wxUserList = mpService.getUserService().userList(nextOpenid); + if (CollUtil.isEmpty(wxUserList.getOpenids())) { + return null; + } + + // 第二步,分批加载粉丝信息 + List> openidsList = CollUtil.split(wxUserList.getOpenids(), 100); + for (List openids : openidsList) { + log.info("[syncUser][批量加载粉丝信息,openids({})]", openids); + List wxUsers = mpService.getUserService().userInfoList(openids); + batchSaveUser(account, wxUsers); + } + + // 返回下一次的 nextOpenId + return wxUserList.getNextOpenid(); + } + + private void batchSaveUser(MpAccountDO account, List wxUsers) { + if (CollUtil.isEmpty(wxUsers)) { + return; + } + // 1. 获得数据库已保存的粉丝列表 + List dbUsers = mpUserMapper.selectListByAppIdAndOpenid(account.getAppId(), + CollectionUtils.convertList(wxUsers, WxMpUser::getOpenId)); + Map openId2Users = CollectionUtils.convertMap(dbUsers, MpUserDO::getOpenid); + + // 2.1 根据情况,插入或更新 + List users = MpUserConvert.INSTANCE.convertList(account, wxUsers); + List newUsers = new ArrayList<>(); + for (MpUserDO user : users) { + MpUserDO dbUser = openId2Users.get(user.getOpenid()); + if (dbUser == null) { // 新增:稍后批量插入 + newUsers.add(user); + } else { // 更新:直接执行更新 + user.setId(dbUser.getId()); + mpUserMapper.updateById(user); + } + } + // 2.2 批量插入 + if (CollUtil.isNotEmpty(newUsers)) { + mpUserMapper.insertBatch(newUsers); + } + } + + @Override + public void updateUserUnsubscribe(String appId, String openid) { + MpUserDO dbUser = mpUserMapper.selectByAppIdAndOpenid(appId, openid); + if (dbUser == null) { + log.error("[updateUserUnsubscribe][微信公众号粉丝 appId({}) openid({}) 不存在]", appId, openid); + return; + } + mpUserMapper.updateById(new MpUserDO().setId(dbUser.getId()).setSubscribeStatus(CommonStatusEnum.DISABLE.getStatus()) + .setUnsubscribeTime(LocalDateTime.now())); + } + + @Override + public void updateUser(MpUserUpdateReqVO updateReqVO) { + // 校验存在 + MpUserDO user = validateUserExists(updateReqVO.getId()); + + // 第一步,更新标签到公众号 + updateUserTag(user.getAppId(), user.getOpenid(), updateReqVO.getTagIds()); + + // 第二步,更新基本信息到数据库 + MpUserDO updateObj = MpUserConvert.INSTANCE.convert(updateReqVO).setId(user.getId()); + mpUserMapper.updateById(updateObj); + } + + private MpUserDO validateUserExists(Long id) { + MpUserDO user = mpUserMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + + private void updateUserTag(String appId, String openid, List tagIds) { + WxMpService mpService = mpServiceFactory.getRequiredMpService(appId); + try { + // 第一步,先取消原来的标签 + List oldTagIds = mpService.getUserTagService().userTagList(openid); + for (Long tagId : oldTagIds) { + mpService.getUserTagService().batchUntagging(tagId, new String[]{openid}); + } + // 第二步,再设置新的标签 + if (CollUtil.isEmpty(tagIds)) { + return; + } + for (Long tagId: tagIds) { + mpService.getUserTagService().batchTagging(tagId, new String[]{openid}); + } + } catch (WxErrorException e) { + throw exception(USER_UPDATE_TAG_FAIL, e.getError().getErrorMsg()); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/pom.xml b/ruoyi-vue-pro-master/yudao-module-pay/pom.xml new file mode 100644 index 0000000..85bcb1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/pom.xml @@ -0,0 +1,25 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + yudao-module-pay + pom + + yudao-module-pay-api + yudao-module-pay-biz + yudao-spring-boot-starter-biz-pay + + + ${project.artifactId} + + pay 模块,我们放支付业务,提供业务的支付能力。 + 例如说:商户、应用、支付、退款等等 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/pom.xml new file mode 100644 index 0000000..0903abe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/pom.xml @@ -0,0 +1,33 @@ + + + + yudao-module-pay + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-pay-api + jar + + ${project.artifactId} + + pay 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java new file mode 100644 index 0000000..8920884 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 支付单的通知 Request DTO + * + * @author 芋道源码 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayOrderNotifyReqDTO { + + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单号不能为空") + private String merchantOrderId; + + /** + * 支付订单编号 + */ + @NotNull(message = "支付订单编号不能为空") + private Long payOrderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java new file mode 100644 index 0000000..270e01b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 退款单的通知 Request DTO + * + * @author 芋道源码 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayRefundNotifyReqDTO { + + /** + * 商户退款单编号 + */ + @NotEmpty(message = "商户退款单编号不能为空") + private String merchantOrderId; + + /** + * 支付退款编号 + */ + @NotNull(message = "支付退款编号不能为空") + private Long payRefundId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java new file mode 100644 index 0000000..14ba644 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 转账单的通知 Request DTO + * + * @author jason + */ +@Data +public class PayTransferNotifyReqDTO { + + /** + * 商户转账单号 + */ + @NotEmpty(message = "商户转账单号不能为空") + private String merchantTransferId; + + /** + * 转账订单编号 + */ + @NotNull(message = "转账订单编号不能为空") + private Long payTransferId; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java new file mode 100644 index 0000000..60c4ca8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位符,无特殊作用 + */ +package cn.iocoder.yudao.module.pay.api.notify; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java new file mode 100644 index 0000000..8a18381 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.pay.api.order; + +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; + +import javax.validation.Valid; + +/** + * 支付单 API 接口 + * + * @author LeeYan9 + * @since 2022-08-26 + */ +public interface PayOrderApi { + + /** + * 创建支付单 + * + * @param reqDTO 创建请求 + * @return 支付单编号 + */ + Long createOrder(@Valid PayOrderCreateReqDTO reqDTO); + + /** + * 获得支付单 + * + * @param id 支付单编号 + * @return 支付单 + */ + PayOrderRespDTO getOrder(Long id); + + /** + * 更新支付订单价格 + * + * @param id 支付单编号 + * @param payPrice 支付单价格 + */ + void updatePayOrderPrice(Long id, Integer payPrice); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java new file mode 100644 index 0000000..383e18a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.pay.api.order.dto; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 支付单创建 Request DTO + */ +@Data +public class PayOrderCreateReqDTO implements Serializable { + + public static final int SUBJECT_MAX_LENGTH = 32; + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + // ========== 商户相关字段 ========== + + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单编号不能为空") + private String merchantOrderId; + /** + * 商品标题 + */ + @NotEmpty(message = "商品标题不能为空") + @Length(max = SUBJECT_MAX_LENGTH, message = "商品标题不能超过 32") + private String subject; + /** + * 商品描述 + */ + @Length(max = 128, message = "商品描述信息长度不能超过128") + private String body; + + // ========== 订单相关字段 ========== + + /** + * 支付金额,单位:分 + */ + @NotNull(message = "支付金额不能为空") + @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") + private Integer price; + + /** + * 支付过期时间 + */ + @NotNull(message = "支付过期时间不能为空") + private LocalDateTime expireTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java new file mode 100644 index 0000000..583d6d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.pay.api.order.dto; + +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import lombok.Data; + +/** + * 支付单信息 Response DTO + * + * @author 芋道源码 + */ +@Data +public class PayOrderRespDTO { + + /** + * 订单编号,数据库自增 + */ + private Long id; + /** + * 渠道编码 + * + * 枚举 PayChannelEnum + */ + private String channelCode; + + // ========== 商户相关字段 ========== + /** + * 商户订单编号 + * 例如说,内部系统 A 的订单号。需要保证每个 PayMerchantDO 唯一 + */ + private String merchantOrderId; + + // ========== 订单相关字段 ========== + /** + * 支付金额,单位:分 + */ + private Integer price; + /** + * 支付状态 + * + * 枚举 {@link PayOrderStatusEnum} + */ + private Integer status; + + // ========== 渠道相关字段 ========== + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java new file mode 100644 index 0000000..93dfc5a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; + +import javax.validation.Valid; + +/** + * 退款单 API 接口 + * + * @author 芋道源码 + */ +public interface PayRefundApi { + + /** + * 创建退款单 + * + * @param reqDTO 创建请求 + * @return 退款单编号 + */ + Long createRefund(@Valid PayRefundCreateReqDTO reqDTO); + + /** + * 获得退款单 + * + * @param id 退款单编号 + * @return 退款单 + */ + PayRefundRespDTO getRefund(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java new file mode 100644 index 0000000..f1d5f6e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.pay.api.refund.dto; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 退款单创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class PayRefundCreateReqDTO { + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + // ========== 商户相关字段 ========== + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单编号不能为空") + private String merchantOrderId; + + /** + * 商户退款编号 + */ + @NotEmpty(message = "商户退款编号不能为空") + private String merchantRefundId; + + /** + * 退款描述 + */ + @NotEmpty(message = "退款描述不能为空") + @Length(max = 128, message = "退款描述长度不能超过 128") + private String reason; + + // ========== 订单相关字段 ========== + + /** + * 退款金额,单位:分 + */ + @NotNull(message = "退款金额不能为空") + @Min(value = 1, message = "退款金额必须大于零") + private Integer price; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java new file mode 100644 index 0000000..bcc2b7f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.pay.api.refund.dto; + +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 退款单信息 Response DTO + * + * @author 芋道源码 + */ +@Data +public class PayRefundRespDTO { + + /** + * 退款单编号 + */ + private Long id; + + // ========== 退款相关字段 ========== + /** + * 退款状态 + * + * 枚举 {@link PayRefundStatusEnum} + */ + private Integer status; + /** + * 退款金额,单位:分 + */ + private Integer refundPrice; + + // ========== 商户相关字段 ========== + /** + * 商户订单编号 + */ + private String merchantOrderId; + /** + * 退款成功时间 + */ + private LocalDateTime successTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java new file mode 100644 index 0000000..7899068 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.api.transfer; + +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; + +import javax.validation.Valid; + +/** + * 转账单 API 接口 + * + * @author jason + */ +public interface PayTransferApi { + + /** + * 创建转账单 + * + * @param reqDTO 创建请求 + * @return 转账单编号 + */ + Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java new file mode 100644 index 0000000..d7bb660 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.pay.api.transfer.dto; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * 转账单创建 Request DTO + * + * @author jason + */ +@Data +public class PayTransferCreateReqDTO { + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + + @NotEmpty(message = "转账渠道不能为空") + private String channelCode; + + /** + * 转账渠道的额外参数 + */ + private Map channelExtras; + + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + /** + * 类型 + */ + @NotNull(message = "转账类型不能为空") + @InEnum(PayTransferTypeEnum.class) + private Integer type; + + + /** + * 商户转账单编号 + */ + @NotEmpty(message = "商户转账单编号能为空") + private String merchantTransferId; + + /** + * 转账金额,单位:分 + */ + @Min(value = 1, message = "转账金额必须大于零") + @NotNull(message = "转账金额不能为空") + private Integer price; + + /** + * 转账标题 + */ + @NotEmpty(message = "转账标题不能为空") + private String subject; + + /** + * 收款人姓名 + */ + @NotBlank(message = "收款人姓名不能为空", groups = {PayTransferTypeEnum.Alipay.class}) + private String userName; + + @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class}) + private String alipayLogonId; + + // ========== 微信转账相关字段 ========== + @NotBlank(message = "微信 openId 不能为空", groups = {PayTransferTypeEnum.WxPay.class}) + private String openid; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/DictTypeConstants.java new file mode 100644 index 0000000..8f0d9b7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/DictTypeConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.pay.enums; + +/** + * Pay 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String CHANNEL_CODE = "pay_channel_code"; // 支付渠道编码 + + String ORDER_STATUS = "pay_order_status"; // 支付渠道 + + String REFUND_STATUS = "pay_order_status"; // 退款状态 + + String NOTIFY_STATUS = "pay_notify_status"; // 回调状态 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..8b7a38e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.pay.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Pay 错误码 Core 枚举类 + * + * pay 系统,使用 1-007-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== APP 模块 1-007-000-000 ========== + ErrorCode APP_NOT_FOUND = new ErrorCode(1_007_000_000, "App 不存在"); + ErrorCode APP_IS_DISABLE = new ErrorCode(1_007_000_002, "App 已经被禁用"); + ErrorCode APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1_007_000_003, "支付应用存在支付订单,无法删除"); + ErrorCode APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1_007_000_004, "支付应用存在退款订单,无法删除"); + + // ========== CHANNEL 模块 1-007-001-000 ========== + ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1_007_001_000, "支付渠道的配置不存在"); + ErrorCode CHANNEL_IS_DISABLE = new ErrorCode(1_007_001_001, "支付渠道已经禁用"); + ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1_007_001_004, "已存在相同的渠道"); + + // ========== ORDER 模块 1-007-002-000 ========== + ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1_007_002_000, "支付订单不存在"); + ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_002_001, "支付订单不处于待支付"); + ErrorCode PAY_ORDER_STATUS_IS_SUCCESS = new ErrorCode(1_007_002_002, "订单已支付,请刷新页面"); + ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1_007_002_003, "支付订单已经过期"); + ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_002_004, "发起支付报错,错误码:{},错误提示:{}"); + ErrorCode PAY_ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1_007_002_005, "支付订单退款失败,原因:状态不是已支付或已退款"); + + // ========== ORDER 模块(拓展单) 1-007-003-000 ========== + ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1_007_003_000, "支付交易拓展单不存在"); + ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_003_001, "支付交易拓展单不处于待支付"); + ErrorCode PAY_ORDER_EXTENSION_IS_PAID = new ErrorCode(1_007_003_002, "订单已支付,请等待支付结果"); + + // ========== 支付模块(退款) 1-007-006-000 ========== + ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1_007_006_000, "退款金额超过订单可退款金额"); + ErrorCode REFUND_HAS_REFUNDING = new ErrorCode(1_007_006_002, "已经有退款在处理中"); + ErrorCode REFUND_EXISTS = new ErrorCode(1_007_006_003, "已经存在退款单"); + ErrorCode REFUND_NOT_FOUND = new ErrorCode(1_007_006_004, "支付退款单不存在"); + ErrorCode REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_006_005, "支付退款单不处于待退款"); + + // ========== 钱包模块 1-007-007-000 ========== + ErrorCode WALLET_NOT_FOUND = new ErrorCode(1_007_007_000, "用户钱包不存在"); + ErrorCode WALLET_BALANCE_NOT_ENOUGH = new ErrorCode(1_007_007_001, "钱包余额不足"); + ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1_007_007_002, "未找到对应的钱包交易"); + ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1_007_007_003, "已经存在钱包退款"); + ErrorCode WALLET_FREEZE_PRICE_NOT_ENOUGH = new ErrorCode(1_007_007_004, "钱包冻结余额不足"); + + // ========== 钱包充值模块 1-007-008-000 ========== + ErrorCode WALLET_RECHARGE_NOT_FOUND = new ErrorCode(1_007_008_000, "钱包充值记录不存在"); + ErrorCode WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_008_001, "钱包充值更新支付状态失败,钱包充值记录不是【未支付】状态"); + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1_007_008_002, "钱包充值更新支付状态失败,支付单编号不匹配"); + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1_007_008_003, "钱包充值更新支付状态失败,支付单状态不是【支付成功】状态"); + ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1_007_008_004, "钱包充值更新支付状态失败,支付单金额不匹配"); + ErrorCode WALLET_RECHARGE_REFUND_FAIL_NOT_PAID = new ErrorCode(1_007_008_005, "钱包发起退款失败,钱包充值订单未支付"); + ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUNDED = new ErrorCode(1_007_008_006, "钱包发起退款失败,钱包充值订单已退款"); + ErrorCode WALLET_RECHARGE_REFUND_BALANCE_NOT_ENOUGH = new ErrorCode(1_007_008_007, "钱包发起退款失败,钱包余额不足"); + ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_008_008, "钱包退款更新失败,钱包退款单编号不匹配"); + ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1_007_008_009, "钱包退款更新失败,退款订单不存在"); + ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_008_010, "钱包退款更新失败,退款单金额不匹配"); + ErrorCode WALLET_RECHARGE_PACKAGE_NOT_FOUND = new ErrorCode(1_007_008_011, "钱包充值套餐不存在"); + ErrorCode WALLET_RECHARGE_PACKAGE_IS_DISABLE = new ErrorCode(1_007_008_012, "钱包充值套餐已禁用"); + ErrorCode WALLET_RECHARGE_PACKAGE_NAME_EXISTS = new ErrorCode(1_007_008_013, "钱包充值套餐名称已存在"); + + // ========== 转账模块 1-007-009-000 ========== + ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); + ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在"); + ErrorCode PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH = new ErrorCode(1_007_009_002, "两次相同转账请求的类型不匹配"); + ErrorCode PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "两次相同转账请求的金额不匹配"); + ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经发起,请查询转账订单相关状态"); + ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账"); + ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中"); + + // ========== 示例订单 1-007-900-000 ========== + ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在"); + ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态"); + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1_007_900_002, "示例订单更新支付状态失败,支付单编号不匹配"); + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1_007_900_003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态"); + ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1_007_900_004, "示例订单更新支付状态失败,支付单金额不匹配"); + ErrorCode DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1_007_900_005, "发起退款失败,示例订单未支付"); + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1_007_900_006, "发起退款失败,示例订单已退款"); + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1_007_900_007, "发起退款失败,退款订单不存在"); + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1_007_900_008, "发起退款失败,退款订单未退款成功"); + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_900_009, "发起退款失败,退款单编号不匹配"); + ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_900_010, "发起退款失败,退款单金额不匹配"); + + // ========== 示例转账订单 1-007-901-001 ========== + ErrorCode DEMO_TRANSFER_NOT_FOUND = new ErrorCode(1_007_901_001, "示例转账单不存在"); + ErrorCode DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR = new ErrorCode(1_007_901_002, "转账失败,转账单编号不匹配"); + ErrorCode DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "转账失败,转账单金额不匹配"); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyStatusEnum.java new file mode 100644 index 0000000..b735598 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyStatusEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.pay.enums.notify; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付通知状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayNotifyStatusEnum { + + WAITING(0, "等待通知"), + SUCCESS(10, "通知成功"), + FAILURE(20, "通知失败"), // 多次尝试,彻底失败 + REQUEST_SUCCESS(21, "请求成功,但是结果失败"), + REQUEST_FAILURE(22, "请求失败"), + + ; + + /** + * 状态 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java new file mode 100644 index 0000000..873e015 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.pay.enums.notify; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付通知类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayNotifyTypeEnum { + + ORDER(1, "支付单"), + REFUND(2, "退款单"), + TRANSFER(3, "转账单") + ; + + /** + * 类型 + */ + private final Integer type; + /** + * 名字 + */ + private final String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java new file mode 100644 index 0000000..86a9e17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.pay.enums.order; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 支付订单的状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayOrderStatusEnum implements IntArrayValuable { + + WAITING(0, "未支付"), + SUCCESS(10, "支付成功"), + REFUND(20, "已退款"), + CLOSED(30, "支付关闭"), // 注意:全部退款后,还是 REFUND 状态 + ; + + private final Integer status; + private final String name; + + @Override + public int[] array() { + return new int[0]; + } + + /** + * 判断是否支付成功 + * + * @param status 状态 + * @return 是否支付成功 + */ + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + /** + * 判断是否支付成功或者已退款 + * + * @param status 状态 + * @return 是否支付成功或者已退款 + */ + public static boolean isSuccessOrRefund(Integer status) { + return ObjectUtils.equalsAny(status, + SUCCESS.getStatus(), REFUND.getStatus()); + } + + /** + * 判断是否支付关闭 + * + * @param status 状态 + * @return 是否支付关闭 + */ + public static boolean isClosed(Integer status) { + return Objects.equals(status, CLOSED.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java new file mode 100644 index 0000000..4ae14cc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.pay.enums.refund; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 渠道的退款状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayRefundStatusEnum { + + WAITING(0, "未退款"), + SUCCESS(10, "退款成功"), + FAILURE(20, "退款失败"); + + private final Integer status; + private final String name; + + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + public static boolean isFailure(Integer status) { + return Objects.equals(status, FAILURE.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java new file mode 100644 index 0000000..6f2f27c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.pay.enums.transfer; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * @author jason + */ +@Getter +@AllArgsConstructor +public enum PayTransferStatusEnum { + + WAITING(0, "等待转账"), + /** + * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现 + */ + IN_PROGRESS(10, "转账进行中"), + + SUCCESS(20, "转账成功"), + /** + * 转账关闭 (失败,或者其它情况) // TODO 改成 转账失败状态 + */ + CLOSED(30, "转账关闭"); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + public static boolean isClosed(Integer status) { + return Objects.equals(status, CLOSED.getStatus()); + } + + public static boolean isWaiting(Integer status) { + return Objects.equals(status, WAITING.getStatus()); + } + public static boolean isInProgress(Integer status) { + return Objects.equals(status, IN_PROGRESS.getStatus()); + } + + /** + * 是否处于待转账或者转账中的状态 + * @param status 状态 + */ + public static boolean isPendingStatus(Integer status) { + return Objects.equals(status, WAITING.getStatus()) || Objects.equals(status, IN_PROGRESS.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferTypeEnum.java new file mode 100644 index 0000000..c881515 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferTypeEnum.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.pay.enums.transfer; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 转账类型枚举 + * + * @author jason + */ +@AllArgsConstructor +@Getter +public enum PayTransferTypeEnum implements IntArrayValuable { + + ALIPAY_BALANCE(1, "支付宝余额"), + WX_BALANCE(2, "微信余额"), + BANK_CARD(3, "银行卡"), + WALLET_BALANCE(4, "钱包余额"); + + public interface WxPay { + } + + public interface Alipay { + } + + private final Integer type; + private final String name; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayTransferTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + + public static PayTransferTypeEnum typeOf(Integer type) { + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java new file mode 100644 index 0000000..20e0a8b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.pay.enums.wallet; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 钱包交易业务分类 + * + * @author jason + */ +@AllArgsConstructor +@Getter +public enum PayWalletBizTypeEnum implements IntArrayValuable { + + RECHARGE(1, "充值"), + RECHARGE_REFUND(2, "充值退款"), + PAYMENT(3, "支付"), + PAYMENT_REFUND(4, "支付退款"); + + // TODO 后续增加 + + /** + * 业务分类 + */ + private final Integer type; + /** + * 说明 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayWalletBizTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/pom.xml new file mode 100644 index 0000000..738b133 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/pom.xml @@ -0,0 +1,80 @@ + + + + cn.iocoder.boot + yudao-module-pay + ${revision} + + 4.0.0 + yudao-module-pay-biz + jar + + ${project.artifactId} + + pay 模块,我们放支付业务,提供业务的支付能力。 + 例如说:商户、应用、支付、退款等等 + + + + + cn.iocoder.boot + yudao-module-pay-api + ${revision} + + + cn.iocoder.boot + yudao-module-member-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-pay + ${revision} + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-job + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java new file mode 100644 index 0000000..26234ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.api.order; + +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 支付单 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class PayOrderApiImpl implements PayOrderApi { + + @Resource + private PayOrderService payOrderService; + + @Override + public Long createOrder(PayOrderCreateReqDTO reqDTO) { + return payOrderService.createOrder(reqDTO); + } + + @Override + public PayOrderRespDTO getOrder(Long id) { + PayOrderDO order = payOrderService.getOrder(id); + return PayOrderConvert.INSTANCE.convert2(order); + } + + @Override + public void updatePayOrderPrice(Long id, Integer payPrice) { + payOrderService.updatePayOrderPrice(id, payPrice); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java new file mode 100644 index 0000000..95ca9a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 退款单 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PayRefundApiImpl implements PayRefundApi { + + @Resource + private PayRefundService payRefundService; + + @Override + public Long createRefund(PayRefundCreateReqDTO reqDTO) { + return payRefundService.createPayRefund(reqDTO); + } + + @Override + public PayRefundRespDTO getRefund(Long id) { + return PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java new file mode 100644 index 0000000..786cf70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.pay.api.transfer; + +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 转账单 API 实现类 + * + * @author jason + */ +@Service +@Validated +public class PayTransferApiImpl implements PayTransferApi { + + @Resource + private PayTransferService payTransferService; + + @Override + public Long createTransfer(PayTransferCreateReqDTO reqDTO) { + return payTransferService.createTransfer(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/PayAppController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/PayAppController.java new file mode 100644 index 0000000..ba62069 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/PayAppController.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.*; +import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Slf4j +@Tag(name = "管理后台 - 支付应用信息") +@RestController +@RequestMapping("/pay/app") +@Validated +public class PayAppController { + + @Resource + private PayAppService appService; + @Resource + private PayChannelService channelService; + + @PostMapping("/create") + @Operation(summary = "创建支付应用信息") + @PreAuthorize("@ss.hasPermission('pay:app:create')") + public CommonResult createApp(@Valid @RequestBody PayAppCreateReqVO createReqVO) { + return success(appService.createApp(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新支付应用信息") + @PreAuthorize("@ss.hasPermission('pay:app:update')") + public CommonResult updateApp(@Valid @RequestBody PayAppUpdateReqVO updateReqVO) { + appService.updateApp(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新支付应用状态") + @PreAuthorize("@ss.hasPermission('pay:app:update')") + public CommonResult updateAppStatus(@Valid @RequestBody PayAppUpdateStatusReqVO updateReqVO) { + appService.updateAppStatus(updateReqVO.getId(), updateReqVO.getStatus()); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除支付应用信息") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('pay:app:delete')") + public CommonResult deleteApp(@RequestParam("id") Long id) { + appService.deleteApp(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得支付应用信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:app:query')") + public CommonResult getApp(@RequestParam("id") Long id) { + PayAppDO app = appService.getApp(id); + return success(PayAppConvert.INSTANCE.convert(app)); + } + + @GetMapping("/page") + @Operation(summary = "获得支付应用信息分页") + @PreAuthorize("@ss.hasPermission('pay:app:query')") + public CommonResult> getAppPage(@Valid PayAppPageReqVO pageVO) { + // 得到应用分页列表 + PageResult pageResult = appService.getAppPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 得到所有的应用编号,查出所有的渠道,并移除未启用的渠道 + List channels = channelService.getChannelListByAppIds( + convertList(pageResult.getList(), PayAppDO::getId)); + channels.removeIf(channel -> !CommonStatusEnum.ENABLE.getStatus().equals(channel.getStatus())); + + // 拼接后返回 + return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels)); + } + + @GetMapping("/list") + @Operation(summary = "获得应用列表") + @PreAuthorize("@ss.hasPermission('pay:merchant:query')") + public CommonResult> getAppList() { + List appListDO = appService.getAppList(); + return success(PayAppConvert.INSTANCE.convertList(appListDO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppBaseVO.java new file mode 100644 index 0000000..45f2936 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppBaseVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.*; + +/** +* 支付应用信息 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class PayAppBaseVO { + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "小豆") + @NotNull(message = "应用名不能为空") + private String name; + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "开启状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "备注", example = "我是一个测试应用") + private String remark; + + @Schema(description = "支付结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay-callback") + @NotNull(message = "支付结果的回调地址不能为空") + @URL(message = "支付结果的回调地址必须为 URL 格式") + private String orderNotifyUrl; + + @Schema(description = "退款结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/refund-callback") + @NotNull(message = "退款结果的回调地址不能为空") + @URL(message = "退款结果的回调地址必须为 URL 格式") + private String refundNotifyUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppCreateReqVO.java new file mode 100644 index 0000000..03cab7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppCreateReqVO.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Schema(description = "管理后台 - 支付应用信息创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayAppCreateReqVO extends PayAppBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageItemRespVO.java new file mode 100644 index 0000000..76b6200 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageItemRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 支付应用信息分页查询 Response VO,相比于支付信息,还会多出应用渠道的开关信息") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayAppPageItemRespVO extends PayAppBaseVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "已配置的支付渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "[alipay_pc, alipay_wap]") + private Set channelCodes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageReqVO.java new file mode 100644 index 0000000..94ade7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 支付应用信息分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayAppPageReqVO extends PageParam { + + @Schema(description = "应用名", example = "小豆") + private String name; + + @Schema(description = "开启状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppRespVO.java new file mode 100644 index 0000000..9471a2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 支付应用信息 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayAppRespVO extends PayAppBaseVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateReqVO.java new file mode 100644 index 0000000..5edf229 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 支付应用信息更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayAppUpdateReqVO extends PayAppBaseVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "应用编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateStatusReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateStatusReqVO.java new file mode 100644 index 0000000..9b8dad6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/app/vo/PayAppUpdateStatusReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.pay.controller.admin.app.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 应用更新状态 Request VO") +@Data +public class PayAppUpdateStatusReqVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "应用编号不能为空") + private Long id; + + @Schema(description = "状态,见 SysCommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java new file mode 100644 index 0000000..37927a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.pay.controller.admin.channel; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 支付渠道") +@RestController +@RequestMapping("/pay/channel") +@Validated +public class PayChannelController { + + @Resource + private PayChannelService channelService; + + @PostMapping("/create") + @Operation(summary = "创建支付渠道 ") + @PreAuthorize("@ss.hasPermission('pay:channel:create')") + public CommonResult createChannel(@Valid @RequestBody PayChannelCreateReqVO createReqVO) { + return success(channelService.createChannel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新支付渠道 ") + @PreAuthorize("@ss.hasPermission('pay:channel:update')") + public CommonResult updateChannel(@Valid @RequestBody PayChannelUpdateReqVO updateReqVO) { + channelService.updateChannel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除支付渠道 ") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('pay:channel:delete')") + public CommonResult deleteChannel(@RequestParam("id") Long id) { + channelService.deleteChannel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得支付渠道") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:channel:query')") + public CommonResult getChannel(@RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "appId", required = false) Long appId, + @RequestParam(value = "code", required = false) String code) { + PayChannelDO channel = null; + if (id != null) { + channel = channelService.getChannel(id); + } else if (appId != null && code != null) { + channel = channelService.getChannelByAppIdAndCode(appId, code); + } + return success(PayChannelConvert.INSTANCE.convert(channel)); + } + + @GetMapping("/get-enable-code-list") + @Operation(summary = "获得指定应用的开启的支付渠道编码列表") + @Parameter(name = "appId", description = "应用编号", required = true, example = "1") + public CommonResult> getEnableChannelCodeList(@RequestParam("appId") Long appId) { + List channels = channelService.getEnableChannelList(appId); + return success(convertSet(channels, PayChannelDO::getCode)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelBaseVO.java new file mode 100644 index 0000000..1416c97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelBaseVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.controller.admin.channel.vo; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import javax.validation.constraints.*; + +/** +* 支付渠道 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class PayChannelBaseVO { + + @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "备注", example = "我是小备注") + private String remark; + + @Schema(description = "渠道费率,单位:百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "渠道费率,单位:百分比不能为空") + private Double feeRate; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "应用编号不能为空") + private Long appId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelCreateReqVO.java new file mode 100644 index 0000000..0807382 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.pay.controller.admin.channel.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 支付渠道 创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayChannelCreateReqVO extends PayChannelBaseVO { + + @Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "alipay_pc") + @NotNull(message = "渠道编码不能为空") + private String code; + + @Schema(description = "渠道配置的 json 字符串") + @NotBlank(message = "渠道配置不能为空") + private String config; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelRespVO.java new file mode 100644 index 0000000..dafd29e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.pay.controller.admin.channel.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 支付渠道 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayChannelRespVO extends PayChannelBaseVO { + + @Schema(description = "商户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private LocalDateTime createTime; + + @Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "alipay_pc") + private String code; + + @Schema(description = "配置", requiredMode = Schema.RequiredMode.REQUIRED) + private String config; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelUpdateReqVO.java new file mode 100644 index 0000000..39bf83e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/vo/PayChannelUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.pay.controller.admin.channel.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 支付渠道 更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayChannelUpdateReqVO extends PayChannelBaseVO { + + @Schema(description = "商户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "商户编号不能为空") + private Long id; + + @Schema(description = "渠道配置的json字符串") + @NotBlank(message = "渠道配置不能为空") + private String config; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java new file mode 100644 index 0000000..58834fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO; +import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; +import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 示例订单") +@RestController +@RequestMapping("/pay/demo-order") +@Validated +public class PayDemoOrderController { + + @Resource + private PayDemoOrderService payDemoOrderService; + + @PostMapping("/create") + @Operation(summary = "创建示例订单") + public CommonResult createDemoOrder(@Valid @RequestBody PayDemoOrderCreateReqVO createReqVO) { + return success(payDemoOrderService.createDemoOrder(getLoginUserId(), createReqVO)); + } + + @GetMapping("/page") + @Operation(summary = "获得示例订单分页") + public CommonResult> getDemoOrderPage(@Valid PageParam pageVO) { + PageResult pageResult = payDemoOrderService.getDemoOrderPage(pageVO); + return success(PayDemoOrderConvert.INSTANCE.convertPage(pageResult)); + } + + @PostMapping("/update-paid") + @Operation(summary = "更新示例订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 + public CommonResult updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { + payDemoOrderService.updateDemoOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), + notifyReqDTO.getPayOrderId()); + return success(true); + } + + @PutMapping("/refund") + @Operation(summary = "发起示例订单的退款") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult refundDemoOrder(@RequestParam("id") Long id) { + payDemoOrderService.refundDemoOrder(id, getClientIP()); + return success(true); + } + + @PostMapping("/update-refunded") + @Operation(summary = "更新示例订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 + public CommonResult updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { + payDemoOrderService.updateDemoOrderRefunded(Long.valueOf(notifyReqDTO.getMerchantOrderId()), + notifyReqDTO.getPayRefundId()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java new file mode 100644 index 0000000..814f0c2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO; +import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; +import cn.iocoder.yudao.module.pay.service.demo.PayDemoTransferService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 示例转账单") +@RestController +@RequestMapping("/pay/demo-transfer") +@Validated +public class PayDemoTransferController { + @Resource + private PayDemoTransferService demoTransferService; + + @PostMapping("/create") + @Operation(summary = "创建示例转账订单") + public CommonResult createDemoTransfer(@Valid @RequestBody PayDemoTransferCreateReqVO createReqVO) { + return success(demoTransferService.createDemoTransfer(createReqVO)); + } + + @GetMapping("/page") + @Operation(summary = "获得示例转账订单分页") + public CommonResult> getDemoTransferPage(@Valid PageParam pageVO) { + PageResult pageResult = demoTransferService.getDemoTransferPage(pageVO); + return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult)); + } + + @PostMapping("/update-status") + @Operation(summary = "更新示例转账订单的转账状态") // 由 pay-module 转账服务,进行回调 + @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现 + public CommonResult updateDemoTransferStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { + demoTransferService.updateDemoTransferStatus(Long.valueOf(notifyReqDTO.getMerchantTransferId()), + notifyReqDTO.getPayTransferId()); + return success(true); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java new file mode 100644 index 0000000..6c82a0a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 示例订单创建 Request VO") +@Data +public class PayDemoOrderCreateReqVO { + + @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17682") + @NotNull(message = "商品编号不能为空") + private Long spuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java new file mode 100644 index 0000000..cb30563 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; + +/** +* 示例订单 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class PayDemoOrderRespVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23199") + private Long userId; + + @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17682") + private Long spuId; + + @Schema(description = "商家备注", example = "李四") + private String spuName; + + @Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "30381") + private Integer price; + + @Schema(description = "是否已支付", requiredMode = Schema.RequiredMode.REQUIRED) + private Boolean payStatus; + + @Schema(description = "支付订单编号", example = "16863") + private Long payOrderId; + + @Schema(description = "订单支付时间") + private LocalDateTime payTime; + + @Schema(description = "支付渠道", example = "alipay_qr") + private String payChannelCode; + + @Schema(description = "支付退款编号", example = "23366") + private Long payRefundId; + + @Schema(description = "退款金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "14039") + private Integer refundPrice; + + @Schema(description = "退款时间") + private LocalDateTime refundTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java new file mode 100644 index 0000000..60adfca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer; + +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Validator; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*; + +/** + * @author jason + */ +@Schema(description = "管理后台 - 示例转账单创建 Request VO") +@Data +public class PayDemoTransferCreateReqVO { + + @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "转账类型不能为空") + @InEnum(PayTransferTypeEnum.class) + private Integer type; + + @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "转账金额不能为空") + @Min(value = 1, message = "转账金额必须大于零") + private Integer price; + + @Schema(description = "收款人姓名", example = "test1") + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class}) + private String userName; + + // ========== 支付宝转账相关字段 ========== + @Schema(description = "支付宝登录号,支持邮箱和手机号格式", example = "test1@@sandbox.com") + @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class}) + private String alipayLogonId; + + // ========== 微信转账相关字段 ========== + @Schema(description = "微信 openId", example = "oLefc4g5Gxx") + @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class}) + private String openid; + + + // ========== 转账到银行卡和钱包相关字段 待补充 ========== + + public void validate(Validator validator) { + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type); + switch (transferType) { + case ALIPAY_BALANCE: { + ValidationUtils.validate(validator, this, Alipay.class); + break; + } + case WX_BALANCE: { + ValidationUtils.validate(validator, this, WxPay.class); + break; + } + default: { + throw new UnsupportedOperationException("待实现"); + } + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferRespVO.java new file mode 100644 index 0000000..3fdab57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferRespVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 示例业务转账订单 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class PayDemoTransferRespVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long appId; + + @Schema(description = "转账金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22338") + private Integer price; + + @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "收款人姓名", example = "test") + private String userName; + + @Schema(description = "支付宝登录号", example = "32167") + private String alipayLogonId; + + @Schema(description = "微信 openId", example = "31139") + private String openid; + + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer transferStatus; + + @Schema(description = "转账订单编号", example = "23695") + private Long payTransferId; + + @Schema(description = "转账支付成功渠道") + private String payChannelCode; + + @Schema(description = "转账支付时间") + private LocalDateTime transferTime; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java new file mode 100644 index 0000000..b66a71e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.pay.controller.admin.notify; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; +import cn.iocoder.yudao.module.pay.convert.notify.PayNotifyTaskConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND; + +@Tag(name = "管理后台 - 回调通知") +@RestController +@RequestMapping("/pay/notify") +@Validated +@Slf4j +public class PayNotifyController { + + @Resource + private PayOrderService orderService; + @Resource + private PayRefundService refundService; + @Resource + private PayNotifyService notifyService; + @Resource + private PayAppService appService; + @Resource + private PayChannelService channelService; + + @PostMapping(value = "/order/{channelId}") + @Operation(summary = "支付渠道的统一【支付】回调") + @PermitAll + public String notifyOrder(@PathVariable("channelId") Long channelId, + @RequestParam(required = false) Map params, + @RequestBody(required = false) String body) { + log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body); + // 1. 校验支付渠道是否存在 + PayClient payClient = channelService.getPayClient(channelId); + if (payClient == null) { + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); + throw exception(CHANNEL_NOT_FOUND); + } + + // 2. 解析通知数据 + PayOrderRespDTO notify = payClient.parseOrderNotify(params, body); + orderService.notifyOrder(channelId, notify); + return "success"; + } + + @PostMapping(value = "/refund/{channelId}") + @Operation(summary = "支付渠道的统一【退款】回调") + @PermitAll + public String notifyRefund(@PathVariable("channelId") Long channelId, + @RequestParam(required = false) Map params, + @RequestBody(required = false) String body) { + log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body); + // 1. 校验支付渠道是否存在 + PayClient payClient = channelService.getPayClient(channelId); + if (payClient == null) { + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); + throw exception(CHANNEL_NOT_FOUND); + } + + // 2. 解析通知数据 + PayRefundRespDTO notify = payClient.parseRefundNotify(params, body); + refundService.notifyRefund(channelId, notify); + return "success"; + } + + @GetMapping("/get-detail") + @Operation(summary = "获得回调通知的明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:notify:query')") + public CommonResult getNotifyTaskDetail(@RequestParam("id") Long id) { + PayNotifyTaskDO task = notifyService.getNotifyTask(id); + if (task == null) { + return success(null); + } + // 拼接返回 + PayAppDO app = appService.getApp(task.getAppId()); + List logs = notifyService.getNotifyLogList(id); + return success(PayNotifyTaskConvert.INSTANCE.convert(task, app, logs)); + } + + @GetMapping("/page") + @Operation(summary = "获得回调通知分页") + @PreAuthorize("@ss.hasPermission('pay:notify:query')") + public CommonResult> getNotifyTaskPage(@Valid PayNotifyTaskPageReqVO pageVO) { + PageResult pageResult = notifyService.getNotifyTaskPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + // 拼接返回 + Map appMap = appService.getAppMap(convertList(pageResult.getList(), PayNotifyTaskDO::getAppId)); + return success(PayNotifyTaskConvert.INSTANCE.convertPage(pageResult, appMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskBaseVO.java new file mode 100644 index 0000000..1e62375 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskBaseVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 回调通知 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class PayNotifyTaskBaseVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10636") + private Long appId; + + @Schema(description = "通知类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Byte type; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6722") + private Long dataId; + + @Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte status; + + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26697") + private String merchantOrderId; + + @Schema(description = "下一次通知时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime nextNotifyTime; + + @Schema(description = "最后一次执行时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime lastExecuteTime; + + @Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED) + private Byte notifyTimes; + + @Schema(description = "最大可通知次数", requiredMode = Schema.RequiredMode.REQUIRED) + private Byte maxNotifyTimes; + + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private String notifyUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskDetailRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskDetailRespVO.java new file mode 100644 index 0000000..7c75613 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskDetailRespVO.java @@ -0,0 +1,54 @@ + +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 回调通知的明细 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayNotifyTaskDetailRespVO extends PayNotifyTaskBaseVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + + @Schema(description = "应用名称", example = "wx_pay") + private String appName; + + @Schema(description = "回调日志列表") + private List logs; + + @Schema(description = "管理后台 - 回调日志") + @Data + public static class Log { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8848") + private Long id; + + @Schema(description = "通知状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte status; + + @Schema(description = "当前通知次数", requiredMode = Schema.RequiredMode.REQUIRED) + private Byte notifyTimes; + + @Schema(description = "HTTP 响应结果", requiredMode = Schema.RequiredMode.REQUIRED) + private String response; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java new file mode 100644 index 0000000..003d2fb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 回调通知分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayNotifyTaskPageReqVO extends PageParam { + + @Schema(description = "应用编号", example = "10636") + private Long appId; + + @Schema(description = "通知类型", example = "2") + private Integer type; + + @Schema(description = "数据编号", example = "6722") + private Long dataId; + + @Schema(description = "通知状态", example = "1") + private Integer status; + + @Schema(description = "商户订单编号", example = "26697") + private String merchantOrderId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskRespVO.java new file mode 100644 index 0000000..d7f7fe6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.controller.admin.notify.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 回调通知 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayNotifyTaskRespVO extends PayNotifyTaskBaseVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3380") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "应用名称", example = "wx_pay") + private String appName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java new file mode 100644 index 0000000..8765ba4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java @@ -0,0 +1,127 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; +import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import com.google.common.collect.Maps; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; + +@Tag(name = "管理后台 - 支付订单") +@RestController +@RequestMapping("/pay/order") +@Validated +public class PayOrderController { + + @Resource + private PayOrderService orderService; + @Resource + private PayAppService appService; + + @GetMapping("/get") + @Operation(summary = "获得支付订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:order:query')") + public CommonResult getOrder(@RequestParam("id") Long id) { + return success(PayOrderConvert.INSTANCE.convert(orderService.getOrder(id))); + } + + @GetMapping("/get-detail") + @Operation(summary = "获得支付订单详情") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:order:query')") + public CommonResult getOrderDetail(@RequestParam("id") Long id) { + PayOrderDO order = orderService.getOrder(id); + if (order == null) { + return success(null); + } + + // 拼接返回 + PayAppDO app = appService.getApp(order.getAppId()); + PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId()); + return success(PayOrderConvert.INSTANCE.convert(order, orderExtension, app)); + } + + @PostMapping("/submit") + @Operation(summary = "提交支付订单") + public CommonResult submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { + // 1. 钱包支付事,需要额外传 user_id 和 user_type + if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { + Map channelExtras = reqVO.getChannelExtras() == null ? + Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); + channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); + channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); + reqVO.setChannelExtras(channelExtras); + } + + // 2. 提交支付 + PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP()); + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得支付订单分页") + @PreAuthorize("@ss.hasPermission('pay:order:query')") + public CommonResult> getOrderPage(@Valid PayOrderPageReqVO pageVO) { + PageResult pageResult = orderService.getOrderPage(pageVO); + if (CollectionUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + + // 拼接返回 + Map appMap = appService.getAppMap(convertList(pageResult.getList(), PayOrderDO::getAppId)); + return success(PayOrderConvert.INSTANCE.convertPage(pageResult, appMap)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出支付订单 Excel") + @PreAuthorize("@ss.hasPermission('pay:order:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportOrderExcel(@Valid PayOrderExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = orderService.getOrderList(exportReqVO); + if (CollectionUtil.isEmpty(list)) { + ExcelUtils.write(response, "支付订单.xls", "数据", + PayOrderExcelVO.class, new ArrayList<>()); + return; + } + + // 拼接返回 + Map appMap = appService.getAppMap(convertList(list, PayOrderDO::getAppId)); + List excelList = PayOrderConvert.INSTANCE.convertList(list, appMap); + // 导出 Excel + ExcelUtils.write(response, "支付订单.xls", "数据", PayOrderExcelVO.class, excelList); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderBaseVO.java new file mode 100644 index 0000000..568f844 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderBaseVO.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 支付订单 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + * + * @author aquan + */ +@Data +public class PayOrderBaseVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "应用编号不能为空") + private Long appId; + + @Schema(description = "渠道编号", example = "2048") + private Long channelId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotNull(message = "商户订单编号不能为空") + private String merchantOrderId; + + @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotNull(message = "商品标题不能为空") + private String subject; + + @Schema(description = "商品描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是土豆") + @NotNull(message = "商品描述不能为空") + private String body; + + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay/notify") + @NotNull(message = "异步通知地址不能为空") + private String notifyUrl; + + @Schema(description = "支付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "支付金额,单位:分不能为空") + private Long price; + + @Schema(description = "渠道手续费,单位:百分比", example = "10") + private Double channelFeeRate; + + @Schema(description = "渠道手续金额,单位:分", example = "100") + private Integer channelFeePrice; + + @Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "支付状态不能为空") + private Integer status; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @NotNull(message = "用户 IP不能为空") + private String userIp; + + @Schema(description = "订单失效时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "订单失效时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime expireTime; + + @Schema(description = "订单支付成功时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime successTime; + + @Schema(description = "支付成功的订单拓展单编号", example = "50") + private Long extensionId; + + @Schema(description = "支付订单号", example = "2048888") + private String no; + + @Schema(description = "退款总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "退款总金额,单位:分不能为空") + private Long refundPrice; + + @Schema(description = "渠道用户编号", example = "2048") + private String channelUserId; + + @Schema(description = "渠道订单号", example = "4096") + private String channelOrderNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderDetailsRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderDetailsRespVO.java new file mode 100644 index 0000000..a4fe463 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderDetailsRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 支付订单详细信息 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayOrderDetailsRespVO extends PayOrderBaseVO { + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String appName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + + /** + * 支付订单扩展 + */ + private PayOrderExtension extension; + + @Data + @Schema(description = "支付订单扩展") + public static class PayOrderExtension { + + @Schema(description = "支付订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String no; + + @Schema(description = "支付异步通知的内容") + private String channelNotifyData; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExcelVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExcelVO.java new file mode 100644 index 0000000..5dc17a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExcelVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; +import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 支付订单 Excel VO + * + * @author aquan + */ +@Data +public class PayOrderExcelVO { + + @ExcelProperty("编号") + private Long id; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @ExcelProperty(value = "支付金额", converter = MoneyConvert.class) + private Integer price; + + @ExcelProperty(value = "退款金额", converter = MoneyConvert.class) + private Integer refundPrice; + + @ExcelProperty(value = "手续金额", converter = MoneyConvert.class) + private Integer channelFeePrice; + + @ExcelProperty("商户单号") + private String merchantOrderId; + + @ExcelProperty(value = "支付单号") + private String no; + + @ExcelProperty("渠道单号") + private String channelOrderNo; + + @ExcelProperty(value = "支付状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.ORDER_STATUS) + private Integer status; + + @ExcelProperty(value = "渠道编号名称", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CHANNEL_CODE) + private String channelCode; + + @ExcelProperty("订单支付成功时间") + private LocalDateTime successTime; + + @ExcelProperty("订单失效时间") + private LocalDateTime expireTime; + + @ExcelProperty(value = "应用名称") + private String appName; + + @ExcelProperty("商品标题") + private String subject; + + @ExcelProperty("商品描述") + private String body; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExportReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExportReqVO.java new file mode 100644 index 0000000..9e4d20b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderExportReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 支付订单 Excel 导出 Request VO,参数和 PayOrderPageReqVO 是一致的") +@Data +public class PayOrderExportReqVO { + + @Schema(description = "应用编号", example = "1024") + private Long appId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户订单编号", example = "4096") + private String merchantOrderId; + + @Schema(description = "渠道编号", example = "1888") + private String channelOrderNo; + + @Schema(description = "支付单号", example = "2014888") + private String no; + + @Schema(description = "支付状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageItemRespVO.java new file mode 100644 index 0000000..05411c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageItemRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 支付订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayOrderPageItemRespVO extends PayOrderBaseVO { + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "应用名称", example = "wx_pay") + private String appName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageReqVO.java new file mode 100644 index 0000000..f7ff801 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 支付订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayOrderPageReqVO extends PageParam { + + @Schema(description = "应用编号", example = "1024") + private Long appId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户订单编号", example = "4096") + private String merchantOrderId; + + @Schema(description = "渠道编号", example = "1888") + private String channelOrderNo; + + @Schema(description = "支付单号", example = "2014888") + private String no; + + @Schema(description = "支付状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java new file mode 100644 index 0000000..d48a4db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 支付订单 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayOrderRespVO extends PayOrderBaseVO { + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitReqVO.java new file mode 100644 index 0000000..ffda105 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 支付订单提交 Request VO") +@Data +public class PayOrderSubmitReqVO { + + @Schema(description = "支付单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "支付单编号不能为空") + private Long id; + + @Schema(description = "支付渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_pub") + @NotEmpty(message = "支付渠道不能为空") + private String channelCode; + + @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数") + private Map channelExtras; + + @Schema(description = "展示模式", example = "url") // 参见 {@link PayDisplayModeEnum} 枚举。如果不传递,则每个支付渠道使用默认的方式 + private String displayMode; + + @Schema(description = "回跳地址") + @URL(message = "回跳地址的格式必须是 URL") + private String returnUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java new file mode 100644 index 0000000..8dcd9df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.pay.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 支付订单提交 Response VO") +@Data +public class PayOrderSubmitRespVO { + + @Schema(description = "支付状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") // 参见 PayOrderStatusEnum 枚举 + private Integer status; + + @Schema(description = "展示模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "url") // 参见 PayDisplayModeEnum 枚举 + private String displayMode; + @Schema(description = "展示内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String displayContent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java new file mode 100644 index 0000000..7dbef49 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*; +import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 退款订单") +@RestController +@RequestMapping("/pay/refund") +@Validated +public class PayRefundController { + + @Resource + private PayRefundService refundService; + @Resource + private PayAppService appService; + + @GetMapping("/get") + @Operation(summary = "获得退款订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:refund:query')") + public CommonResult getRefund(@RequestParam("id") Long id) { + PayRefundDO refund = refundService.getRefund(id); + if (refund == null) { + return success(new PayRefundDetailsRespVO()); + } + + // 拼接数据 + PayAppDO app = appService.getApp(refund.getAppId()); + return success(PayRefundConvert.INSTANCE.convert(refund, app)); + } + + @GetMapping("/page") + @Operation(summary = "获得退款订单分页") + @PreAuthorize("@ss.hasPermission('pay:refund:query')") + public CommonResult> getRefundPage(@Valid PayRefundPageReqVO pageVO) { + PageResult pageResult = refundService.getRefundPage(pageVO); + if (CollectionUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + + // 处理应用ID数据 + Map appMap = appService.getAppMap(convertList(pageResult.getList(), PayRefundDO::getAppId)); + return success(PayRefundConvert.INSTANCE.convertPage(pageResult, appMap)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出退款订单 Excel") + @PreAuthorize("@ss.hasPermission('pay:refund:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = refundService.getRefundList(exportReqVO); + if (CollectionUtil.isEmpty(list)) { + ExcelUtils.write(response, "退款订单.xls", "数据", + PayRefundExcelVO.class, new ArrayList<>()); + return; + } + + // 拼接返回 + Map appMap = appService.getAppMap(convertList(list, PayRefundDO::getAppId)); + List excelList = PayRefundConvert.INSTANCE.convertList(list, appMap); + // 导出 Excel + ExcelUtils.write(response, "退款订单.xls", "数据", PayRefundExcelVO.class, excelList); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundBaseVO.java new file mode 100644 index 0000000..25cadf4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundBaseVO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** +* 退款订单 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class PayRefundBaseVO { + + @Schema(description = "外部退款号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110") + private String no; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long appId; + + @Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long channelId; + + @Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_app") + private String channelCode; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long orderId; + + // ========== 商户相关字段 ========== + + @Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "225") + private String merchantOrderId; + + @Schema(description = "商户退款订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "512") + private String merchantRefundId; + + @Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED) + private String notifyUrl; + + // ========== 退款相关字段 ========== + + @Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long payPrice; + + @Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + private Long refundPrice; + + @Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要退了") + private String reason; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String userIp; + + // ========== 渠道相关字段 ========== + + @Schema(description = "渠道订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "233") + private String channelOrderNo; + + @Schema(description = "渠道退款单号", example = "2022") + private String channelRefundNo; + + @Schema(description = "退款成功时间") + private LocalDateTime successTime; + + @Schema(description = "调用渠道的错误码") + private String channelErrorCode; + + @Schema(description = "调用渠道的错误提示") + private String channelErrorMsg; + + @Schema(description = "支付渠道的额外参数") + private String channelNotifyData; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundDetailsRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundDetailsRespVO.java new file mode 100644 index 0000000..8f50a3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundDetailsRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 退款订单详情 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayRefundDetailsRespVO extends PayRefundBaseVO { + + @Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿") + private String appName; + + @Schema(description = "支付订单", requiredMode = Schema.RequiredMode.REQUIRED) + private Order order; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "管理后台 - 支付订单") + @Data + public static class Order { + + @Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String subject; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java new file mode 100644 index 0000000..758b6b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert; +import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 退款订单 Excel VO + * + * @author aquan + */ +@Data +public class PayRefundExcelVO { + + @ExcelProperty("支付退款编号") + private Long id; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @ExcelProperty(value = "支付金额", converter = MoneyConvert.class) + private Integer payPrice; + + @ExcelProperty(value = "退款金额", converter = MoneyConvert.class) + private Integer refundPrice; + + @ExcelProperty("商户退款单号") + private String merchantRefundId; + @ExcelProperty("退款单号") + private String no; + @ExcelProperty("渠道退款单号") + private String channelRefundNo; + + @ExcelProperty("商户支付单号") + private String merchantOrderId; + @ExcelProperty("渠道支付单号") + private String channelOrderNo; + + @ExcelProperty(value = "退款状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.REFUND_STATUS) + private Integer status; + + @ExcelProperty(value = "退款渠道", converter = DictConvert.class) + @DictFormat(DictTypeConstants.CHANNEL_CODE) + private String channelCode; + + @ExcelProperty("成功时间") + private LocalDateTime successTime; + + @ExcelProperty(value = "支付应用") + private String appName; + + @ExcelProperty("退款原因") + private String reason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExportReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExportReqVO.java new file mode 100644 index 0000000..645816e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExportReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 退款订单 Excel 导出 Request VO,参数和 PayRefundPageReqVO 是一致的") +@Data +public class PayRefundExportReqVO { + + @Schema(description = "应用编号", example = "1024") + private Long appId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户支付单号", example = "10") + private String merchantOrderId; + + @Schema(description = "商户退款单号", example = "20") + private String merchantRefundId; + + @Schema(description = "渠道支付单号", example = "30") + private String channelOrderNo; + + @Schema(description = "渠道退款单号", example = "40") + private String channelRefundNo; + + @Schema(description = "退款状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageItemRespVO.java new file mode 100644 index 0000000..27c1285 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageItemRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 退款订单分页查询 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayRefundPageItemRespVO extends PayRefundBaseVO { + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿") + private String appName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageReqVO.java new file mode 100644 index 0000000..7ff1530 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.pay.controller.admin.refund.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 退款订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayRefundPageReqVO extends PageParam { + + @Schema(description = "应用编号", example = "1024") + private Long appId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户支付单号", example = "10") + private String merchantOrderId; + + @Schema(description = "商户退款单号", example = "20") + private String merchantRefundId; + + @Schema(description = "渠道支付单号", example = "30") + private String channelOrderNo; + + @Schema(description = "渠道退款单号", example = "40") + private String channelRefundNo; + + @Schema(description = "退款状态", example = "0") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java new file mode 100644 index 0000000..29ac6e6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.*; +import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; + +@Tag(name = "管理后台 - 转账单") +@RestController +@RequestMapping("/pay/transfer") +@Validated +public class PayTransferController { + + @Resource + private PayTransferService payTransferService; + + @PostMapping("/create") + @Operation(summary = "创建转账单,发起转账") + @PreAuthorize("@ss.hasPermission('pay:transfer:create')") + public CommonResult createPayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) { + PayTransferDO payTransfer = payTransferService.createTransfer(reqVO, getClientIP()); + return success(new PayTransferCreateRespVO().setId(payTransfer.getId()).setStatus(payTransfer.getStatus())); + } + + @GetMapping("/get") + @Operation(summary = "获得转账订单") + @PreAuthorize("@ss.hasPermission('pay:transfer:query')") + public CommonResult getTransfer(@RequestParam("id") Long id) { + return success(PayTransferConvert.INSTANCE.convert(payTransferService.getTransfer(id))); + } + + @GetMapping("/page") + @Operation(summary = "获得转账订单分页") + @PreAuthorize("@ss.hasPermission('pay:transfer:query')") + public CommonResult> getTransferPage(@Valid PayTransferPageReqVO pageVO) { + PageResult pageResult = payTransferService.getTransferPage(pageVO); + return success(PayTransferConvert.INSTANCE.convertPage(pageResult)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java new file mode 100644 index 0000000..b68398b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo; + +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.Validator; +import javax.validation.constraints.*; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*; + +@Schema(description = "管理后台 - 发起转账 Request VO") +@Data +public class PayTransferCreateReqVO { + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "应用编号不能为空") + private Long appId; + + @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "商户转账单编号不能为空") + private String merchantTransferId; + + @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "转账类型不能为空") + @InEnum(PayTransferTypeEnum.class) + private Integer type; + + @Schema(description = "转账渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "alipay_pc") + @NotEmpty(message = "转账渠道不能为空") + private String channelCode; + + @Min(value = 1, message = "转账金额必须大于零") + @NotNull(message = "转账金额不能为空") + private Integer price; + + @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "示例转账") + @NotEmpty(message = "转账标题不能为空") + private String subject; + + @Schema(description = "收款人姓名", example = "test1") + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class}) + private String userName; + + @Schema(description = "支付宝登录号", example = "test1@sandbox.com") + @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class}) + private String alipayLogonId; + + @Schema(description = "微信 openId", example = "oLefc4g5Gxx") + @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class}) + private String openid; + + @Schema(description = "转账渠道的额外参数") + private Map channelExtras; + + public void validate(Validator validator) { + PayTransferTypeEnum transferType = typeOf(type); + switch (transferType) { + case ALIPAY_BALANCE: { + ValidationUtils.validate(validator, this, Alipay.class); + break; + } + case WX_BALANCE: { + ValidationUtils.validate(validator, this, WxPay.class); + break; + } + default: { + throw new UnsupportedOperationException("待实现"); + } + } + } + + @AssertTrue(message = "转账类型和转账渠道不匹配") + public boolean isValidChannelCode() { + PayTransferTypeEnum transferType = typeOf(type); + switch (transferType) { + case ALIPAY_BALANCE: { + return PayChannelEnum.isAlipay(channelCode); + } + case WX_BALANCE: + case BANK_CARD: + case WALLET_BALANCE: { + throw exception(NOT_IMPLEMENTED); + } + } + return Boolean.FALSE; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateRespVO.java new file mode 100644 index 0000000..9cb44bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 发起转账 Response VO") +@Data +public class PayTransferCreateRespVO { + + @Schema(description = "转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 参见 PayTransferStatusEnum 枚举 + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageItemRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageItemRespVO.java new file mode 100644 index 0000000..9440142 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageItemRespVO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author jason + */ +@Schema(description = "管理后台 - 转账单分页项 Response VO") +@Data +public class PayTransferPageItemRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2931") + private Long id; + + @Schema(description = "转账单号", requiredMode = Schema.RequiredMode.REQUIRED) + private String no; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12831") + private Long appId; + + @Schema(description = "转账渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24833") + private Long channelId; + + @Schema(description = "转账渠道编码", requiredMode = Schema.RequiredMode.REQUIRED) + private String channelCode; + + @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17481") + private String merchantTransferId; + + @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; + + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer status; + + @Schema(description = "转账成功时间") + private LocalDateTime successTime; + + @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "964") + private Integer price; + + @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED) + private String subject; + + @Schema(description = "收款人姓名", example = "王五") + private String userName; + + @Schema(description = "支付宝登录号", example = "29245") + private String alipayLogonId; + + @Schema(description = "微信 openId", example = "26589") + private String openid; + + @Schema(description = "渠道转账单号") + private String channelTransferNo; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java new file mode 100644 index 0000000..88cda1b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 转账单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayTransferPageReqVO extends PageParam { + + @Schema(description = "转账单号") + private String no; + + @Schema(description = "应用编号", example = "12831") + private Long appId; + + @Schema(description = "渠道编码", example = "wx_app") + private String channelCode; + + @Schema(description = "商户转账单编号", example = "17481") + private String merchantTransferId; + + @Schema(description = "类型", example = "2") + private Integer type; + + @Schema(description = "转账状态", example = "2") + private Integer status; + + @Schema(description = "收款人姓名", example = "王五") + private String userName; + + @Schema(description = "渠道转账单号") + private String channelTransferNo; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferRespVO.java new file mode 100644 index 0000000..6b65dfd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferRespVO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 转账单 Response VO") +@Data +public class PayTransferRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2931") + private Long id; + + @Schema(description = "转账单号", requiredMode = Schema.RequiredMode.REQUIRED) + private String no; + + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12831") + private Long appId; + + @Schema(description = "转账渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24833") + private Long channelId; + + @Schema(description = "转账渠道编码", requiredMode = Schema.RequiredMode.REQUIRED) + private String channelCode; + + @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17481") + private String merchantTransferId; + + @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; + + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer status; + + @Schema(description = "转账成功时间") + private LocalDateTime successTime; + + @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "964") + private Integer price; + + @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED) + private String subject; + + @Schema(description = "收款人姓名", example = "王五") + private String userName; + + @Schema(description = "支付宝登录号", example = "29245") + private String alipayLogonId; + + @Schema(description = "微信 openId", example = "26589") + private String openid; + + @Schema(description = "异步通知商户地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private String notifyUrl; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED) + private String userIp; + + @Schema(description = "渠道的额外参数") + private Map channelExtras; + + @Schema(description = "渠道转账单号") + private String channelTransferNo; + + @Schema(description = "调用渠道的错误码") + private String channelErrorCode; + + @Schema(description = "调用渠道的错误提示") + private String channelErrorMsg; + + @Schema(description = "渠道的同步/异步通知的内容") + private String channelNotifyData; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletController.java new file mode 100644 index 0000000..6d61cca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletController.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletUserReqVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.enums.UserTypeEnum.MEMBER; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +@Tag(name = "管理后台 - 用户钱包") +@RestController +@RequestMapping("/pay/wallet") +@Validated +@Slf4j +public class PayWalletController { + + @Resource + private PayWalletService payWalletService; + @Resource + private MemberUserApi memberUserApi; + + @GetMapping("/get") + @PreAuthorize("@ss.hasPermission('pay:wallet:query')") + @Operation(summary = "获得用户钱包明细") + public CommonResult getWallet(PayWalletUserReqVO reqVO) { + PayWalletDO wallet = payWalletService.getOrCreateWallet(reqVO.getUserId(), MEMBER.getValue()); + // TODO jason:如果为空,返回给前端只要 null 就可以了 + MemberUserRespDTO memberUser = memberUserApi.getUser(reqVO.getUserId()); + String nickname = memberUser == null ? "" : memberUser.getNickname(); + String avatar = memberUser == null ? "" : memberUser.getAvatar(); + return success(PayWalletConvert.INSTANCE.convert02(nickname, avatar, wallet)); + } + + @GetMapping("/page") + @Operation(summary = "获得会员钱包分页") + @PreAuthorize("@ss.hasPermission('pay:wallet:query')") + public CommonResult> getWalletPage(@Valid PayWalletPageReqVO pageVO) { + if (StrUtil.isNotEmpty(pageVO.getNickname())) { + List users = memberUserApi.getUserListByNickname(pageVO.getNickname()); + pageVO.setUserIds(convertSet(users, MemberUserRespDTO::getId)); + } + // TODO @jason:管理员也可以先查询下。。 + // 暂时支持查询 userType 会员类型。管理员类型还不知道使用场景 + PageResult pageResult = payWalletService.getWalletPage(MEMBER.getValue(),pageVO); + if (CollectionUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + List users = memberUserApi.getUserList(convertList(pageResult.getList(), PayWalletDO::getUserId)); + Map userMap = convertMap(users, MemberUserRespDTO::getId); + return success(PayWalletConvert.INSTANCE.convertPage(pageResult, userMap)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java new file mode 100644 index 0000000..97942c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; + +@Tag(name = "管理后台 - 钱包充值") +@RestController +@RequestMapping("/pay/wallet-recharge") +@Validated +@Slf4j +public class PayWalletRechargeController { + + @Resource + private PayWalletRechargeService walletRechargeService; + + @PostMapping("/update-paid") + @Operation(summary = "更新钱包充值为已充值") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll // 无需登录, 内部校验实现 + public CommonResult updateWalletRechargerPaid(@Valid @RequestBody PayOrderNotifyReqDTO notifyReqDTO) { + walletRechargeService.updateWalletRechargerPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), + notifyReqDTO.getPayOrderId()); + return success(true); + } + + // TODO @jason:发起退款,要 post 操作哈; + @GetMapping("/refund") + @Operation(summary = "发起钱包充值退款") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult refundWalletRecharge(@RequestParam("id") Long id) { + walletRechargeService.refundWalletRecharge(id, getClientIP()); + return success(true); + } + + @PostMapping("/update-refunded") + @Operation(summary = "更新钱包充值为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob + @PermitAll // 无需登录, 内部校验实现 + public CommonResult updateWalletRechargeRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { + walletRechargeService.updateWalletRechargeRefunded( + Long.valueOf(notifyReqDTO.getMerchantOrderId()), notifyReqDTO.getPayRefundId()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargePackageController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargePackageController.java new file mode 100644 index 0000000..a8e80bc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargePackageController.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackagePageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageUpdateReqVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargePackageConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargePackageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - 钱包充值套餐") +@RestController +@RequestMapping("/pay/wallet-recharge-package") +@Validated +public class PayWalletRechargePackageController { + + @Resource + private PayWalletRechargePackageService walletRechargePackageService; + + @PostMapping("/create") + @Operation(summary = "创建钱包充值套餐") + @PreAuthorize("@ss.hasPermission('pay:wallet-recharge-package:create')") + public CommonResult createWalletRechargePackage(@Valid @RequestBody WalletRechargePackageCreateReqVO createReqVO) { + return success(walletRechargePackageService.createWalletRechargePackage(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新钱包充值套餐") + @PreAuthorize("@ss.hasPermission('pay:wallet-recharge-package:update')") + public CommonResult updateWalletRechargePackage(@Valid @RequestBody WalletRechargePackageUpdateReqVO updateReqVO) { + walletRechargePackageService.updateWalletRechargePackage(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除钱包充值套餐") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('pay:wallet-recharge-package:delete')") + public CommonResult deleteWalletRechargePackage(@RequestParam("id") Long id) { + walletRechargePackageService.deleteWalletRechargePackage(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得钱包充值套餐") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('pay:wallet-recharge-package:query')") + public CommonResult getWalletRechargePackage(@RequestParam("id") Long id) { + PayWalletRechargePackageDO walletRechargePackage = walletRechargePackageService.getWalletRechargePackage(id); + return success(PayWalletRechargePackageConvert.INSTANCE.convert(walletRechargePackage)); + } + + @GetMapping("/page") + @Operation(summary = "获得钱包充值套餐分页") + @PreAuthorize("@ss.hasPermission('pay:wallet-recharge-package:query')") + public CommonResult> getWalletRechargePackagePage(@Valid WalletRechargePackagePageReqVO pageVO) { + PageResult pageResult = walletRechargePackageService.getWalletRechargePackagePage(pageVO); + return success(PayWalletRechargePackageConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletTransactionController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletTransactionController.java new file mode 100644 index 0000000..37dd516 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletTransactionController.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionRespVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 钱包余额明细") +@RestController +@RequestMapping("/pay/wallet-transaction") +@Validated +@Slf4j +public class PayWalletTransactionController { + + @Resource + private PayWalletTransactionService payWalletTransactionService; + + @GetMapping("/page") + @Operation(summary = "获得钱包流水分页") + @PreAuthorize("@ss.hasPermission('pay:wallet:query')") + public CommonResult> getWalletTransactionPage( + @Valid PayWalletTransactionPageReqVO pageReqVO) { + PageResult result = payWalletTransactionService.getWalletTransactionPage(pageReqVO); + return success(PayWalletTransactionConvert.INSTANCE.convertPage2(result)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageBaseVO.java new file mode 100644 index 0000000..c3f58e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageBaseVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 充值套餐 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class WalletRechargePackageBaseVO { + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "套餐名不能为空") + private String name; + + @Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "16454") + @NotNull(message = "支付金额不能为空") + private Integer payPrice; + + @Schema(description = "赠送金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20887") + @NotNull(message = "赠送金额不能为空") + private Integer bonusPrice; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "状态不能为空") + private Byte status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageCreateReqVO.java new file mode 100644 index 0000000..4232a99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 充值套餐创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class WalletRechargePackageCreateReqVO extends WalletRechargePackageBaseVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackagePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackagePageReqVO.java new file mode 100644 index 0000000..346e859 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackagePageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 充值套餐分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class WalletRechargePackagePageReqVO extends PageParam { + + @Schema(description = "套餐名", example = "李四") + private String name; + + @Schema(description = "状态", example = "2") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageRespVO.java new file mode 100644 index 0000000..84abaf7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 充值套餐 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class WalletRechargePackageRespVO extends WalletRechargePackageBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9032") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageUpdateReqVO.java new file mode 100644 index 0000000..37170cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/rechargepackage/WalletRechargePackageUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 充值套餐更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class WalletRechargePackageUpdateReqVO extends WalletRechargePackageBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9032") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionPageReqVO.java new file mode 100644 index 0000000..678649c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionPageReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 钱包流水分页 Request VO") +@Data +public class PayWalletTransactionPageReqVO extends PageParam { + + @Schema(description = "钱包编号", example = "1") + private Long walletId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionRespVO.java new file mode 100644 index 0000000..6203b78 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/transaction/PayWalletTransactionRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 APP - 钱包流水分页 Response VO") +@Data +public class PayWalletTransactionRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "钱包编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Long walletId; + + @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer bizType; + + @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long price; + + @Schema(description = "流水标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆土豆") + private String title; + + @Schema(description = "交易后的余额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long balance; + + @Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // TODO @jason:merchantOrderId 字段,需要在 PayWalletTransaction 存储下;然后,前端也返回下这个字段,界面也展示下商户名 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletBaseVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletBaseVO.java new file mode 100644 index 0000000..a45ea8b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletBaseVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 用户钱包 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class PayWalletBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20020") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "余额,单位分", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "余额,单位分不能为空") + private Integer balance; + + @Schema(description = "累计支出,单位分", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "累计支出,单位分不能为空") + private Integer totalExpense; + + @Schema(description = "累计充值,单位分", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "累计充值,单位分不能为空") + private Integer totalRecharge; + + @Schema(description = "冻结金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "20737") + @NotNull(message = "冻结金额,单位分不能为空") + private Integer freezePrice; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletPageReqVO.java new file mode 100644 index 0000000..d74bd44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.Collection; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 会员钱包分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayWalletPageReqVO extends PageParam { + + @Schema(description = "用户昵称", example = "李四") + private String nickname; + + @Schema(description = "用户编号", example = "[1,2]") + private Collection userIds; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletRespVO.java new file mode 100644 index 0000000..a9eedbd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 用户钱包 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayWalletRespVO extends PayWalletBaseVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29528") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王**") + private String nickname; + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.jpg") + private String avatar; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletUserReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletUserReqVO.java new file mode 100644 index 0000000..dfa3351 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/vo/wallet/PayWalletUserReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户钱包明细 Request VO") +@Data +public class PayWalletUserReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/channel/AppPayChannelController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/channel/AppPayChannelController.java new file mode 100644 index 0000000..12323a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/channel/AppPayChannelController.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.controller.app.channel; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "用户 App - 支付渠道") +@RestController +@RequestMapping("/pay/channel") +@Validated +public class AppPayChannelController { + + @Resource + private PayChannelService channelService; + + @GetMapping("/get-enable-code-list") + @Operation(summary = "获得指定应用的开启的支付渠道编码列表") + @Parameter(name = "appId", description = "应用编号", required = true, example = "1") + public CommonResult> getEnableChannelCodeList(@RequestParam("appId") Long appId) { + List channels = channelService.getEnableChannelList(appId); + return success(convertSet(channels, PayChannelDO::getCode)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http new file mode 100644 index 0000000..14ce54e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http @@ -0,0 +1,63 @@ +### /pay/create 提交支付订单【alipay_pc】 +POST {{appApi}}/pay/order/submit +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "id": 174, + "channelCode": "alipay_pc" +} + +### /pay/create 提交支付订单【wx_bar】 +POST {{appApi}}/pay/order/submit +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "id": 202, + "channelCode": "wx_bar", + "channelExtras": { + "authCode": "134042110834344848" + } +} + +### /pay/create 提交支付订单【wx_pub】 +POST {{appApi}}/pay/order/submit +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "id": 202, + "channelCode": "wx_pub", + "channelExtras": { + "openid": "ockUAwIZ-0OeMZl9ogcZ4ILrGba0" + } +} + +### /pay/create 提交支付订单【wx_lite】 +POST {{appApi}}/pay/order/submit +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "id": 202, + "channelCode": "wx_lite", + "channelExtras": { + "openid": "oLefc4g5GjKWHJjLjMSXB3wX0fD0" + } +} + +### /pay/create 提交支付订单【wx_native】 +POST {{appApi}}/pay/order/submit +Content-Type: application/json +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +{ + "id": 202, + "channelCode": "wx_native" +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java new file mode 100644 index 0000000..8033b26 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.pay.controller.app.order; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; +import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; +import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import com.google.common.collect.Maps; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; + +@Tag(name = "用户 APP - 支付订单") +@RestController +@RequestMapping("/pay/order") +@Validated +@Slf4j +public class AppPayOrderController { + + @Resource + private PayOrderService payOrderService; + + // TODO 芋艿:临时 demo,技术打样。 + @GetMapping("/get") + @Operation(summary = "获得支付订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getOrder(@RequestParam("id") Long id) { + return success(PayOrderConvert.INSTANCE.convert(payOrderService.getOrder(id))); + } + + @PostMapping("/submit") + @Operation(summary = "提交支付订单") + public CommonResult submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { + // 1. 钱包支付事,需要额外传 user_id 和 user_type + if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { + Map channelExtras = reqVO.getChannelExtras() == null ? + Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); + channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); + channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); + reqVO.setChannelExtras(channelExtras); + } + + // 2. 提交支付 + PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP()); + return success(PayOrderConvert.INSTANCE.convert3(respVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java new file mode 100644 index 0000000..8f18c6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.pay.controller.app.order.vo; + +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "用户 APP - 支付订单提交 Request VO") +@Data +public class AppPayOrderSubmitReqVO extends PayOrderSubmitReqVO { +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java new file mode 100644 index 0000000..106535e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.pay.controller.app.order.vo; + +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Schema(description = "用户 APP - 支付订单提交 Response VO") +@Data +public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO { + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/package-info.java new file mode 100644 index 0000000..ee2004e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:占个位置,没啥用 + */ +package cn.iocoder.yudao.module.pay.controller.app.refund; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java new file mode 100644 index 0000000..95c085c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.wallet.AppPayWalletRespVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * @author jason + */ +@Tag(name = "用户 APP - 钱包") +@RestController +@RequestMapping("/pay/wallet") +@Validated +@Slf4j +public class AppPayWalletController { + + @Resource + private PayWalletService payWalletService; + + @GetMapping("/get") + @Operation(summary = "获取钱包") + @PreAuthenticated + public CommonResult getPayWallet() { + PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); + return success(PayWalletConvert.INSTANCE.convert(wallet)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java new file mode 100644 index 0000000..515c477 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeRespVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletConvert; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargeService; +import com.google.common.collect.Lists; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; + +@Tag(name = "用户 APP - 钱包充值") +@RestController +@RequestMapping("/pay/wallet-recharge") +@Validated +@Slf4j +public class AppPayWalletRechargeController { + + @Resource + private PayWalletRechargeService walletRechargeService; + @Resource + private PayOrderService payOrderService; + + @PostMapping("/create") + @Operation(summary = "创建钱包充值记录(发起充值)") + public CommonResult createWalletRecharge( + @Valid @RequestBody AppPayWalletRechargeCreateReqVO reqVO) { + PayWalletRechargeDO walletRecharge = walletRechargeService.createWalletRecharge( + getLoginUserId(), getLoginUserType(), getClientIP(), reqVO); + return success(PayWalletRechargeConvert.INSTANCE.convert(walletRecharge)); + } + + @GetMapping("/page") + @Operation(summary = "获得钱包充值记录分页") + public CommonResult> getWalletRechargePage(@Valid PageParam pageReqVO) { + PageResult pageResult = walletRechargeService.getWalletRechargePackagePage( + getLoginUserId(), UserTypeEnum.MEMBER.getValue(), pageReqVO, true); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 拼接数据 + List payOrderList = payOrderService.getOrderList( + convertList(pageResult.getList(), PayWalletRechargeDO::getPayOrderId)); + return success(PayWalletRechargeConvert.INSTANCE.convertPage(pageResult, payOrderList)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargePackageController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargePackageController.java new file mode 100644 index 0000000..5446511 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargePackageController.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletPackageRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargePackageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 APP - 钱包充值套餐") +@RestController +@RequestMapping("/pay/wallet-recharge-package") +@Validated +@Slf4j +public class AppPayWalletRechargePackageController { + + @Resource + private PayWalletRechargePackageService walletRechargePackageService; + + @GetMapping("/list") + @Operation(summary = "获得钱包充值套餐列表") + public CommonResult> getWalletRechargePackageList() { + List list = walletRechargePackageService.getWalletRechargePackageList( + CommonStatusEnum.ENABLE.getStatus()); + list.sort(Comparator.comparingInt(PayWalletRechargePackageDO::getPayPrice)); + return success(BeanUtils.toBean(list, AppPayWalletPackageRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletTransactionController.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletTransactionController.java new file mode 100644 index 0000000..1f651d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletTransactionController.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionSummaryRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.format.annotation.DateTimeFormat; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "用户 APP - 钱包余额明细") +@RestController +@RequestMapping("/pay/wallet-transaction") +@Validated +@Slf4j +public class AppPayWalletTransactionController { + + @Resource + private PayWalletTransactionService payWalletTransactionService; + + @GetMapping("/page") + @Operation(summary = "获得钱包流水分页") + public CommonResult> getWalletTransactionPage( + @Valid AppPayWalletTransactionPageReqVO pageReqVO) { + PageResult pageResult = payWalletTransactionService.getWalletTransactionPage( + getLoginUserId(), UserTypeEnum.MEMBER.getValue(), pageReqVO); + return success(BeanUtils.toBean(pageResult, AppPayWalletTransactionRespVO.class)); + } + + @GetMapping("/get-summary") + @Operation(summary = "获得钱包流水统计") + @Parameter(name = "times", description = "时间段", required = true) + public CommonResult getWalletTransactionSummary( + @RequestParam("createTime") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] createTime) { + AppPayWalletTransactionSummaryRespVO summary = payWalletTransactionService.getWalletTransactionSummary( + getLoginUserId(), UserTypeEnum.MEMBER.getValue(), createTime); + return success(summary); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletPackageRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletPackageRespVO.java new file mode 100644 index 0000000..c12db98 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletPackageRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 用户充值套餐 Response VO") +@Data +public class AppPayWalletPackageRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "小套餐") + private String name; + + @Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer payPrice; + @Schema(description = "赠送金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer bonusPrice; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java new file mode 100644 index 0000000..1049e4e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import java.util.Objects; + +@Schema(description = "用户 APP - 创建钱包充值 Request VO") +@Data +public class AppPayWalletRechargeCreateReqVO { + + @Schema(description = "支付金额", example = "1000") + @Min(value = 1, message = "支付金额必须大于零") + private Integer payPrice; + + @Schema(description = "充值套餐编号", example = "1024") + private Long packageId; + + @AssertTrue(message = "充值金额和充钱套餐不能同时为空") + public boolean isValidPayPriceAndPackageId() { + return Objects.nonNull(payPrice) || Objects.nonNull(packageId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateRespVO.java new file mode 100644 index 0000000..2c4a96f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 创建钱包充值 Resp VO") +@Data +public class AppPayWalletRechargeCreateRespVO { + + @Schema(description = "钱包充值编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long payOrderId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeRespVO.java new file mode 100644 index 0000000..ee55b40 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 APP - 钱包充值记录 Resp VO") +@Data +public class AppPayWalletRechargeRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户实际到账余额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer totalPrice; + + @Schema(description = "实际支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Integer payPrice; + + @Schema(description = "钱包赠送金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + private Integer bonusPrice; + + @Schema(description = "支付成功的支付渠道", requiredMode = Schema.RequiredMode.REQUIRED) + private String payChannelCode; + + @Schema(description = "支付渠道名", example = "微信小程序支付") + private String payChannelName; + + @Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long payOrderId; + + @Schema(description = "支付成功的外部订单号", requiredMode = Schema.RequiredMode.REQUIRED) + private String payOrderChannelOrderNo; // 从 PayOrderDO 的 channelOrderNo 字段 + + @Schema(description = "订单支付时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime payTime; + + @Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer refundStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionPageReqVO.java new file mode 100644 index 0000000..d5daad0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Schema(description = "用户 APP - 钱包流水分页 Request VO") +@Data +public class AppPayWalletTransactionPageReqVO extends PageParam { + + /** + * 类型 - 收入 + */ + public static final Integer TYPE_INCOME = 1; + /** + * 类型 - 支出 + */ + public static final Integer TYPE_EXPENSE = 2; + + @Schema(description = "类型", example = "1") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionRespVO.java new file mode 100644 index 0000000..5c20188 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "用户 APP - 钱包流水分页 Response VO") +@Data +public class AppPayWalletTransactionRespVO { + + @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer bizType; + + @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Long price; + + @Schema(description = "流水标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆土豆") + private String title; + + @Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionSummaryRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionSummaryRespVO.java new file mode 100644 index 0000000..b1cc587 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/transaction/AppPayWalletTransactionSummaryRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 钱包流水统计 Request VO") +@Data +public class AppPayWalletTransactionSummaryRespVO { + + @Schema(description = "累计支出,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer totalExpense; + + @Schema(description = "累计收入,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + private Integer totalIncome; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java new file mode 100644 index 0000000..7e42fc5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.pay.controller.app.wallet.vo.wallet; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 用户钱包 Response VO") +@Data +public class AppPayWalletRespVO { + + @Schema(description = "钱包余额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Integer balance; + + @Schema(description = "累计支出,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Integer totalExpense; + + @Schema(description = "累计充值,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") + private Integer totalRecharge; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/package-info.java new file mode 100644 index 0000000..6521227 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.pay.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/app/PayAppConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/app/PayAppConvert.java new file mode 100644 index 0000000..4853d07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/app/PayAppConvert.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.pay.convert.app; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageItemRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +/** + * 支付应用信息 Convert + * + * @author 芋艿 + */ +@Mapper +public interface PayAppConvert { + + PayAppConvert INSTANCE = Mappers.getMapper(PayAppConvert.class); + + PayAppPageItemRespVO pageConvert (PayAppDO bean); + + PayAppDO convert(PayAppCreateReqVO bean); + + PayAppDO convert(PayAppUpdateReqVO bean); + + PayAppRespVO convert(PayAppDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult pageResult, List channels) { + PageResult voPageResult = convertPage(pageResult); + // 处理 channel 关系 + Map> appIdChannelMap = CollectionUtils.convertMultiMap2(channels, PayChannelDO::getAppId, PayChannelDO::getCode); + voPageResult.getList().forEach(app -> app.setChannelCodes(appIdChannelMap.get(app.getId()))); + return voPageResult; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java new file mode 100644 index 0000000..5baf598 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.pay.convert.channel; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface PayChannelConvert { + + PayChannelConvert INSTANCE = Mappers.getMapper(PayChannelConvert.class); + + @Mapping(target = "config",ignore = true) + PayChannelDO convert(PayChannelCreateReqVO bean); + + @Mapping(target = "config",ignore = true) + PayChannelDO convert(PayChannelUpdateReqVO bean); + + @Mapping(target = "config",expression = "java(cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString(bean.getConfig()))") + PayChannelRespVO convert(PayChannelDO bean); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java new file mode 100644 index 0000000..8fca997 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.pay.convert.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 示例订单 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface PayDemoOrderConvert { + + PayDemoOrderConvert INSTANCE = Mappers.getMapper(PayDemoOrderConvert.class); + + PayDemoOrderDO convert(PayDemoOrderCreateReqVO bean); + + PayDemoOrderRespVO convert(PayDemoOrderDO bean); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java new file mode 100644 index 0000000..0df9c9d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.pay.convert.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author jason + */ +@Mapper +public interface PayDemoTransferConvert { + + PayDemoTransferConvert INSTANCE = Mappers.getMapper(PayDemoTransferConvert.class); + + PayDemoTransferDO convert(PayDemoTransferCreateReqVO bean); + + PageResult convertPage(PageResult pageResult); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/notify/PayNotifyTaskConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/notify/PayNotifyTaskConvert.java new file mode 100644 index 0000000..d0b8e36 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/notify/PayNotifyTaskConvert.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.pay.convert.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 支付通知 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface PayNotifyTaskConvert { + + PayNotifyTaskConvert INSTANCE = Mappers.getMapper(PayNotifyTaskConvert.class); + + PayNotifyTaskRespVO convert(PayNotifyTaskDO bean); + + default PageResult convertPage(PageResult page, Map appMap){ + PageResult result = convertPage(page); + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName()))); + return result; + } + PageResult convertPage(PageResult page); + + default PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, PayAppDO app, List logs) { + PayNotifyTaskDetailRespVO respVO = convert(task, logs); + if (app != null) { + respVO.setAppName(app.getName()); + } + return respVO; + } + PayNotifyTaskDetailRespVO convert(PayNotifyTaskDO task, List logs); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java new file mode 100644 index 0000000..6820060 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.pay.convert.order; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; +import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 支付订单 Convert + * + * @author aquan + */ +@Mapper +public interface PayOrderConvert { + + PayOrderConvert INSTANCE = Mappers.getMapper(PayOrderConvert.class); + + PayOrderRespVO convert(PayOrderDO bean); + + PayOrderRespDTO convert2(PayOrderDO order); + + default PayOrderDetailsRespVO convert(PayOrderDO order, PayOrderExtensionDO orderExtension, PayAppDO app) { + PayOrderDetailsRespVO respVO = convertDetail(order); + respVO.setExtension(convert(orderExtension)); + if (app != null) { + respVO.setAppName(app.getName()); + } + return respVO; + } + PayOrderDetailsRespVO convertDetail(PayOrderDO bean); + PayOrderDetailsRespVO.PayOrderExtension convert(PayOrderExtensionDO bean); + + default PageResult convertPage(PageResult page, Map appMap) { + PageResult result = convertPage(page); + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName()))); + return result; + } + PageResult convertPage(PageResult page); + + default List convertList(List list, Map appMap) { + return CollectionUtils.convertList(list, order -> { + PayOrderExcelVO excelVO = convertExcel(order); + MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName())); + return excelVO; + }); + } + PayOrderExcelVO convertExcel(PayOrderDO bean); + + PayOrderDO convert(PayOrderCreateReqDTO bean); + + @Mapping(target = "id", ignore = true) + PayOrderExtensionDO convert(PayOrderSubmitReqVO bean, String userIp); + + PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO, String userIp); + + @Mapping(source = "order.status", target = "status") + PayOrderSubmitRespVO convert(PayOrderDO order, cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO respDTO); + + AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/package-info.java new file mode 100644 index 0000000..df43d5a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.pay.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java new file mode 100644 index 0000000..9f087f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.pay.convert.refund; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundDetailsRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExcelVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageItemRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface PayRefundConvert { + + PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class); + + + default PayRefundDetailsRespVO convert(PayRefundDO refund, PayAppDO app) { + PayRefundDetailsRespVO respVO = convert(refund); + if (app != null) { + respVO.setAppName(app.getName()); + } + return respVO; + } + PayRefundDetailsRespVO convert(PayRefundDO bean); + PayRefundDetailsRespVO.Order convert(PayOrderDO bean); + + default PageResult convertPage(PageResult page, Map appMap) { + PageResult result = convertPage(page); + result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName()))); + return result; + } + PageResult convertPage(PageResult page); + + PayRefundDO convert(PayRefundCreateReqDTO bean); + + PayRefundRespDTO convert02(PayRefundDO bean); + + default List convertList(List list, Map appMap) { + return CollectionUtils.convertList(list, order -> { + PayRefundExcelVO excelVO = convertExcel(order); + MapUtils.findAndThen(appMap, order.getAppId(), app -> excelVO.setAppName(app.getName())); + return excelVO; + }); + } + PayRefundExcelVO convertExcel(PayRefundDO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java new file mode 100644 index 0000000..4e79548 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.convert.transfer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface PayTransferConvert { + + PayTransferConvert INSTANCE = Mappers.getMapper(PayTransferConvert.class); + + PayTransferDO convert(PayTransferCreateReqDTO dto); + + PayTransferUnifiedReqDTO convert2(PayTransferDO dto); + + PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo); + + PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); + + PayTransferRespVO convert(PayTransferDO bean); + + PageResult convertPage(PageResult pageResult); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletConvert.java new file mode 100644 index 0000000..5a003a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletConvert.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.pay.convert.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletRespVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.wallet.AppPayWalletRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Map; + +@Mapper +public interface PayWalletConvert { + + PayWalletConvert INSTANCE = Mappers.getMapper(PayWalletConvert.class); + + AppPayWalletRespVO convert(PayWalletDO bean); + + PayWalletRespVO convert02(String nickname,String avatar, PayWalletDO bean); + + PageResult convertPage(PageResult page); + + default PageResult convertPage(PageResult page, Map userMap) { + PageResult pageResult = convertPage(page); + pageResult.getList().forEach(wallet -> MapUtils.findAndThen(userMap, wallet.getUserId(), + user -> wallet.setNickname(user.getNickname()).setAvatar(user.getAvatar()))); + return pageResult; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java new file mode 100644 index 0000000..e9867fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.pay.convert.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; +import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface PayWalletRechargeConvert { + + PayWalletRechargeConvert INSTANCE = Mappers.getMapper(PayWalletRechargeConvert.class); + + @Mapping(target = "totalPrice", expression = "java( payPrice + bonusPrice)") + PayWalletRechargeDO convert(Long walletId, Integer payPrice, Integer bonusPrice, Long packageId); + + AppPayWalletRechargeCreateRespVO convert(PayWalletRechargeDO bean); + + default PageResult convertPage(PageResult pageResult, + List payOrderList) { + PageResult voPageResult = BeanUtils.toBean(pageResult, AppPayWalletRechargeRespVO.class); + Map payOrderMap = CollectionUtils.convertMap(payOrderList, PayOrderDO::getId); + voPageResult.getList().forEach(recharge -> { + recharge.setPayChannelName(DictFrameworkUtils.getDictDataLabel( + DictTypeConstants.CHANNEL_CODE, recharge.getPayChannelCode())); + MapUtils.findAndThen(payOrderMap, recharge.getPayOrderId(), + order -> recharge.setPayOrderChannelOrderNo(order.getChannelOrderNo())); + }); + return voPageResult; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargePackageConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargePackageConvert.java new file mode 100644 index 0000000..d3af67b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargePackageConvert.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.pay.convert.wallet; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface PayWalletRechargePackageConvert { + + PayWalletRechargePackageConvert INSTANCE = Mappers.getMapper(PayWalletRechargePackageConvert.class); + + PayWalletRechargePackageDO convert(WalletRechargePackageCreateReqVO bean); + + PayWalletRechargePackageDO convert(WalletRechargePackageUpdateReqVO bean); + + WalletRechargePackageRespVO convert(PayWalletRechargePackageDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java new file mode 100644 index 0000000..a64c217 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.pay.convert.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionRespVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface PayWalletTransactionConvert { + + PayWalletTransactionConvert INSTANCE = Mappers.getMapper(PayWalletTransactionConvert.class); + + PageResult convertPage2(PageResult page); + + PayWalletTransactionDO convert(WalletTransactionCreateReqBO bean); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java new file mode 100644 index 0000000..8f3490f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.app; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 支付应用 DO + * 一个商户下,可能会有多个支付应用。例如说,京东有京东商城、京东到家等等 + * 不过一般来说,一个商户,只有一个应用哈~ + * + * 即 PayMerchantDO : PayAppDO = 1 : n + * + * @author 芋道源码 + */ +@TableName("pay_app") +@KeySequence("pay_app_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayAppDO extends BaseDO { + + /** + * 应用编号,数据库自增 + */ + @TableId + private Long id; + /** + * 应用名 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 支付结果的回调地址 + */ + private String orderNotifyUrl; + /** + * 退款结果的回调地址 + */ + private String refundNotifyUrl; + + /** + * 转账结果的回调地址 + */ + private String transferNotifyUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java new file mode 100644 index 0000000..72387eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.channel; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +/** + * 支付渠道 DO + * 一个应用下,会有多种支付渠道,例如说微信支付、支付宝支付等等 + * + * 即 PayAppDO : PayChannelDO = 1 : n + * + * @author 芋道源码 + */ +@TableName(value = "pay_channel", autoResultMap = true) +@KeySequence("pay_channel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayChannelDO extends TenantBaseDO { + + /** + * 渠道编号,数据库自增 + */ + private Long id; + /** + * 渠道编码 + * + * 枚举 {@link PayChannelEnum} + */ + private String code; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 渠道费率,单位:百分比 + */ + private Double feeRate; + /** + * 备注 + */ + private String remark; + + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + /** + * 支付渠道配置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private PayClientConfig config; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoOrderDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoOrderDO.java new file mode 100644 index 0000000..a22f7c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoOrderDO.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.demo; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 示例订单 + * + * 演示业务系统的订单,如何接入 pay 系统的支付与退款 + * + * @author 芋道源码 + */ +@TableName("pay_demo_order") +@KeySequence("pay_demo_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayDemoOrderDO extends BaseDO { + + /** + * 订单编号,自增 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 商品编号 + */ + private Long spuId; + /** + * 商品名称 + */ + private String spuName; + /** + * 价格,单位:分 + */ + private Integer price; + + // ========== 支付相关字段 ========== + + /** + * 是否支付 + */ + private Boolean payStatus; + /** + * 支付订单编号 + * + * 对接 pay-module-biz 支付服务的支付订单编号,即 PayOrderDO 的 id 编号 + */ + private Long payOrderId; + /** + * 付款时间 + */ + private LocalDateTime payTime; + /** + * 支付渠道 + * + * 对应 PayChannelEnum 枚举 + */ + private String payChannelCode; + + // ========== 退款相关字段 ========== + /** + * 支付退款单号 + */ + private Long payRefundId; + /** + * 退款金额,单位:分 + */ + private Integer refundPrice; + /** + * 退款完成时间 + */ + private LocalDateTime refundTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java new file mode 100644 index 0000000..f465d0b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.demo; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +// TODO 芋艿:需要详细 review +/** + * 示例转账订单 + * + * 演示业务系统的转账业务 + */ +@TableName(value ="pay_demo_transfer", autoResultMap = true) +@KeySequence("pay_demo_transfer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayDemoTransferDO extends BaseDO { + + /** + * 订单编号 + */ + @TableId + private Long id; + + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + + /** + * 转账类型 + *

+ * 枚举 {@link PayTransferTypeEnum} + */ + private Integer type; + + /** + * 转账金额,单位:分 + */ + private Integer price; + + /** + * 收款人姓名 + */ + private String userName; + + /** + * 支付宝登录号 + */ + private String alipayLogonId; + + /** + * 微信 openId + */ + private String openid; + + /** + * 转账状态 + */ + private Integer transferStatus; + + /** + * 转账单编号 + */ + private Long payTransferId; + + /** + * 转账支付成功渠道 + */ + private String payChannelCode; + + /** + * 转账支付时间 + */ + private LocalDateTime transferTime; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java new file mode 100644 index 0000000..a482605 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.notify; + +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 商户支付、退款等的通知 Log + * 每次通知时,都会在该表中,记录一次 Log,方便排查问题 + * + * @author 芋道源码 + */ +@TableName("pay_notify_log") +@KeySequence("pay_notify_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayNotifyLogDO extends BaseDO { + + /** + * 日志编号,自增 + */ + private Long id; + /** + * 通知任务编号 + * + * 关联 {@link PayNotifyTaskDO#getId()} + */ + private Long taskId; + /** + * 第几次被通知 + * + * 对应到 {@link PayNotifyTaskDO#getNotifyTimes()} + */ + private Integer notifyTimes; + /** + * HTTP 响应结果 + */ + private String response; + /** + * 支付通知状态 + * + * 外键 {@link PayNotifyStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java new file mode 100644 index 0000000..7bfabad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.notify; + +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 支付通知 + * 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。 + * + * @author 芋道源码 + */ +@TableName("pay_notify_task") +@KeySequence("pay_notify_task_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class PayNotifyTaskDO extends TenantBaseDO { + + /** + * 通知频率,单位为秒。 + * + * 算上首次的通知,实际是一共 1 + 8 = 9 次。 + */ + public static final Integer[] NOTIFY_FREQUENCY = new Integer[]{ + 15, 15, 30, 180, + 1800, 1800, 1800, 3600 + }; + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + /** + * 通知类型 + * + * 外键 {@link PayNotifyTypeEnum} + */ + private Integer type; + /** + * 数据编号,根据不同 type 进行关联: + * + * 1. {@link PayNotifyTypeEnum#ORDER} 时,关联 {@link PayOrderDO#getId()} + * 2. {@link PayNotifyTypeEnum#REFUND} 时,关联 {@link PayRefundDO#getId()} + */ + private Long dataId; + /** + * 商户订单编号 + */ + private String merchantOrderId; + /** + * 商户转账单编号 + */ + private String merchantTransferId; + /** + * 通知状态 + * + * 外键 {@link PayNotifyStatusEnum} + */ + private Integer status; + /** + * 下一次通知时间 + */ + private LocalDateTime nextNotifyTime; + /** + * 最后一次执行时间 + */ + private LocalDateTime lastExecuteTime; + /** + * 当前通知次数 + */ + private Integer notifyTimes; + /** + * 最大可通知次数 + */ + private Integer maxNotifyTimes; + /** + * 通知地址 + */ + private String notifyUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java new file mode 100644 index 0000000..a51b875 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.order; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 支付订单 DO + * + * @author 芋道源码 + */ +@TableName("pay_order") +@KeySequence("pay_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayOrderDO extends BaseDO { + + /** + * 订单编号,数据库自增 + */ + private Long id; + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + /** + * 渠道编号 + * + * 关联 {@link PayChannelDO#getId()} + */ + private Long channelId; + /** + * 渠道编码 + * + * 枚举 {@link PayChannelEnum} + */ + private String channelCode; + + // ========== 商户相关字段 ========== + + /** + * 商户订单编号 + * + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 + */ + private String merchantOrderId; + /** + * 商品标题 + */ + private String subject; + /** + * 商品描述信息 + */ + private String body; + /** + * 异步通知地址 + */ + private String notifyUrl; + + // ========== 订单相关字段 ========== + + /** + * 支付金额,单位:分 + */ + private Integer price; + /** + * 渠道手续费,单位:百分比 + * + * 冗余 {@link PayChannelDO#getFeeRate()} + */ + private Double channelFeeRate; + /** + * 渠道手续金额,单位:分 + */ + private Integer channelFeePrice; + /** + * 支付状态 + * + * 枚举 {@link PayOrderStatusEnum} + */ + private Integer status; + /** + * 用户 IP + */ + private String userIp; + /** + * 订单失效时间 + */ + private LocalDateTime expireTime; + /** + * 订单支付成功时间 + */ + private LocalDateTime successTime; + /** + * 支付成功的订单拓展单编号 + * + * 关联 {@link PayOrderExtensionDO#getId()} + */ + private Long extensionId; + /** + * 支付成功的外部订单号 + * + * 关联 {@link PayOrderExtensionDO#getNo()} + */ + private String no; + + // ========== 退款相关字段 ========== + /** + * 退款总金额,单位:分 + */ + private Integer refundPrice; + + // ========== 渠道相关字段 ========== + /** + * 渠道用户编号 + * + * 例如说,微信 openid、支付宝账号 + */ + private String channelUserId; + /** + * 渠道订单号 + */ + private String channelOrderNo; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java new file mode 100644 index 0000000..9466243 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.order; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.Map; + +/** + * 支付订单拓展 DO + * + * 每次调用支付渠道,都会生成一条对应记录 + * + * @author 芋道源码 + */ +@TableName(value = "pay_order_extension",autoResultMap = true) +@KeySequence("pay_order_extension_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayOrderExtensionDO extends BaseDO { + + /** + * 订单拓展编号,数据库自增 + */ + private Long id; + /** + * 外部订单号,根据规则生成 + * + * 调用支付渠道时,使用该字段作为对接的订单号: + * 1. 微信支付:对应 JSAPI 支付 的 out_trade_no 字段 + * 2. 支付宝支付:对应 电脑网站支付 的 out_trade_no 字段 + * + * 例如说,P202110132239124200055 + */ + private String no; + /** + * 订单号 + * + * 关联 {@link PayOrderDO#getId()} + */ + private Long orderId; + /** + * 渠道编号 + * + * 关联 {@link PayChannelDO#getId()} + */ + private Long channelId; + /** + * 渠道编码 + */ + private String channelCode; + /** + * 用户 IP + */ + private String userIp; + /** + * 支付状态 + * + * 枚举 {@link PayOrderStatusEnum} + */ + private Integer status; + /** + * 支付渠道的额外参数 + * + * 参见 参数说明 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map channelExtras; + + /** + * 调用渠道的错误码 + */ + private String channelErrorCode; + /** + * 调用渠道报错时,错误信息 + */ + private String channelErrorMsg; + + /** + * 支付渠道的同步/异步通知的内容 + * + * 对应 {@link PayOrderRespDTO#getRawData()} + */ + private String channelNotifyData; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java new file mode 100644 index 0000000..5d9c612 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.refund; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 支付退款单 DO + * 一个支付订单,可以拥有多个支付退款单 + * + * 即 PayOrderDO : PayRefundDO = 1 : n + * + * @author 芋道源码 + */ +@TableName("pay_refund") +@KeySequence("pay_refund_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PayRefundDO extends BaseDO { + + /** + * 退款单编号,数据库自增 + */ + @TableId + private Long id; + /** + * 外部退款号,根据规则生成 + * + * 调用支付渠道时,使用该字段作为对接的退款号: + * 1. 微信退款:对应 申请退款 的 out_refund_no 字段 + * 2. 支付宝退款:对应 的 out_request_no 字段 + */ + private String no; + + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + /** + * 渠道编号 + * + * 关联 {@link PayChannelDO#getId()} + */ + private Long channelId; + /** + * 商户编码 + * + * 枚举 {@link PayChannelEnum} + */ + private String channelCode; + /** + * 订单编号 + * + * 关联 {@link PayOrderDO#getId()} + */ + private Long orderId; + /** + * 支付订单编号 + * + * 冗余 {@link PayOrderDO#getNo()} + */ + private String orderNo; + + // ========== 商户相关字段 ========== + /** + * 商户订单编号 + * + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 + */ + private String merchantOrderId; + /** + * 商户退款订单号 + * + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 + */ + private String merchantRefundId; + /** + * 异步通知地址 + */ + private String notifyUrl; + + // ========== 退款相关字段 ========== + /** + * 退款状态 + * + * 枚举 {@link PayRefundStatusEnum} + */ + private Integer status; + + /** + * 支付金额,单位:分 + */ + private Integer payPrice; + /** + * 退款金额,单位:分 + */ + private Integer refundPrice; + + /** + * 退款原因 + */ + private String reason; + + /** + * 用户 IP + */ + private String userIp; + + // ========== 渠道相关字段 ========== + /** + * 渠道订单号 + * + * 冗余 {@link PayOrderDO#getChannelOrderNo()} + */ + private String channelOrderNo; + /** + * 渠道退款单号 + * + * 1. 微信退款:对应 申请退款 的 refund_id 字段 + * 2. 支付宝退款:没有字段 + */ + private String channelRefundNo; + /** + * 退款成功时间 + */ + private LocalDateTime successTime; + + /** + * 调用渠道的错误码 + */ + private String channelErrorCode; + /** + * 调用渠道的错误提示 + */ + private String channelErrorMsg; + + /** + * 支付渠道的同步/异步通知的内容 + * + * 对应 {@link PayRefundRespDTO#getRawData()} + */ + private String channelNotifyData; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java new file mode 100644 index 0000000..8f3563f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.transfer; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +// TODO 芋艿:需要详细 review +/** + * 转账单 DO + * + * @author jason + */ +@TableName(value ="pay_transfer", autoResultMap = true) +@KeySequence("pay_transfer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayTransferDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 转账单号 + * + */ + private String no; + + /** + * 应用编号 + * + * 关联 {@link PayAppDO#getId()} + */ + private Long appId; + + /** + * 转账渠道编号 + * + * 关联 {@link PayChannelDO#getId()} + */ + private Long channelId; + + /** + * 转账渠道编码 + * + * 枚举 {@link PayChannelEnum} + */ + private String channelCode; + + // ========== 商户相关字段 ========== + /** + * 商户转账单编号 + * + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 + */ + private String merchantTransferId; + + // ========== 转账相关字段 ========== + + /** + * 类型 + * + * 枚举 {@link PayTransferTypeEnum} + */ + private Integer type; + + /** + * 转账标题 + */ + private String subject; + + /** + * 转账金额,单位:分 + */ + private Integer price; + + /** + * 收款人姓名 + */ + private String userName; + + /** + * 转账状态 + * + * 枚举 {@link PayTransferStatusRespEnum} + */ + private Integer status; + + /** + * 订单转账成功时间 + */ + private LocalDateTime successTime; + + // ========== 支付宝转账相关字段 ========== + /** + * 支付宝登录号 + */ + private String alipayLogonId; + + + // ========== 微信转账相关字段 ========== + /** + * 微信 openId + */ + private String openid; + + // ========== 其它字段 ========== + + /** + * 异步通知地址 + */ + private String notifyUrl; + + /** + * 用户 IP + */ + private String userIp; + + /** + * 渠道的额外参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map channelExtras; + + /** + * 渠道转账单号 + */ + private String channelTransferNo; + + /** + * 调用渠道的错误码 + */ + private String channelErrorCode; + /** + * 调用渠道的错误提示 + */ + private String channelErrorMsg; + + /** + * 渠道的同步/异步通知的内容 + * + */ + private String channelNotifyData; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java new file mode 100644 index 0000000..a3c54c9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.wallet; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 会员钱包 DO + * + * @author jason + */ +@TableName(value ="pay_wallet") +@KeySequence("pay_wallet_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayWalletDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 用户 id + * + * 关联 MemberUserDO 的 id 编号 + * 关联 AdminUserDO 的 id 编号 + */ + private Long userId; + /** + * 用户类型, 预留 多商户转帐可能需要用到 + * + * 关联 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 余额,单位分 + */ + private Integer balance; + + /** + * 冻结金额,单位分 + */ + private Integer freezePrice; + + /** + * 累计支出,单位分 + */ + private Integer totalExpense; + /** + * 累计充值,单位分 + */ + private Integer totalRecharge; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargeDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargeDO.java new file mode 100644 index 0000000..a842c95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargeDO.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.wallet; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 会员钱包充值 + */ +@TableName(value ="pay_wallet_recharge") +@KeySequence("pay_wallet_recharge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayWalletRechargeDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 钱包编号 + * + * 关联 {@link PayWalletDO#getId()} + */ + private Long walletId; + + /** + * 用户实际到账余额 + * + * 例如充 100 送 20,则该值是 120 + */ + private Integer totalPrice; + /** + * 实际支付金额 + */ + private Integer payPrice; + /** + * 钱包赠送金额 + */ + private Integer bonusPrice; + + /** + * 充值套餐编号 + * + * 关联 {@link PayWalletRechargeDO#getPackageId()} 字段 + */ + private Long packageId; + + /** + * 是否已支付 + * + * true - 已支付 + * false - 未支付 + */ + private Boolean payStatus; + + /** + * 支付订单编号 + * + * 关联 {@link PayOrderDO#getId()} + */ + private Long payOrderId; + + /** + * 支付成功的支付渠道 + * + * 冗余 {@link PayOrderDO#getChannelCode()} + */ + private String payChannelCode; + /** + * 订单支付时间 + */ + private LocalDateTime payTime; + + /** + * 支付退款单编号 + * + * 关联 {@link PayRefundDO#getId()} + */ + private Long payRefundId; + + /** + * 退款金额,包含赠送金额 + */ + private Integer refundTotalPrice; + /** + * 退款支付金额 + */ + private Integer refundPayPrice; + + /** + * 退款钱包赠送金额 + */ + private Integer refundBonusPrice; + + /** + * 退款时间 + */ + private LocalDateTime refundTime; + + /** + * 退款状态 + * + * 枚举 {@link PayRefundStatusEnum} + */ + private Integer refundStatus; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargePackageDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargePackageDO.java new file mode 100644 index 0000000..72fc43d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletRechargePackageDO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.wallet; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 会员钱包充值套餐 DO + * + * 通过充值套餐时,可以赠送一定金额; + * + * @author 芋道源码 + */ +@TableName(value ="pay_wallet_recharge_package") +@KeySequence("pay_wallet_recharge_package_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayWalletRechargePackageDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 套餐名 + */ + private String name; + + /** + * 支付金额 + */ + private Integer payPrice; + /** + * 赠送金额 + */ + private Integer bonusPrice; + + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java new file mode 100644 index 0000000..654e511 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletTransactionDO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.wallet; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 会员钱包流水 DO + * + * @author jason + */ +@TableName(value ="pay_wallet_transaction") +@KeySequence("pay_wallet_transaction_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class PayWalletTransactionDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 流水号 + */ + private String no; + + /** + * 钱包编号 + * + * 关联 {@link PayWalletDO#getId()} + */ + private Long walletId; + + /** + * 关联业务分类 + * + * 枚举 {@link PayWalletBizTypeEnum#getType()} + */ + private Integer bizType; + + /** + * 关联业务编号 + */ + private String bizId; + + /** + * 流水说明 + */ + private String title; + + /** + * 交易金额,单位分 + * + * 正值表示余额增加,负值表示余额减少 + */ + private Integer price; + + /** + * 交易后余额,单位分 + */ + private Integer balance; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/app/PayAppMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/app/PayAppMapper.java new file mode 100644 index 0000000..c31dba5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/app/PayAppMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.app; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PayAppMapper extends BaseMapperX { + + default PageResult selectPage(PayAppPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(PayAppDO::getName, reqVO.getName()) + .eqIfPresent(PayAppDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayAppDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayAppDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java new file mode 100644 index 0000000..e698498 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.channel; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +@Mapper +public interface PayChannelMapper extends BaseMapperX { + + default PayChannelDO selectByAppIdAndCode(Long appId, String code) { + return selectOne(PayChannelDO::getAppId, appId, PayChannelDO::getCode, code); + } + + default List selectListByAppIds(Collection appIds){ + return selectList(PayChannelDO::getAppId, appIds); + } + + default List selectListByAppId(Long appId, Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(PayChannelDO::getAppId, appId) + .eq(PayChannelDO::getStatus, status)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoOrderMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoOrderMapper.java new file mode 100644 index 0000000..0a92c6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoOrderMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 示例订单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface PayDemoOrderMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .orderByDesc(PayDemoOrderDO::getId)); + } + + default int updateByIdAndPayed(Long id, boolean wherePayed, PayDemoOrderDO updateObj) { + return update(updateObj, new LambdaQueryWrapperX() + .eq(PayDemoOrderDO::getId, id).eq(PayDemoOrderDO::getPayStatus, wherePayed)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoTransferMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoTransferMapper.java new file mode 100644 index 0000000..77c7ba0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoTransferMapper.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PayDemoTransferMapper extends BaseMapperX { + + default PageResult selectPage(PageParam pageParam){ + return selectPage(pageParam, new LambdaQueryWrapperX() + .orderByDesc(PayDemoTransferDO::getId)); + } +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogMapper.java new file mode 100644 index 0000000..8b586df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogMapper.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.notify; + +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface PayNotifyLogMapper extends BaseMapperX { + + default List selectListByTaskId(Long taskId) { + return selectList(PayNotifyLogDO::getTaskId, taskId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskMapper.java new file mode 100644 index 0000000..cc77012 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface PayNotifyTaskMapper extends BaseMapperX { + + /** + * 获得需要通知的 PayNotifyTaskDO 记录。需要满足如下条件: + * + * 1. status 非成功 + * 2. nextNotifyTime 小于当前时间 + * + * @return PayTransactionNotifyTaskDO 数组 + */ + default List selectListByNotify() { + return selectList(new LambdaQueryWrapper() + .in(PayNotifyTaskDO::getStatus, PayNotifyStatusEnum.WAITING.getStatus(), + PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()) + .le(PayNotifyTaskDO::getNextNotifyTime, LocalDateTime.now())); + } + + default PageResult selectPage(PayNotifyTaskPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PayNotifyTaskDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayNotifyTaskDO::getType, reqVO.getType()) + .eqIfPresent(PayNotifyTaskDO::getDataId, reqVO.getDataId()) + .eqIfPresent(PayNotifyTaskDO::getStatus, reqVO.getStatus()) + .eqIfPresent(PayNotifyTaskDO::getMerchantOrderId, reqVO.getMerchantOrderId()) + .betweenIfPresent(PayNotifyTaskDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayNotifyTaskDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderExtensionMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderExtensionMapper.java new file mode 100644 index 0000000..8513c4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderExtensionMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.order; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface PayOrderExtensionMapper extends BaseMapperX { + + default PayOrderExtensionDO selectByNo(String no) { + return selectOne(PayOrderExtensionDO::getNo, no); + } + + default int updateByIdAndStatus(Long id, Integer status, PayOrderExtensionDO update) { + return update(update, new LambdaQueryWrapper() + .eq(PayOrderExtensionDO::getId, id).eq(PayOrderExtensionDO::getStatus, status)); + } + + default List selectListByOrderId(Long orderId) { + return selectList(PayOrderExtensionDO::getOrderId, orderId); + } + + default List selectListByStatusAndCreateTimeGe(Integer status, LocalDateTime minCreateTime) { + return selectList(new LambdaQueryWrapper() + .eq(PayOrderExtensionDO::getStatus, status) + .ge(PayOrderExtensionDO::getCreateTime, minCreateTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java new file mode 100644 index 0000000..95510d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.order; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface PayOrderMapper extends BaseMapperX { + + default PageResult selectPage(PayOrderPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode()) + .likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId()) + .likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo()) + .likeIfPresent(PayOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayOrderDO::getId)); + } + + default List selectList(PayOrderExportReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(PayOrderDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayOrderDO::getChannelCode, reqVO.getChannelCode()) + .likeIfPresent(PayOrderDO::getMerchantOrderId, reqVO.getMerchantOrderId()) + .likeIfPresent(PayOrderDO::getChannelOrderNo, reqVO.getChannelOrderNo()) + .likeIfPresent(PayOrderDO::getNo, reqVO.getNo()) + .eqIfPresent(PayOrderDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayOrderDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayOrderDO::getId)); + } + + default Long selectCountByAppId(Long appId) { + return selectCount(PayOrderDO::getAppId, appId); + } + + default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) { + return selectOne(PayOrderDO::getAppId, appId, + PayOrderDO::getMerchantOrderId, merchantOrderId); + } + + default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) { + return update(update, new LambdaQueryWrapper() + .eq(PayOrderDO::getId, id).eq(PayOrderDO::getStatus, status)); + } + + default List selectListByStatusAndExpireTimeLt(Integer status, LocalDateTime expireTime) { + return selectList(new LambdaQueryWrapper() + .eq(PayOrderDO::getStatus, status) + .lt(PayOrderDO::getExpireTime, expireTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java new file mode 100644 index 0000000..0b620ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.refund; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface PayRefundMapper extends BaseMapperX { + + default Long selectCountByAppId(Long appId) { + return selectCount(PayRefundDO::getAppId, appId); + } + + default PayRefundDO selectByAppIdAndMerchantRefundId(Long appId, String merchantRefundId) { + return selectOne(new LambdaQueryWrapperX() + .eq(PayRefundDO::getAppId, appId) + .eq(PayRefundDO::getMerchantRefundId, merchantRefundId)); + } + + default Long selectCountByAppIdAndOrderId(Long appId, Long orderId, Integer status) { + return selectCount(new LambdaQueryWrapperX() + .eq(PayRefundDO::getAppId, appId) + .eq(PayRefundDO::getOrderId, orderId) + .eq(PayRefundDO::getStatus, status)); + } + + default PayRefundDO selectByAppIdAndNo(Long appId, String no) { + return selectOne(new LambdaQueryWrapperX() + .eq(PayRefundDO::getAppId, appId) + .eq(PayRefundDO::getNo, no)); + } + + default PayRefundDO selectByNo(String no) { + return selectOne(PayRefundDO::getNo, no); + } + + default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) { + return update(update, new LambdaQueryWrapper() + .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status)); + } + + default PageResult selectPage(PayRefundPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode()) + .likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId()) + .likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId()) + .likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo()) + .likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo()) + .eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayRefundDO::getId)); + } + + default List selectList(PayRefundExportReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode()) + .likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId()) + .likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId()) + .likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo()) + .likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo()) + .eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayRefundDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(PayRefundDO::getStatus, status); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java new file mode 100644 index 0000000..af4f6de --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.transfer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface PayTransferMapper extends BaseMapperX { + + default int updateByIdAndStatus(Long id, List status, PayTransferDO updateObj) { + return update(updateObj, new LambdaQueryWrapper() + .eq(PayTransferDO::getId, id).in(PayTransferDO::getStatus, status)); + } + + default PayTransferDO selectByAppIdAndMerchantTransferId(Long appId, String merchantTransferId){ + return selectOne(PayTransferDO::getAppId, appId, + PayTransferDO::getMerchantTransferId, merchantTransferId); + } + + default PayTransferDO selectByNo(String no){ + return selectOne(PayTransferDO::getNo, no); + } + + default PageResult selectPage(PayTransferPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PayTransferDO::getNo, reqVO.getNo()) + .eqIfPresent(PayTransferDO::getAppId, reqVO.getAppId()) + .eqIfPresent(PayTransferDO::getChannelCode, reqVO.getChannelCode()) + .eqIfPresent(PayTransferDO::getMerchantTransferId, reqVO.getMerchantTransferId()) + .eqIfPresent(PayTransferDO::getType, reqVO.getType()) + .eqIfPresent(PayTransferDO::getStatus, reqVO.getStatus()) + .likeIfPresent(PayTransferDO::getUserName, reqVO.getUserName()) + .eqIfPresent(PayTransferDO::getChannelTransferNo, reqVO.getChannelTransferNo()) + .betweenIfPresent(PayTransferDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayTransferDO::getId)); + } + + default List selectListByStatus(Integer status){ + return selectList(PayTransferDO::getStatus, status); + } +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java new file mode 100644 index 0000000..ce67225 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.wallet; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PayWalletMapper extends BaseMapperX { + + default PayWalletDO selectByUserIdAndType(Long userId, Integer userType) { + return selectOne(PayWalletDO::getUserId, userId, + PayWalletDO::getUserType, userType); + } + + default PageResult selectPage(Integer userType, PayWalletPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .inIfPresent(PayWalletDO::getUserId, reqVO.getUserIds()) + .eqIfPresent(PayWalletDO::getUserType, userType) + .betweenIfPresent(PayWalletDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayWalletDO::getId)); + } + + /** + * 当消费退款时候, 更新钱包 + * + * @param id 钱包 id + * @param price 消费金额 + */ + default int updateWhenConsumptionRefund(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" balance = balance + " + price + + ", total_expense = total_expense - " + price) + .eq(PayWalletDO::getId, id); + return update(null, lambdaUpdateWrapper); + } + + /** + * 当消费时候, 更新钱包 + * + * @param price 消费金额 + * @param id 钱包 id + */ + default int updateWhenConsumption(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" balance = balance - " + price + + ", total_expense = total_expense + " + price) + .eq(PayWalletDO::getId, id) + .ge(PayWalletDO::getBalance, price); // cas 逻辑 + return update(null, lambdaUpdateWrapper); + } + + /** + * 当充值的时候,更新钱包 + * + * @param id 钱包 id + * @param price 钱包金额 + */ + default int updateWhenRecharge(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" balance = balance + " + price + + ", total_recharge = total_recharge + " + price) + .eq(PayWalletDO::getId, id); + return update(null, lambdaUpdateWrapper); + } + + /** + * 冻结钱包部分余额 + * + * @param id 钱包 id + * @param price 冻结金额 + */ + default int freezePrice(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" balance = balance - " + price + + ", freeze_price = freeze_price + " + price) + .eq(PayWalletDO::getId, id) + .ge(PayWalletDO::getBalance, price); // cas 逻辑 + return update(null, lambdaUpdateWrapper); + } + + /** + * 解冻钱包余额 + * + * @param id 钱包 id + * @param price 解冻金额 + */ + default int unFreezePrice(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" balance = balance + " + price + + ", freeze_price = freeze_price - " + price) + .eq(PayWalletDO::getId, id) + .ge(PayWalletDO::getFreezePrice, price); // cas 逻辑 + return update(null, lambdaUpdateWrapper); + } + + /** + * 当充值退款时, 更新钱包 + * + * @param id 钱包 id + * @param price 退款金额 + */ + default int updateWhenRechargeRefund(Long id, Integer price){ + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper() + .setSql(" freeze_price = freeze_price - " + price + + ", total_recharge = total_recharge - " + price) + .eq(PayWalletDO::getId, id) + .ge(PayWalletDO::getFreezePrice, price) + .ge(PayWalletDO::getTotalRecharge, price);// cas 逻辑 + return update(null, lambdaUpdateWrapper); + } + + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargeMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargeMapper.java new file mode 100644 index 0000000..f82b885 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargeMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PayWalletRechargeMapper extends BaseMapperX { + + default int updateByIdAndPaid(Long id, boolean wherePayStatus, PayWalletRechargeDO updateObj) { + return update(updateObj, new LambdaQueryWrapperX() + .eq(PayWalletRechargeDO::getId, id).eq(PayWalletRechargeDO::getPayStatus, wherePayStatus)); + } + + default int updateByIdAndRefunded(Long id, Integer whereRefundStatus, PayWalletRechargeDO updateObj) { + return update(updateObj, new LambdaQueryWrapperX() + .eq(PayWalletRechargeDO::getId, id).eq(PayWalletRechargeDO::getRefundStatus, whereRefundStatus)); + } + + default PageResult selectPage(PageParam pageReqVO, Long walletId, Boolean payStatus) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eq(PayWalletRechargeDO::getWalletId, walletId) + .eq(PayWalletRechargeDO::getPayStatus, payStatus) + .orderByDesc(PayWalletRechargeDO::getId)); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargePackageMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargePackageMapper.java new file mode 100644 index 0000000..821908c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargePackageMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.wallet; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackagePageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface PayWalletRechargePackageMapper extends BaseMapperX { + + default PageResult selectPage(WalletRechargePackagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(PayWalletRechargePackageDO::getName, reqVO.getName()) + .eqIfPresent(PayWalletRechargePackageDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(PayWalletRechargePackageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PayWalletRechargePackageDO::getPayPrice)); + } + + default PayWalletRechargePackageDO selectByName(String name) { + return selectOne(PayWalletRechargePackageDO::getName, name); + } + + default List selectListByStatus(Integer status) { + return selectList(PayWalletRechargePackageDO::getStatus, status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java new file mode 100644 index 0000000..212a90c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.wallet; + + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; + +import static cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO.*; + +@Mapper +public interface PayWalletTransactionMapper extends BaseMapperX { + + default PageResult selectPage(Long walletId, Integer type, + PageParam pageParam, LocalDateTime[] createTime) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .eqIfPresent(PayWalletTransactionDO::getWalletId, walletId); + if (Objects.equals(type, TYPE_INCOME)) { + query.gt(PayWalletTransactionDO::getPrice, 0); + } else if (Objects.equals(type, TYPE_EXPENSE)) { + query.lt(PayWalletTransactionDO::getPrice, 0); + } + query.betweenIfPresent(PayWalletTransactionDO::getCreateTime, createTime); + query.orderByDesc(PayWalletTransactionDO::getId); + return selectPage(pageParam, query); + } + + default Integer selectPriceSum(Long walletId, Integer type, LocalDateTime[] createTime) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapperX() + .select("SUM(price) AS priceSum") + .gt(Objects.equals(type, TYPE_INCOME), "price", 0) // 收入 + .lt(Objects.equals(type, TYPE_EXPENSE), "price", 0) // 支出 + .eq("wallet_id", walletId) + .between("create_time", createTime[0], createTime[1])); + // 获得 sum 结果 + Map first = CollUtil.getFirst(result); + return MapUtil.getInt(first, "priceSum", 0); + } + + default PayWalletTransactionDO selectByNo(String no) { + return selectOne(PayWalletTransactionDO::getNo, no); + } + + default PayWalletTransactionDO selectByBiz(String bizId, Integer bizType) { + return selectOne(PayWalletTransactionDO::getBizId, bizId, + PayWalletTransactionDO::getBizType, bizType); + } + +} + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..30081c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.pay.dal.redis; + +/** + * 支付 Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 通知任务的分布式锁 + * + * KEY 格式:pay_notify:lock:%d // 参数来自 DefaultLockKeyBuilder 类 + * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构 + * 过期时间:不固定 + */ + String PAY_NOTIFY_LOCK = "pay_notify:lock:%d"; + + /** + * 支付序号的缓存 + * + * KEY 格式:pay_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String PAY_NO = "pay_no:"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/no/PayNoRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/no/PayNoRedisDAO.java new file mode 100644 index 0000000..f6be6f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/no/PayNoRedisDAO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.dal.redis.no; + +import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.pay.dal.redis.RedisKeyConstants; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + +/** + * 支付序号的 Redis DAO + * + * @author 芋道源码 + */ +@Repository +public class PayNoRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号 + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); + String key = RedisKeyConstants.PAY_NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofMinutes(1L)); + return noPrefix + no; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/notify/PayNotifyLockRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/notify/PayNotifyLockRedisDAO.java new file mode 100644 index 0000000..69fab20 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/notify/PayNotifyLockRedisDAO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.dal.redis.notify; + +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.module.pay.dal.redis.RedisKeyConstants.PAY_NOTIFY_LOCK; + +/** + * 支付通知的锁 Redis DAO + * + * @author 芋道源码 + */ +@Repository +public class PayNotifyLockRedisDAO { + + @Resource + private RedissonClient redissonClient; + + public void lock(Long id, Long timeoutMillis, Runnable runnable) { + String lockKey = formatKey(id); + RLock lock = redissonClient.getLock(lockKey); + try { + lock.lock(timeoutMillis, TimeUnit.MILLISECONDS); + // 执行逻辑 + runnable.run(); + } finally { + lock.unlock(); + } + } + + private static String formatKey(Long id) { + return String.format(PAY_NOTIFY_LOCK, id); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/config/PayJobConfiguration.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/config/PayJobConfiguration.java new file mode 100644 index 0000000..cd6bd0b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/config/PayJobConfiguration.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.pay.framework.job.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +@Configuration(proxyBeanMethods = false) +public class PayJobConfiguration { + + public static final String NOTIFY_THREAD_POOL_TASK_EXECUTOR = "NOTIFY_THREAD_POOL_TASK_EXECUTOR"; + + @Bean(NOTIFY_THREAD_POOL_TASK_EXECUTOR) + public ThreadPoolTaskExecutor notifyThreadPoolTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(8); // 设置核心线程数 + executor.setMaxPoolSize(16); // 设置最大线程数 + executor.setKeepAliveSeconds(60); // 设置空闲时间 + executor.setQueueCapacity(100); // 设置队列大小 + executor.setThreadNamePrefix("notify-task-"); // 配置线程池的前缀 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 进行加载 + executor.initialize(); + return executor; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/core/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/core/package-info.java new file mode 100644 index 0000000..5a5a689 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/job/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.pay.framework.job.core; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/package-info.java new file mode 100644 index 0000000..a128682 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 pay 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.pay.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayConfiguration.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayConfiguration.java new file mode 100644 index 0000000..376cd0a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayConfiguration.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.pay.framework.pay.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(PayProperties.class) +public class PayConfiguration { +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java new file mode 100644 index 0000000..d422b35 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.pay.framework.pay.config; + +import lombok.Data; +import org.hibernate.validator.constraints.URL; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; + +@ConfigurationProperties(prefix = "yudao.pay") +@Validated +@Data +public class PayProperties { + + private static final String ORDER_NO_PREFIX = "P"; + private static final String REFUND_NO_PREFIX = "R"; + + /** + * 支付回调地址 + * + * 实际上,对应的 PayNotifyController 的 notifyOrder 方法的 URL + * + * 回调顺序:支付渠道(支付宝支付、微信支付) => yudao-module-pay 的 orderNotifyUrl 地址 => 业务的 PayAppDO.orderNotifyUrl 地址 + */ + @NotEmpty(message = "支付回调地址不能为空") + @URL(message = "支付回调地址的格式必须是 URL") + private String orderNotifyUrl; + + /** + * 退款回调地址 + * + * 实际上,对应的 PayNotifyController 的 notifyRefund 方法的 URL + * + * 回调顺序:支付渠道(支付宝支付、微信支付) => yudao-module-pay 的 refundNotifyUrl 地址 => 业务的 PayAppDO.notifyRefundUrl 地址 + */ + @NotEmpty(message = "支付回调地址不能为空") + @URL(message = "支付回调地址的格式必须是 URL") + private String refundNotifyUrl; + + /** + * 支付订单 no 的前缀 + */ + @NotEmpty(message = "支付订单 no 的前缀不能为空") + private String orderNoPrefix = ORDER_NO_PREFIX; + + /** + * 退款订单 no 的前缀 + */ + @NotEmpty(message = "退款订单 no 的前缀不能为空") + private String refundNoPrefix = REFUND_NO_PREFIX; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java new file mode 100644 index 0000000..c7be35f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.pay.framework.pay.core; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FOUND; + +/** + * 钱包支付的 PayClient 实现类 + * + * @author jason + */ +@Slf4j +public class WalletPayClient extends AbstractPayClient { + + public static final String USER_ID_KEY = "user_id"; + public static final String USER_TYPE_KEY = "user_type"; + + private PayWalletService wallService; + private PayWalletTransactionService walletTransactionService; + private PayOrderService orderService; + private PayRefundService refundService; + + public WalletPayClient(Long channelId, NonePayClientConfig config) { + super(channelId, PayChannelEnum.WALLET.getCode(), config); + } + + @Override + protected void doInit() { + if (wallService == null) { + wallService = SpringUtil.getBean(PayWalletService.class); + } + if (walletTransactionService == null) { + walletTransactionService = SpringUtil.getBean(PayWalletTransactionService.class); + } + } + + @Override + protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + try { + Long userId = MapUtil.getLong(reqDTO.getChannelExtras(), USER_ID_KEY); + Integer userType = MapUtil.getInt(reqDTO.getChannelExtras(), USER_TYPE_KEY); + Assert.notNull(userId, "用户 id 不能为空"); + Assert.notNull(userType, "用户类型不能为空"); + PayWalletTransactionDO transaction = wallService.orderPay(userId, userType, reqDTO.getOutTradeNo(), + reqDTO.getPrice()); + return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), + transaction.getCreateTime(), + reqDTO.getOutTradeNo(), transaction); + } catch (Throwable ex) { + log.error("[doUnifiedOrder] 失败", ex); + Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); + String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); + if (ex instanceof ServiceException) { + ServiceException serviceException = (ServiceException) ex; + errorCode = serviceException.getCode(); + errorMsg = serviceException.getMessage(); + } + return PayOrderRespDTO.closedOf(String.valueOf(errorCode), errorMsg, + reqDTO.getOutTradeNo(), ""); + } + } + + @Override + protected PayOrderRespDTO doParseOrderNotify(Map params, String body) { + throw new UnsupportedOperationException("钱包支付无支付回调"); + } + + @Override + protected PayOrderRespDTO doGetOrder(String outTradeNo) { + if (orderService == null) { + orderService = SpringUtil.getBean(PayOrderService.class); + } + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); + // 支付交易拓展单不存在, 返回关闭状态 + if (orderExtension == null) { + return PayOrderRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()), + PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, ""); + } + // 关闭状态 + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { + return PayOrderRespDTO.closedOf(orderExtension.getChannelErrorCode(), + orderExtension.getChannelErrorMsg(), outTradeNo, ""); + } + // 成功状态 + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction( + String.valueOf(orderExtension.getOrderId()), PayWalletBizTypeEnum.PAYMENT); + Assert.notNull(walletTransaction, "支付单 {} 钱包流水不能为空", outTradeNo); + return PayOrderRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreator(), + walletTransaction.getCreateTime(), outTradeNo, walletTransaction); + } + // 其它状态为无效状态 + log.error("[doGetOrder] 支付单 {} 的状态不正确", outTradeNo); + throw new IllegalStateException(String.format("支付单[%s] 状态不正确", outTradeNo)); + } + + @Override + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { + try { + PayWalletTransactionDO payWalletTransaction = wallService.orderRefund(reqDTO.getOutRefundNo(), + reqDTO.getRefundPrice(), reqDTO.getReason()); + return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(), + reqDTO.getOutRefundNo(), payWalletTransaction); + } catch (Throwable ex) { + log.error("[doUnifiedRefund] 失败", ex); + Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); + String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); + if (ex instanceof ServiceException) { + ServiceException serviceException = (ServiceException) ex; + errorCode = serviceException.getCode(); + errorMsg = serviceException.getMessage(); + } + return PayRefundRespDTO.failureOf(String.valueOf(errorCode), errorMsg, + reqDTO.getOutRefundNo(), ""); + } + } + + @Override + protected PayRefundRespDTO doParseRefundNotify(Map params, String body) { + throw new UnsupportedOperationException("钱包支付无退款回调"); + } + + @Override + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { + if (refundService == null) { + refundService = SpringUtil.getBean(PayRefundService.class); + } + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); + // 支付退款单不存在, 返回退款失败状态 + if (payRefund == null) { + return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(), + outRefundNo, ""); + } + // 退款失败 + if (PayRefundStatusRespEnum.isFailure(payRefund.getStatus())) { + return PayRefundRespDTO.failureOf(payRefund.getChannelErrorCode(), payRefund.getChannelErrorMsg(), + outRefundNo, ""); + } + // 退款成功 + if (PayRefundStatusRespEnum.isSuccess(payRefund.getStatus())) { + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction( + String.valueOf(payRefund.getId()), PayWalletBizTypeEnum.PAYMENT_REFUND); + Assert.notNull(walletTransaction, "支付退款单 {} 钱包流水不能为空", outRefundNo); + return PayRefundRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreateTime(), + outRefundNo, walletTransaction); + } + // 其它状态为无效状态 + log.error("[doGetRefund] 支付退款单 {} 的状态不正确", outRefundNo); + throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo)); + } + + @Override + public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { + throw new UnsupportedOperationException("待实现"); + } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/config/PayWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/config/PayWebConfiguration.java new file mode 100644 index 0000000..febc2bc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/config/PayWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.pay.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * pay 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class PayWebConfiguration { + + /** + * pay 模块的 API 分组 + */ + @Bean + public GroupedOpenApi payGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("pay"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/package-info.java new file mode 100644 index 0000000..03bfad9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * pay 模块的 web 配置 + */ +package cn.iocoder.yudao.module.pay.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java new file mode 100644 index 0000000..f5f7ebc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.job.notify; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 支付通知 Job + * 通过不断扫描待通知的 PayNotifyTaskDO 记录,回调业务线的回调接口 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class PayNotifyJob implements JobHandler { + + @Resource + private PayNotifyService payNotifyService; + + @Override + @TenantJob + public String execute(String param) throws Exception { + int notifyCount = payNotifyService.executeNotify(); + return String.format("执行支付通知 %s 个", notifyCount); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderExpireJob.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderExpireJob.java new file mode 100644 index 0000000..2a27229 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderExpireJob.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.job.order; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 支付订单的过期 Job + * + * 支付超过过期时间时,支付渠道是不会通知进行过期,所以需要定时进行过期关闭。 + * + * @author 芋道源码 + */ +@Component +public class PayOrderExpireJob implements JobHandler { + + @Resource + private PayOrderService orderService; + + @Override + @TenantJob + public String execute(String param) { + int count = orderService.expireOrder(); + return StrUtil.format("支付过期 {} 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderSyncJob.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderSyncJob.java new file mode 100644 index 0000000..6961b7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/order/PayOrderSyncJob.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.pay.job.order; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + +/** + * 支付订单的同步 Job + * + * 由于支付订单的状态,是由支付渠道异步通知进行同步,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。 + * + * @author 芋道源码 + */ +@Component +public class PayOrderSyncJob implements JobHandler { + + /** + * 同步创建时间在 N 分钟之前的订单 + * + * 为什么同步 10 分钟之前的订单? + * 因为一个订单发起支付,到支付成功,大多数在 10 分钟内,需要保证轮询到。 + * 如果设置为 30、60 或者更大时间范围,会导致轮询的订单太多,影响性能。当然,你也可以根据自己的业务情况来处理。 + */ + private static final Duration CREATE_TIME_DURATION_BEFORE = Duration.ofMinutes(10); + + @Resource + private PayOrderService orderService; + + @Override + @TenantJob + public String execute(String param) { + LocalDateTime minCreateTime = LocalDateTime.now().minus(CREATE_TIME_DURATION_BEFORE); + int count = orderService.syncOrder(minCreateTime); + return StrUtil.format("同步支付订单 {} 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/refund/PayRefundSyncJob.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/refund/PayRefundSyncJob.java new file mode 100644 index 0000000..72f343b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/refund/PayRefundSyncJob.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.pay.job.refund; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 退款订单的同步 Job + * + * 由于退款订单的状态,是由支付渠道异步通知进行同步,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。 + * + * @author 芋道源码 + */ +@Component +public class PayRefundSyncJob implements JobHandler { + + @Resource + private PayRefundService refundService; + + @Override + @TenantJob + public String execute(String param) { + int count = refundService.syncRefund(); + return StrUtil.format("同步退款订单 {} 个", count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java new file mode 100644 index 0000000..191071e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.job.transfer; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 转账订单的同步 Job + * + * 由于转账订单的转账结果,有些渠道是异步通知进行同步的,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。 + * + * @author jason + */ +@Component +public class PayTransferSyncJob implements JobHandler { + + @Resource + private PayTransferService transferService; + + @Override + @TenantJob + public String execute(String param) { + int count = transferService.syncTransfer(); + return StrUtil.format("同步转账订单 {} 个", count); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java new file mode 100644 index 0000000..40ab66d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java @@ -0,0 +1,10 @@ +/** + * pay 模块,我们放支付业务,提供业务的支付能力。 + * 例如说:商户、应用、支付、退款等等 + * + * 1. Controller URL:以 /pay/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 pay_ 开头,方便在数据库中区分 + * + * 注意,由于 Pay 模块和 Trade 模块,容易重名,所以类名都加载 Pay 的前缀~ + */ +package cn.iocoder.yudao.module.pay; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppService.java new file mode 100644 index 0000000..4f9e289 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppService.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.pay.service.app; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 支付应用 Service 接口 + * + * @author 芋艿 + */ +public interface PayAppService { + + /** + * 创建支付应用 + * + * @param createReqVO 创建 + * @return 编号 + */ + Long createApp(@Valid PayAppCreateReqVO createReqVO); + + /** + * 更新支付应用 + * + * @param updateReqVO 更新 + */ + void updateApp(@Valid PayAppUpdateReqVO updateReqVO); + + /** + * 修改应用状态 + * + * @param id 应用编号 + * @param status 状态 + */ + void updateAppStatus(Long id, Integer status); + + /** + * 删除支付应用 + * + * @param id 编号 + */ + void deleteApp(Long id); + + /** + * 获得支付应用 + * + * @param id 编号 + * @return 支付应用 + */ + PayAppDO getApp(Long id); + + /** + * 获得支付应用列表 + * + * @param ids 编号 + * @return 支付应用列表 + */ + List getAppList(Collection ids); + + /** + * 获得支付应用列表 + * + * @return 支付应用列表 + */ + List getAppList(); + + /** + * 获得支付应用分页 + * + * @param pageReqVO 分页查询 + * @return 支付应用分页 + */ + PageResult getAppPage(PayAppPageReqVO pageReqVO); + + /** + * 获得指定编号的商户 Map + * + * @param ids 应用编号集合 + * @return 商户 Map + */ + default Map getAppMap(Collection ids) { + List list = getAppList(ids); + return CollectionUtils.convertMap(list, PayAppDO::getId); + } + + /** + * 支付应用的合法性 + * + * 如果不合法,抛出 {@link ServiceException} 业务异常 + * + * @param id 应用编号 + * @return 应用 + */ + PayAppDO validPayApp(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java new file mode 100644 index 0000000..56087ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceImpl.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.pay.service.app; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; +import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; +import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 支付应用 Service 实现类 + * + * @author aquan + */ +@Service +@Validated +public class PayAppServiceImpl implements PayAppService { + + @Resource + private PayAppMapper appMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖报错 + private PayOrderService orderService; + @Resource + @Lazy // 延迟加载,避免循环依赖报错 + private PayRefundService refundService; + + @Override + public Long createApp(PayAppCreateReqVO createReqVO) { + // 插入 + PayAppDO app = PayAppConvert.INSTANCE.convert(createReqVO); + appMapper.insert(app); + // 返回 + return app.getId(); + } + + @Override + public void updateApp(PayAppUpdateReqVO updateReqVO) { + // 校验存在 + validateAppExists(updateReqVO.getId()); + // 更新 + PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO); + appMapper.updateById(updateObj); + } + + @Override + public void updateAppStatus(Long id, Integer status) { + // 校验商户存在 + validateAppExists(id); + // 更新状态 + appMapper.updateById(new PayAppDO().setId(id).setStatus(status)); + } + + @Override + public void deleteApp(Long id) { + // 校验存在 + validateAppExists(id); + // 校验关联数据是否存在 + if (orderService.getOrderCountByAppId(id) > 0) { + throw exception(APP_EXIST_ORDER_CANT_DELETE); + } + if (refundService.getRefundCountByAppId(id) > 0) { + throw exception(APP_EXIST_REFUND_CANT_DELETE); + } + + // 删除 + appMapper.deleteById(id); + } + + private void validateAppExists(Long id) { + if (appMapper.selectById(id) == null) { + throw exception(APP_NOT_FOUND); + } + } + + @Override + public PayAppDO getApp(Long id) { + return appMapper.selectById(id); + } + + @Override + public List getAppList(Collection ids) { + return appMapper.selectBatchIds(ids); + } + + @Override + public List getAppList() { + return appMapper.selectList(); + } + + @Override + public PageResult getAppPage(PayAppPageReqVO pageReqVO) { + return appMapper.selectPage(pageReqVO); + } + + @Override + public PayAppDO validPayApp(Long id) { + PayAppDO app = appMapper.selectById(id); + // 校验是否存在 + if (app == null) { + throw exception(ErrorCodeConstants.APP_NOT_FOUND); + } + // 校验是否禁用 + if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) { + throw exception(ErrorCodeConstants.APP_IS_DISABLE); + } + return app; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java new file mode 100644 index 0000000..2814966 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.pay.service.channel; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 支付渠道 Service 接口 + * + * @author aquan + */ +public interface PayChannelService { + + /** + * 创建支付渠道 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createChannel(@Valid PayChannelCreateReqVO createReqVO); + + /** + * 更新支付渠道 + * + * @param updateReqVO 更新信息 + */ + void updateChannel(@Valid PayChannelUpdateReqVO updateReqVO); + + /** + * 删除支付渠道 + * + * @param id 编号 + */ + void deleteChannel(Long id); + + /** + * 获得支付渠道 + * + * @param id 编号 + * @return 支付渠道 + */ + PayChannelDO getChannel(Long id); + + /** + * 根据支付应用 ID 集合,获得支付渠道列表 + * + * @param appIds 应用编号集合 + * @return 支付渠道列表 + */ + List getChannelListByAppIds(Collection appIds); + + /** + * 根据条件获取渠道 + * + * @param appId 应用编号 + * @param code 渠道编码 + * @return 数量 + */ + PayChannelDO getChannelByAppIdAndCode(Long appId, String code); + + /** + * 支付渠道的合法性 + * + * 如果不合法,抛出 {@link ServiceException} 业务异常 + * + * @param id 渠道编号 + * @return 渠道信息 + */ + PayChannelDO validPayChannel(Long id); + + /** + * 支付渠道的合法性 + * + * 如果不合法,抛出 {@link ServiceException} 业务异常 + * + * @param appId 应用编号 + * @param code 支付渠道 + * @return 渠道信息 + */ + PayChannelDO validPayChannel(Long appId, String code); + + /** + * 获得指定应用的开启的渠道列表 + * + * @param appId 应用编号 + * @return 渠道列表 + */ + List getEnableChannelList(Long appId); + + /** + * 获得指定编号的支付客户端 + * + * @param id 编号 + * @return 支付客户端 + */ + PayClient getPayClient(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java new file mode 100644 index 0000000..2fe495a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java @@ -0,0 +1,208 @@ +package cn.iocoder.yudao.module.pay.service.channel; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; +import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.validation.Validator; +import java.time.Duration; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 支付渠道 Service 实现类 + * + * @author aquan + */ +@Service +@Slf4j +@Validated +public class PayChannelServiceImpl implements PayChannelService { + + /** + * {@link PayClient} 缓存,通过它异步清空 smsClientFactory + */ + @Getter + private final LoadingCache clientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public PayClient load(Long id) { + // 查询,然后尝试清空 + PayChannelDO channel = payChannelMapper.selectById(id); + if (channel != null) { + payClientFactory.createOrUpdatePayClient(channel.getId(), channel.getCode(), channel.getConfig()); + } + return payClientFactory.getPayClient(id); + } + + }); + + @Resource + private PayClientFactory payClientFactory; + + @Resource + private PayChannelMapper payChannelMapper; + + @Resource + private Validator validator; + + /** + * 初始化,为了注册钱包 + */ + @PostConstruct + public void init() { + payClientFactory.registerPayClientClass(PayChannelEnum.WALLET, WalletPayClient.class); + } + + @Override + public Long createChannel(PayChannelCreateReqVO reqVO) { + // 断言是否有重复的 + PayChannelDO dbChannel = getChannelByAppIdAndCode(reqVO.getAppId(), reqVO.getCode()); + if (dbChannel != null) { + throw exception(CHANNEL_EXIST_SAME_CHANNEL_ERROR); + } + + // 新增渠道 + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO) + .setConfig(parseConfig(reqVO.getCode(), reqVO.getConfig())); + payChannelMapper.insert(channel); + return channel.getId(); + } + + @Override + public void updateChannel(PayChannelUpdateReqVO updateReqVO) { + // 校验存在 + PayChannelDO dbChannel = validateChannelExists(updateReqVO.getId()); + + // 更新 + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO) + .setConfig(parseConfig(dbChannel.getCode(), updateReqVO.getConfig())); + payChannelMapper.updateById(channel); + + // 清空缓存 + clearCache(channel.getId()); + } + + /** + * 解析并校验配置 + * + * @param code 渠道编码 + * @param configStr 配置 + * @return 支付配置 + */ + private PayClientConfig parseConfig(String code, String configStr) { + // 解析配置 + Class payClass = PayChannelEnum.getByCode(code).getConfigClass(); + if (ObjectUtil.isNull(payClass)) { + throw exception(CHANNEL_NOT_FOUND); + } + PayClientConfig config = JsonUtils.parseObject2(configStr, payClass); + Assert.notNull(config); + + // 验证参数 + config.validate(validator); + return config; + } + + @Override + public void deleteChannel(Long id) { + // 校验存在 + validateChannelExists(id); + + // 删除 + payChannelMapper.deleteById(id); + + // 清空缓存 + clearCache(id); + } + + /** + * 删除缓存 + * + * @param id 渠道编号 + */ + private void clearCache(Long id) { + clientCache.invalidate(id); + } + + private PayChannelDO validateChannelExists(Long id) { + PayChannelDO channel = payChannelMapper.selectById(id); + if (channel == null) { + throw exception(CHANNEL_NOT_FOUND); + } + return channel; + } + + @Override + public PayChannelDO getChannel(Long id) { + return payChannelMapper.selectById(id); + } + + @Override + public List getChannelListByAppIds(Collection appIds) { + return payChannelMapper.selectListByAppIds(appIds); + } + + @Override + public PayChannelDO getChannelByAppIdAndCode(Long appId, String code) { + return payChannelMapper.selectByAppIdAndCode(appId, code); + } + + @Override + public PayChannelDO validPayChannel(Long id) { + PayChannelDO channel = payChannelMapper.selectById(id); + validPayChannel(channel); + return channel; + } + + @Override + public PayChannelDO validPayChannel(Long appId, String code) { + PayChannelDO channel = payChannelMapper.selectByAppIdAndCode(appId, code); + validPayChannel(channel); + return channel; + } + + private void validPayChannel(PayChannelDO channel) { + if (channel == null) { + throw exception(CHANNEL_NOT_FOUND); + } + if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) { + throw exception(CHANNEL_IS_DISABLE); + } + } + + @Override + public List getEnableChannelList(Long appId) { + return payChannelMapper.selectListByAppId(appId, CommonStatusEnum.ENABLE.getStatus()); + } + + @Override + public PayClient getPayClient(Long id) { + return clientCache.getUnchecked(id); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java new file mode 100644 index 0000000..cf87025 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.pay.service.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; + +import javax.validation.Valid; + +/** + * 示例订单 Service 接口 + * + * @author 芋道源码 + */ +public interface PayDemoOrderService { + + /** + * 创建示例订单 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemoOrder(Long userId, @Valid PayDemoOrderCreateReqVO createReqVO); + + /** + * 获得示例订单 + * + * @param id 编号 + * @return 示例订单 + */ + PayDemoOrderDO getDemoOrder(Long id); + + /** + * 获得示例订单分页 + * + * @param pageReqVO 分页查询 + * @return 示例订单分页 + */ + PageResult getDemoOrderPage(PageParam pageReqVO); + + /** + * 更新示例订单为已支付 + * + * @param id 编号 + * @param payOrderId 支付订单号 + */ + void updateDemoOrderPaid(Long id, Long payOrderId); + + /** + * 发起示例订单的退款 + * + * @param id 编号 + * @param userIp 用户编号 + */ + void refundDemoOrder(Long id, String userIp); + + /** + * 更新示例订单为已退款 + * + * @param id 编号 + * @param payRefundId 退款订单号 + */ + void updateDemoOrderRefunded(Long id, Long payRefundId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java new file mode 100644 index 0000000..018dd36 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java @@ -0,0 +1,265 @@ +package cn.iocoder.yudao.module.pay.service.demo; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; +import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static cn.hutool.core.util.ObjectUtil.notEqual; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 示例订单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class PayDemoOrderServiceImpl implements PayDemoOrderService { + + /** + * 接入的实力应用编号 + * + * 从 [支付管理 -> 应用信息] 里添加 + */ + private static final Long PAY_APP_ID = 7L; + + /** + * 商品信息 Map + * + * key:商品编号 + * value:[商品名、商品价格] + */ + private final Map spuNames = new HashMap<>(); + + @Resource + private PayOrderApi payOrderApi; + @Resource + private PayRefundApi payRefundApi; + + @Resource + private PayDemoOrderMapper payDemoOrderMapper; + + public PayDemoOrderServiceImpl() { + spuNames.put(1L, new Object[]{"华为手机", 1}); + spuNames.put(2L, new Object[]{"小米电视", 10}); + spuNames.put(3L, new Object[]{"苹果手表", 100}); + spuNames.put(4L, new Object[]{"华硕笔记本", 1000}); + spuNames.put(5L, new Object[]{"蔚来汽车", 200000}); + } + + @Override + public Long createDemoOrder(Long userId, PayDemoOrderCreateReqVO createReqVO) { + // 1.1 获得商品 + Object[] spu = spuNames.get(createReqVO.getSpuId()); + Assert.notNull(spu, "商品({}) 不存在", createReqVO.getSpuId()); + String spuName = (String) spu[0]; + Integer price = (Integer) spu[1]; + // 1.2 插入 demo 订单 + PayDemoOrderDO demoOrder = new PayDemoOrderDO().setUserId(userId) + .setSpuId(createReqVO.getSpuId()).setSpuName(spuName) + .setPrice(price).setPayStatus(false).setRefundPrice(0); + payDemoOrderMapper.insert(demoOrder); + + // 2.1 创建支付单 + Long payOrderId = payOrderApi.createOrder(new PayOrderCreateReqDTO() + .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用 + .setMerchantOrderId(demoOrder.getId().toString()) // 业务的订单编号 + .setSubject(spuName).setBody("").setPrice(price) // 价格信息 + .setExpireTime(addTime(Duration.ofHours(2L)))); // 支付的过期时间 + // 2.2 更新支付单到 demo 订单 + payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(demoOrder.getId()) + .setPayOrderId(payOrderId)); + // 返回 + return demoOrder.getId(); + } + + @Override + public PayDemoOrderDO getDemoOrder(Long id) { + return payDemoOrderMapper.selectById(id); + } + + @Override + public PageResult getDemoOrderPage(PageParam pageReqVO) { + return payDemoOrderMapper.selectPage(pageReqVO); + } + + @Override + public void updateDemoOrderPaid(Long id, Long payOrderId) { + // 校验并获得支付订单(可支付) + PayOrderRespDTO payOrder = validateDemoOrderCanPaid(id, payOrderId); + + // 更新 PayDemoOrderDO 状态为已支付 + int updateCount = payDemoOrderMapper.updateByIdAndPayed(id, false, + new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now()) + .setPayChannelCode(payOrder.getChannelCode())); + if (updateCount == 0) { + throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + } + + /** + * 校验交易订单满足被支付的条件 + * + * 1. 交易订单未支付 + * 2. 支付单已支付 + * + * @param id 交易订单编号 + * @param payOrderId 支付订单编号 + * @return 交易订单 + */ + private PayOrderRespDTO validateDemoOrderCanPaid(Long id, Long payOrderId) { + // 1.1 校验订单是否存在 + PayDemoOrderDO order = payDemoOrderMapper.selectById(id); + if (order == null) { + throw exception(DEMO_ORDER_NOT_FOUND); + } + // 1.2 校验订单未支付 + if (order.getPayStatus()) { + log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]", + id, toJsonString(order)); + throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + // 1.3 校验支付订单匹配 + if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 + log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]", + id, payOrderId, toJsonString(order)); + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); + } + + // 2.1 校验支付单是否存在 + PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); + if (payOrder == null) { + log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); + throw exception(PAY_ORDER_NOT_FOUND); + } + // 2.2 校验支付单已支付 + if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { + log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", + id, payOrderId, toJsonString(payOrder)); + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS); + } + // 2.3 校验支付金额一致 + if (notEqual(payOrder.getPrice(), order.getPrice())) { + log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]", + id, payOrderId, toJsonString(order), toJsonString(payOrder)); + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH); + } + // 2.4 校验支付订单匹配(二次) + if (notEqual(payOrder.getMerchantOrderId(), id.toString())) { + log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", + id, payOrderId, toJsonString(payOrder)); + throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); + } + return payOrder; + } + + @Override + public void refundDemoOrder(Long id, String userIp) { + // 1. 校验订单是否可以退款 + PayDemoOrderDO order = validateDemoOrderCanRefund(id); + + // 2.1 生成退款单号 + // 一般来说,用户发起退款的时候,都会单独插入一个售后维权表,然后使用该表的 id 作为 refundId + // 这里我们是个简单的 demo,所以没有售后维权表,直接使用订单 id + "-refund" 来演示 + String refundId = order.getId() + "-refund"; + // 2.2 创建退款单 + Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO() + .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用 + .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 + .setMerchantRefundId(refundId) + .setReason("想退钱").setPrice(order.getPrice()));// 价格信息 + // 2.3 更新退款单到 demo 订单 + payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id) + .setPayRefundId(payRefundId).setRefundPrice(order.getPrice())); + } + + private PayDemoOrderDO validateDemoOrderCanRefund(Long id) { + // 校验订单是否存在 + PayDemoOrderDO order = payDemoOrderMapper.selectById(id); + if (order == null) { + throw exception(DEMO_ORDER_NOT_FOUND); + } + // 校验订单是否支付 + if (!order.getPayStatus()) { + throw exception(DEMO_ORDER_REFUND_FAIL_NOT_PAID); + } + // 校验订单是否已退款 + if (order.getPayRefundId() != null) { + throw exception(DEMO_ORDER_REFUND_FAIL_REFUNDED); + } + return order; + } + + @Override + public void updateDemoOrderRefunded(Long id, Long payRefundId) { + // 1. 校验并获得退款订单(可退款) + PayRefundRespDTO payRefund = validateDemoOrderCanRefunded(id, payRefundId); + // 2.2 更新退款单到 demo 订单 + payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id) + .setRefundTime(payRefund.getSuccessTime())); + } + + private PayRefundRespDTO validateDemoOrderCanRefunded(Long id, Long payRefundId) { + // 1.1 校验示例订单 + PayDemoOrderDO order = payDemoOrderMapper.selectById(id); + if (order == null) { + throw exception(DEMO_ORDER_NOT_FOUND); + } + // 1.2 校验退款订单匹配 + if (Objects.equals(order.getPayRefundId(), payRefundId)) { + log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]", + id, payRefundId, toJsonString(order)); + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); + } + + // 2.1 校验退款订单 + PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId); + if (payRefund == null) { + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND); + } + // 2.2 + if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) { + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS); + } + // 2.3 校验退款金额一致 + if (notEqual(payRefund.getRefundPrice(), order.getPrice())) { + log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]", + id, payRefundId, toJsonString(order), toJsonString(payRefund)); + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH); + } + // 2.4 校验退款订单匹配(二次) + if (notEqual(payRefund.getMerchantOrderId(), id.toString())) { + log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]", + id, payRefundId, toJsonString(payRefund)); + throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); + } + return payRefund; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java new file mode 100644 index 0000000..fb01ec4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.pay.service.demo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; + +import javax.validation.Valid; + +/** + * 示例转账业务 Service 接口 + * + * @author jason + */ +public interface PayDemoTransferService { + + /** + * 创建转账业务示例订单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO createReqVO); + + /** + * 获得转账业务示例订单分页 + * + * @param pageVO 分页查询参数 + */ + PageResult getDemoTransferPage(PageParam pageVO); + + /** + * 更新转账业务示例订单的转账状态 + * + * @param id 编号 + * @param payTransferId 转账单编号 + */ + void updateDemoTransferStatus(Long id, Long payTransferId); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java new file mode 100644 index 0000000..8de98da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.pay.service.demo; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import javax.validation.Validator; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING; + +/** + * 示例转账业务 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class PayDemoTransferServiceImpl implements PayDemoTransferService { + + /** + * 接入的实力应用编号 + + * 从 [支付管理 -> 应用信息] 里添加 + */ + private static final Long TRANSFER_APP_ID = 8L; + @Resource + private PayDemoTransferMapper demoTransferMapper; + @Resource + private PayTransferService payTransferService; + @Resource + private Validator validator; + + @Override + public Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO vo) { + // 1 校验参数 + vo.validate(validator); + // 2 保存示例转账业务表 + PayDemoTransferDO demoTransfer = PayDemoTransferConvert.INSTANCE.convert(vo) + .setAppId(TRANSFER_APP_ID).setTransferStatus(WAITING.getStatus()); + demoTransferMapper.insert(demoTransfer); + return demoTransfer.getId(); + } + + @Override + public PageResult getDemoTransferPage(PageParam pageVO) { + return demoTransferMapper.selectPage(pageVO); + } + + @Override + public void updateDemoTransferStatus(Long id, Long payTransferId) { + PayTransferDO payTransfer = validateDemoTransferStatusCanUpdate(id, payTransferId); + // 更新示例订单状态 + if (payTransfer != null) { + demoTransferMapper.updateById(new PayDemoTransferDO().setId(id) + .setPayTransferId(payTransferId) + .setPayChannelCode(payTransfer.getChannelCode()) + .setTransferStatus(payTransfer.getStatus()) + .setTransferTime(payTransfer.getSuccessTime())); + } + } + + private PayTransferDO validateDemoTransferStatusCanUpdate(Long id, Long payTransferId) { + PayDemoTransferDO demoTransfer = demoTransferMapper.selectById(id); + if (demoTransfer == null) { + throw exception(DEMO_TRANSFER_NOT_FOUND); + } + if (PayTransferStatusEnum.isSuccess(demoTransfer.getTransferStatus()) + || PayTransferStatusEnum.isClosed(demoTransfer.getTransferStatus())) { + // 无需更新返回 null + return null; + } + PayTransferDO transfer = payTransferService.getTransfer(payTransferId); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (!Objects.equals(demoTransfer.getPrice(), transfer.getPrice())) { + throw exception(DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH); + } + if (ObjectUtil.notEqual(transfer.getMerchantTransferId(), id.toString())) { + throw exception(DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR); + } + // TODO 校验账号 + return transfer; + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyService.java new file mode 100644 index 0000000..ed93997 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyService.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.pay.service.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; + +import java.util.List; + +/** + * 回调通知 Service 接口 + * + * @author 芋道源码 + */ +public interface PayNotifyService { + + /** + * 创建回调通知任务 + * + * @param type 类型 + * @param dataId 数据编号 + */ + void createPayNotifyTask(Integer type, Long dataId); + + /** + * 执行回调通知 + * + * 注意,该方法提供给定时任务调用。目前是 yudao-server 进行调用 + * @return 通知数量 + */ + int executeNotify() throws InterruptedException; + + /** + * 获得回调通知 + * + * @param id 编号 + * @return 回调通知 + */ + PayNotifyTaskDO getNotifyTask(Long id); + + /** + * 获得回调通知分页 + * + * @param pageReqVO 分页查询 + * @return 回调通知分页 + */ + PageResult getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO); + + /** + * 获得回调日志列表 + * + * @param taskId 任务编号 + * @return 日志列表 + */ + List getNotifyLogList(Long taskId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java new file mode 100644 index 0000000..1d356cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java @@ -0,0 +1,308 @@ +package cn.iocoder.yudao.module.pay.service.notify; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper; +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; +import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration.NOTIFY_THREAD_POOL_TASK_EXECUTOR; + +/** + * 支付通知 Core Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Valid +@Slf4j +public class PayNotifyServiceImpl implements PayNotifyService { + + /** + * 通知超时时间,单位:秒 + */ + public static final int NOTIFY_TIMEOUT = 120; + /** + * {@link #NOTIFY_TIMEOUT} 的毫秒 + */ + public static final long NOTIFY_TIMEOUT_MILLIS = 120 * DateUtils.SECOND_MILLIS; + + @Resource + @Lazy // 循环依赖,避免报错 + private PayOrderService orderService; + @Resource + @Lazy // 循环依赖,避免报错 + private PayRefundService refundService; + @Resource + @Lazy // 循环依赖,避免报错 + private PayTransferService transferService; + + @Resource + private PayNotifyTaskMapper notifyTaskMapper; + @Resource + private PayNotifyLogMapper notifyLogMapper; + + @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR) + private ThreadPoolTaskExecutor threadPoolTaskExecutor; + + @Resource + private PayNotifyLockRedisDAO notifyLockCoreRedisDAO; + + @Override + @Transactional(rollbackFor = Exception.class) + public void createPayNotifyTask(Integer type, Long dataId) { + PayNotifyTaskDO task = new PayNotifyTaskDO().setType(type).setDataId(dataId); + task.setStatus(PayNotifyStatusEnum.WAITING.getStatus()).setNextNotifyTime(LocalDateTime.now()) + .setNotifyTimes(0).setMaxNotifyTimes(PayNotifyTaskDO.NOTIFY_FREQUENCY.length + 1); + // 补充 appId + notifyUrl 字段 + if (Objects.equals(task.getType(), PayNotifyTypeEnum.ORDER.getType())) { + PayOrderDO order = orderService.getOrder(task.getDataId()); // 不进行非空判断,有问题直接异常 + task.setAppId(order.getAppId()). + setMerchantOrderId(order.getMerchantOrderId()).setNotifyUrl(order.getNotifyUrl()); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { + PayRefundDO refundDO = refundService.getRefund(task.getDataId()); + task.setAppId(refundDO.getAppId()) + .setMerchantOrderId(refundDO.getMerchantOrderId()).setNotifyUrl(refundDO.getNotifyUrl()); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) { + PayTransferDO transfer = transferService.getTransfer(task.getDataId()); + task.setAppId(transfer.getAppId()).setMerchantTransferId(transfer.getMerchantTransferId()) + .setNotifyUrl(transfer.getNotifyUrl()); + } + + // 执行插入 + notifyTaskMapper.insert(task); + + // 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + executeNotify(task); + } + }); + } + + @Override + public int executeNotify() throws InterruptedException { + // 获得需要通知的任务 + List tasks = notifyTaskMapper.selectListByNotify(); + if (CollUtil.isEmpty(tasks)) { + return 0; + } + + // 遍历,逐个通知 + CountDownLatch latch = new CountDownLatch(tasks.size()); + tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> { + try { + executeNotify(task); + } finally { + latch.countDown(); + } + })); + // 等待完成 + awaitExecuteNotify(latch); + // 返回执行完成的任务数(成功 + 失败) + return tasks.size(); + } + + /** + * 等待全部支付通知的完成 + * 每 1 秒会打印一次剩余任务数量 + * + * @param latch Latch + * @throws InterruptedException 如果被打断 + */ + private void awaitExecuteNotify(CountDownLatch latch) throws InterruptedException { + long size = latch.getCount(); + for (int i = 0; i < NOTIFY_TIMEOUT; i++) { + if (latch.await(1L, TimeUnit.SECONDS)) { + return; + } + log.info("[awaitExecuteNotify][任务处理中, 总任务数({}) 剩余任务数({})]", size, latch.getCount()); + } + log.error("[awaitExecuteNotify][任务未处理完,总任务数({}) 剩余任务数({})]", size, latch.getCount()); + } + + /** + * 同步执行单个支付通知 + * + * @param task 通知任务 + */ + public void executeNotify(PayNotifyTaskDO task) { + // 分布式锁,避免并发问题 + notifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { + // 校验,当前任务是否已经被通知过 + // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。 + // 因此,此处我们通过第 notifyTimes 通知次数是否匹配来判断 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + if (ObjectUtil.notEqual(task.getNotifyTimes(), dbTask.getNotifyTimes())) { + log.warn("[executeNotifySync][task({}) 任务被忽略,原因是它的通知不是第 ({}) 次,可能是因为并发执行了]", + JsonUtils.toJsonString(task), dbTask.getNotifyTimes()); + return; + } + + // 执行通知 + getSelf().executeNotify0(dbTask); + }); + } + + @Transactional(rollbackFor = Exception.class) + public void executeNotify0(PayNotifyTaskDO task) { + // 发起回调 + CommonResult invokeResult = null; + Throwable invokeException = null; + try { + invokeResult = executeNotifyInvoke(task); + } catch (Throwable e) { + invokeException = e; + } + + // 处理结果 + Integer newStatus = processNotifyResult(task, invokeResult, invokeException); + + // 记录 PayNotifyLog 日志 + String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : + JsonUtils.toJsonString(invokeResult); + notifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) + .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); + } + + /** + * 执行单个支付任务的 HTTP 调用 + * + * @param task 通知任务 + * @return HTTP 响应 + */ + private CommonResult executeNotifyInvoke(PayNotifyTaskDO task) { + // 拼接 body 参数 + Object request; + if (Objects.equals(task.getType(), PayNotifyTypeEnum.ORDER.getType())) { + request = PayOrderNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) + .payOrderId(task.getDataId()).build(); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { + request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) + .payRefundId(task.getDataId()).build(); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) { + request = new PayTransferNotifyReqDTO().setMerchantTransferId(task.getMerchantTransferId()) + .setPayTransferId(task.getDataId()); + } else { + throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task)); + } + // 拼接 header 参数 + Map headers = new HashMap<>(); + TenantUtils.addTenantHeader(headers, task.getTenantId()); + + // 发起请求 + try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl()) + .body(JsonUtils.toJsonString(request)).addHeaders(headers) + .timeout((int) NOTIFY_TIMEOUT_MILLIS).execute()) { + // 解析结果 + return JsonUtils.parseObject(response.body(), CommonResult.class); + } + } + + /** + * 处理并更新通知结果 + * + * @param task 通知任务 + * @param invokeResult 通知结果 + * @param invokeException 通知异常 + * @return 最终任务的状态 + */ + @VisibleForTesting + Integer processNotifyResult(PayNotifyTaskDO task, CommonResult invokeResult, Throwable invokeException) { + // 设置通用的更新 PayNotifyTaskDO 的字段 + PayNotifyTaskDO updateTask = new PayNotifyTaskDO() + .setId(task.getId()) + .setLastExecuteTime(LocalDateTime.now()) + .setNotifyTimes(task.getNotifyTimes() + 1); + + // 情况一:调用成功 + if (invokeResult != null && invokeResult.isSuccess()) { + updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); + notifyTaskMapper.updateById(updateTask); + return updateTask.getStatus(); + } + + // 情况二:调用失败、调用异常 + // 2.1 超过最大回调次数 + if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { + updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); + notifyTaskMapper.updateById(updateTask); + return updateTask.getStatus(); + } + // 2.2 未超过最大回调次数 + updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()]))); + updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() + : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); + notifyTaskMapper.updateById(updateTask); + return updateTask.getStatus(); + } + + @Override + public PayNotifyTaskDO getNotifyTask(Long id) { + return notifyTaskMapper.selectById(id); + } + + @Override + public PageResult getNotifyTaskPage(PayNotifyTaskPageReqVO pageReqVO) { + return notifyTaskMapper.selectPage(pageReqVO); + } + + @Override + public List getNotifyLogList(Long taskId) { + return notifyLogMapper.selectListByTaskId(taskId); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayNotifyServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java new file mode 100644 index 0000000..1a7bf31 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.pay.service.order; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +/** + * 支付订单 Service 接口 + * + * @author aquan + */ +public interface PayOrderService { + + /** + * 获得支付订单 + * + * @param id 编号 + * @return 支付订单 + */ + PayOrderDO getOrder(Long id); + + /** + * 获得支付订单 + * + * @param appId 应用编号 + * @param merchantOrderId 商户订单编号 + * @return 支付订单 + */ + PayOrderDO getOrder(Long appId, String merchantOrderId); + + /** + * 获得支付订单列表 + * + * @param ids 编号数组 + * @return 支付订单列表 + */ + List getOrderList(Collection ids); + + /** + * 获得指定应用的订单数量 + * + * @param appId 应用编号 + * @return 订单数量 + */ + Long getOrderCountByAppId(Long appId); + + /** + * 获得支付订单分页 + * + * @param pageReqVO 分页查询 + * @return 支付订单分页 + */ + PageResult getOrderPage(PayOrderPageReqVO pageReqVO); + + /** + * 获得支付订单列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 支付订单列表 + */ + List getOrderList(PayOrderExportReqVO exportReqVO); + + /** + * 创建支付单 + * + * @param reqDTO 创建请求 + * @return 支付单编号 + */ + Long createOrder(@Valid PayOrderCreateReqDTO reqDTO); + + /** + * 提交支付 + * 此时,会发起支付渠道的调用 + * + * @param reqVO 提交请求 + * @param userIp 提交 IP + * @return 提交结果 + */ + PayOrderSubmitRespVO submitOrder(@Valid PayOrderSubmitReqVO reqVO, + @NotEmpty(message = "提交 IP 不能为空") String userIp); + + /** + * 通知支付单成功 + * + * @param channelId 渠道编号 + * @param notify 通知 + */ + void notifyOrder(Long channelId, PayOrderRespDTO notify); + + /** + * 更新支付订单的退款金额 + * + * @param id 编号 + * @param incrRefundPrice 增加的退款金额 + */ + void updateOrderRefundPrice(Long id, Integer incrRefundPrice); + + /** + * 更新支付订单价格 + * + * @param id 支付单编号 + * @param payPrice 支付单价格 + */ + void updatePayOrderPrice(Long id, Integer payPrice); + + /** + * 获得支付订单 + * + * @param id 编号 + * @return 支付订单 + */ + PayOrderExtensionDO getOrderExtension(Long id); + + /** + * 获得支付订单 + * + * @param no 支付订单 no + * @return 支付订单 + */ + PayOrderExtensionDO getOrderExtensionByNo(String no); + + /** + * 同步订单的支付状态 + * + * @param minCreateTime 最小创建时间 + * @return 同步到已支付的订单数量 + */ + int syncOrder(LocalDateTime minCreateTime); + + /** + * 将已过期的订单,状态修改为已关闭 + * + * @return 过期的订单数量 + */ + int expireOrder(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java new file mode 100644 index 0000000..a058b95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java @@ -0,0 +1,588 @@ +package cn.iocoder.yudao.module.pay.service.order; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper; +import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 支付订单 Service 实现类 + * + * @author aquan + */ +@Service +@Validated +@Slf4j +public class PayOrderServiceImpl implements PayOrderService { + + @Resource + private PayProperties payProperties; + + @Resource + private PayOrderMapper orderMapper; + @Resource + private PayOrderExtensionMapper orderExtensionMapper; + @Resource + private PayNoRedisDAO noRedisDAO; + + @Resource + private PayAppService appService; + @Resource + private PayChannelService channelService; + @Resource + private PayNotifyService notifyService; + + @Override + public PayOrderDO getOrder(Long id) { + return orderMapper.selectById(id); + } + + @Override + public PayOrderDO getOrder(Long appId, String merchantOrderId) { + return orderMapper.selectByAppIdAndMerchantOrderId(appId, merchantOrderId); + } + + @Override + public List getOrderList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return orderMapper.selectBatchIds(ids); + } + + @Override + public Long getOrderCountByAppId(Long appId) { + return orderMapper.selectCountByAppId(appId); + } + + @Override + public PageResult getOrderPage(PayOrderPageReqVO pageReqVO) { + return orderMapper.selectPage(pageReqVO); + } + + @Override + public List getOrderList(PayOrderExportReqVO exportReqVO) { + return orderMapper.selectList(exportReqVO); + } + + @Override + public Long createOrder(PayOrderCreateReqDTO reqDTO) { + // 校验 App + PayAppDO app = appService.validPayApp(reqDTO.getAppId()); + + // 查询对应的支付交易单是否已经存在。如果是,则直接返回 + PayOrderDO order = orderMapper.selectByAppIdAndMerchantOrderId( + reqDTO.getAppId(), reqDTO.getMerchantOrderId()); + if (order != null) { + log.warn("[createOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(), + order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况 + return order.getId(); + } + + // 创建支付交易单 + order = PayOrderConvert.INSTANCE.convert(reqDTO).setAppId(app.getId()) + // 商户相关字段 + .setNotifyUrl(app.getOrderNotifyUrl()) + // 订单相关字段 + .setStatus(PayOrderStatusEnum.WAITING.getStatus()) + // 退款相关字段 + .setRefundPrice(0); + orderMapper.insert(order); + return order.getId(); + } + + @Override // 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了 + public PayOrderSubmitRespVO submitOrder(PayOrderSubmitReqVO reqVO, String userIp) { + // 1.1 获得 PayOrderDO ,并校验其是否存在 + PayOrderDO order = validateOrderCanSubmit(reqVO.getId()); + // 1.32 校验支付渠道是否有效 + PayChannelDO channel = validateChannelCanSubmit(order.getAppId(), reqVO.getChannelCode()); + PayClient client = channelService.getPayClient(channel.getId()); + + // 2. 插入 PayOrderExtensionDO + String no = noRedisDAO.generate(payProperties.getOrderNoPrefix()); + PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp) + .setOrderId(order.getId()).setNo(no) + .setChannelId(channel.getId()).setChannelCode(channel.getCode()) + .setStatus(PayOrderStatusEnum.WAITING.getStatus()); + orderExtensionMapper.insert(orderExtension); + + // 3. 调用三方接口 + PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO, userIp) + // 商户相关的字段 + .setOutTradeNo(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! + .setSubject(order.getSubject()).setBody(order.getBody()) + .setNotifyUrl(genChannelOrderNotifyUrl(channel)) + .setReturnUrl(reqVO.getReturnUrl()) + // 订单相关字段 + .setPrice(order.getPrice()).setExpireTime(order.getExpireTime()); + PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO); + + // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功 + if (unifiedOrderResp != null) { + getSelf().notifyOrder(channel, unifiedOrderResp); + // 如有渠道错误码,则抛出业务异常,提示用户 + if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) { + throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(), + unifiedOrderResp.getChannelErrorMsg()); + } + // 此处需要读取最新的状态 + order = orderMapper.selectById(order.getId()); + } + return PayOrderConvert.INSTANCE.convert(order, unifiedOrderResp); + } + + private PayOrderDO validateOrderCanSubmit(Long id) { + PayOrderDO order = orderMapper.selectById(id); + if (order == null) { // 是否存在 + throw exception(PAY_ORDER_NOT_FOUND); + } + if (PayOrderStatusEnum.isSuccess(order.getStatus())) { // 校验状态,发现已支付 + throw exception(PAY_ORDER_STATUS_IS_SUCCESS); + } + if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); + } + if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期 + throw exception(PAY_ORDER_IS_EXPIRED); + } + + // 【重要】校验是否支付拓展单已支付,只是没有回调、或者数据不正常 + validateOrderActuallyPaid(id); + return order; + } + + /** + * 校验支付订单实际已支付 + * + * @param id 支付编号 + */ + @VisibleForTesting + void validateOrderActuallyPaid(Long id) { + List orderExtensions = orderExtensionMapper.selectListByOrderId(id); + orderExtensions.forEach(orderExtension -> { + // 情况一:校验数据库中的 orderExtension 是不是已支付 + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { + log.warn("[validateOrderCanSubmit][order({}) 的 extension({}) 已支付,可能是数据不一致]", + id, orderExtension.getId()); + throw exception(PAY_ORDER_EXTENSION_IS_PAID); + } + // 情况二:调用三方接口,查询支付单状态,是不是已支付 + PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); + if (payClient == null) { + log.error("[validateOrderCanSubmit][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); + return; + } + PayOrderRespDTO respDTO = payClient.getOrder(orderExtension.getNo()); + if (respDTO != null && PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) { + log.warn("[validateOrderCanSubmit][order({}) 的 PayOrderRespDTO({}) 已支付,可能是回调延迟]", + id, toJsonString(respDTO)); + throw exception(PAY_ORDER_EXTENSION_IS_PAID); + } + }); + } + + private PayChannelDO validateChannelCanSubmit(Long appId, String channelCode) { + // 校验 App + appService.validPayApp(appId); + // 校验支付渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(appId, channelCode); + PayClient client = channelService.getPayClient(channel.getId()); + if (client == null) { + log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); + throw exception(CHANNEL_NOT_FOUND); + } + return channel; + } + + /** + * 根据支付渠道的编码,生成支付渠道的回调地址 + * + * @param channel 支付渠道 + * @return 支付渠道的回调地址 配置地址 + "/" + channel id + */ + private String genChannelOrderNotifyUrl(PayChannelDO channel) { + return payProperties.getOrderNotifyUrl() + "/" + channel.getId(); + } + + @Override + public void notifyOrder(Long channelId, PayOrderRespDTO notify) { + // 校验支付渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(channelId); + // 更新支付订单为已支付 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyOrder(channel, notify)); + } + + /** + * 通知并更新订单的支付结果 + * + * @param channel 支付渠道 + * @param notify 通知 + */ + @Transactional(rollbackFor = Exception.class) + // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyPayOrder(channel, notify) 调用,否则事务不生效 + public void notifyOrder(PayChannelDO channel, PayOrderRespDTO notify) { + // 情况一:支付成功的回调 + if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { + notifyOrderSuccess(channel, notify); + return; + } + // 情况二:支付失败的回调 + if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) { + notifyOrderClosed(channel, notify); + } + // 情况三:WAITING:无需处理 + // 情况四:REFUND:通过退款回调处理 + } + + private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) { + // 1. 更新 PayOrderExtensionDO 支付成功 + PayOrderExtensionDO orderExtension = updateOrderSuccess(notify); + // 2. 更新 PayOrderDO 支付成功 + Boolean paid = updateOrderSuccess(channel, orderExtension, notify); + if (paid) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调 + return; + } + + // 3. 插入支付通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.ORDER.getType(), + orderExtension.getOrderId()); + } + + /** + * 更新 PayOrderExtensionDO 支付成功 + * + * @param notify 通知 + * @return PayOrderExtensionDO 对象 + */ + private PayOrderExtensionDO updateOrderSuccess(PayOrderRespDTO notify) { + // 1. 查询 PayOrderExtensionDO + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); + if (orderExtension == null) { + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); + } + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 + log.info("[updateOrderExtensionSuccess][orderExtension({}) 已经是已支付,无需更新]", orderExtension.getId()); + return orderExtension; + } + if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + + // 2. 更新 PayOrderExtensionDO + int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), + PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + log.info("[updateOrderExtensionSuccess][orderExtension({}) 更新为已支付]", orderExtension.getId()); + return orderExtension; + } + + /** + * 更新 PayOrderDO 支付成功 + * + * @param channel 支付渠道 + * @param orderExtension 支付拓展单 + * @param notify 通知回调 + * @return 是否之前已经成功回调 + */ + private Boolean updateOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension, + PayOrderRespDTO notify) { + // 1. 判断 PayOrderDO 是否处于待支付 + PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); + if (order == null) { + throw exception(PAY_ORDER_NOT_FOUND); + } + if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新 + && Objects.equals(order.getExtensionId(), orderExtension.getId())) { + log.info("[updateOrderExtensionSuccess][order({}) 已经是已支付,无需更新]", order.getId()); + return true; + } + if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); + } + + // 2. 更新 PayOrderDO + int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(), + PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()) + .channelId(channel.getId()).channelCode(channel.getCode()) + .successTime(notify.getSuccessTime()).extensionId(orderExtension.getId()).no(orderExtension.getNo()) + .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId()) + .channelFeeRate(channel.getFeeRate()) + .channelFeePrice(MoneyUtils.calculateRatePrice(order.getPrice(), channel.getFeeRate())) + .build()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); + } + log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId()); + return false; + } + + private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) { + updateOrderExtensionClosed(channel, notify); + } + + private void updateOrderExtensionClosed(PayChannelDO channel, PayOrderRespDTO notify) { + // 1. 查询 PayOrderExtensionDO + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); + if (orderExtension == null) { + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); + } + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新 + log.info("[updateOrderExtensionClosed][orderExtension({}) 已经是支付关闭,无需更新]", orderExtension.getId()); + return; + } + // 一般出现先是支付成功,然后支付关闭,都是全部退款导致关闭的场景。这个情况,我们不更新支付拓展单,只通过退款流程,更新支付单 + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { + log.info("[updateOrderExtensionClosed][orderExtension({}) 是已支付,无需更新为支付关闭]", orderExtension.getId()); + return; + } + if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + + // 2. 更新 PayOrderExtensionDO + int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), + PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) + .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); + if (updateCounts == 0) { // 校验状态,必须是待支付 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + log.info("[updateOrderExtensionClosed][orderExtension({}) 更新为支付关闭]", orderExtension.getId()); + } + + @Override + public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) { + PayOrderDO order = orderMapper.selectById(id); + if (order == null) { + throw exception(PAY_ORDER_NOT_FOUND); + } + if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) { + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR); + } + if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) { + throw exception(REFUND_PRICE_EXCEED); + } + + // 更新订单 + PayOrderDO updateObj = new PayOrderDO() + .setRefundPrice(order.getRefundPrice() + incrRefundPrice) + .setStatus(PayOrderStatusEnum.REFUND.getStatus()); + int updateCount = orderMapper.updateByIdAndStatus(id, order.getStatus(), updateObj); + if (updateCount == 0) { + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR); + } + } + + @Override + public void updatePayOrderPrice(Long id, Integer payPrice) { + PayOrderDO order = orderMapper.selectById(id); + if (order == null) { + throw exception(PAY_ORDER_NOT_FOUND); + } + if (ObjectUtil.notEqual(PayOrderStatusEnum.WAITING.getStatus(), order.getStatus())) { + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); + } + if (ObjectUtil.equal(order.getPrice(), payPrice)) { + return; + } + + // TODO 芋艿:应该 new 出来更新 + order.setPrice(payPrice); + orderMapper.updateById(order); + } + + @Override + public PayOrderExtensionDO getOrderExtension(Long id) { + return orderExtensionMapper.selectById(id); + } + + @Override + public PayOrderExtensionDO getOrderExtensionByNo(String no) { + return orderExtensionMapper.selectByNo(no); + } + + @Override + public int syncOrder(LocalDateTime minCreateTime) { + // 1. 查询指定创建时间前的待支付订单 + List orderExtensions = orderExtensionMapper.selectListByStatusAndCreateTimeGe( + PayOrderStatusEnum.WAITING.getStatus(), minCreateTime); + if (CollUtil.isEmpty(orderExtensions)) { + return 0; + } + // 2. 遍历执行 + int count = 0; + for (PayOrderExtensionDO orderExtension : orderExtensions) { + count += syncOrder(orderExtension) ? 1 : 0; + } + return count; + } + + /** + * 同步单个支付拓展单 + * + * @param orderExtension 支付拓展单 + * @return 是否已支付 + */ + private boolean syncOrder(PayOrderExtensionDO orderExtension) { + try { + // 1.1 查询支付订单信息 + PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); + if (payClient == null) { + log.error("[syncOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); + return false; + } + PayOrderRespDTO respDTO = payClient.getOrder(orderExtension.getNo()); + // 如果查询到订单不存在,PayClient 返回的状态为关闭。但此时不能关闭订单。存在以下一种场景: + // 拉起渠道支付后,短时间内用户未及时完成支付,但是该订单同步定时任务恰巧自动触发了,主动查询结果为订单不存在。 + // 当用户支付成功之后,该订单状态在渠道的回调中无法从已关闭改为已支付,造成重大影响。 + // 考虑此定时任务是异常场景的兜底操作,因此这里不做变更,优先以回调为准。 + // 让订单自动随着支付渠道那边一起等到过期,确保渠道先过期关闭支付入口,而后通过订单过期定时任务关闭自己的订单。 + if (PayOrderStatusRespEnum.isClosed(respDTO.getStatus())) { + return false; + } + // 1.2 回调支付结果 + notifyOrder(orderExtension.getChannelId(), respDTO); + + // 2. 如果是已支付,则返回 true + return PayOrderStatusRespEnum.isSuccess(respDTO.getStatus()); + } catch (Throwable e) { + log.error("[syncOrder][orderExtension({}) 同步支付状态异常]", orderExtension.getId(), e); + return false; + } + } + + @Override + public int expireOrder() { + // 1. 查询过期的待支付订单 + List orders = orderMapper.selectListByStatusAndExpireTimeLt( + PayOrderStatusEnum.WAITING.getStatus(), LocalDateTime.now()); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行 + int count = 0; + for (PayOrderDO order : orders) { + count += expireOrder(order) ? 1 : 0; + } + return count; + } + + /** + * 同步单个支付单 + * + * @param order 支付单 + * @return 是否已过期 + */ + private boolean expireOrder(PayOrderDO order) { + try { + // 1. 需要先处理关联的支付拓展单,避免错误的过期已支付 or 已退款的订单 + List orderExtensions = orderExtensionMapper.selectListByOrderId(order.getId()); + for (PayOrderExtensionDO orderExtension : orderExtensions) { + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { + continue; + } + // 情况一:校验数据库中的 orderExtension 是不是已支付 + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { + log.error("[expireOrder][order({}) 的 extension({}) 已支付,可能是数据不一致]", + order.getId(), orderExtension.getId()); + return false; + } + // 情况二:调用三方接口,查询支付单状态,是不是已支付/已退款 + PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); + if (payClient == null) { + log.error("[expireOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); + return false; + } + PayOrderRespDTO respDTO = payClient.getOrder(orderExtension.getNo()); + if (PayOrderStatusRespEnum.isRefund(respDTO.getStatus())) { + // 补充说明:按道理,应该是 WAITING => SUCCESS => REFUND 状态,如果直接 WAITING => REFUND 状态,说明中间丢了过程 + // 此时,需要人工介入,手工补齐数据,保持 WAITING => SUCCESS => REFUND 的过程 + log.error("[expireOrder][extension({}) 的 PayOrderRespDTO({}) 已退款,可能是回调延迟]", + orderExtension.getId(), toJsonString(respDTO)); + return false; + } + if (PayOrderStatusRespEnum.isSuccess(respDTO.getStatus())) { + notifyOrder(orderExtension.getChannelId(), respDTO); + return false; + } + // 兜底逻辑:将支付拓展单更新为已关闭 + PayOrderExtensionDO updateObj = new PayOrderExtensionDO().setStatus(PayOrderStatusEnum.CLOSED.getStatus()) + .setChannelNotifyData(toJsonString(respDTO)); + if (orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), PayOrderStatusEnum.WAITING.getStatus(), + updateObj) == 0) { + log.error("[expireOrder][extension({}) 更新为支付关闭失败]", orderExtension.getId()); + return false; + } + log.info("[expireOrder][extension({}) 更新为支付关闭成功]", orderExtension.getId()); + } + + // 2. 都没有上述情况,可以安心更新为已关闭 + PayOrderDO updateObj = new PayOrderDO().setStatus(PayOrderStatusEnum.CLOSED.getStatus()); + if (orderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateObj) == 0) { + log.error("[expireOrder][order({}) 更新为支付关闭失败]", order.getId()); + return false; + } + log.info("[expireOrder][order({}) 更新为支付关闭失败]", order.getId()); + return true; + } catch (Throwable e) { + log.error("[expireOrder][order({}) 过期订单异常]", order.getId(), e); + return false; + } + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayOrderServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java new file mode 100644 index 0000000..258cea9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.pay.service.refund; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; + +import java.util.List; + +/** + * 退款订单 Service 接口 + * + * @author aquan + */ +public interface PayRefundService { + + /** + * 获得退款订单 + * + * @param id 编号 + * @return 退款订单 + */ + PayRefundDO getRefund(Long id); + + /** + * 获得退款订单 + * + * @param no 外部退款单号 + * @return 退款订单 + */ + PayRefundDO getRefundByNo(String no); + + /** + * 获得指定应用的退款数量 + * + * @param appId 应用编号 + * @return 退款数量 + */ + Long getRefundCountByAppId(Long appId); + + /** + * 获得退款订单分页 + * + * @param pageReqVO 分页查询 + * @return 退款订单分页 + */ + PageResult getRefundPage(PayRefundPageReqVO pageReqVO); + + /** + * 获得退款订单列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 退款订单列表 + */ + List getRefundList(PayRefundExportReqVO exportReqVO); + + /** + * 创建退款申请 + * + * @param reqDTO 退款申请信息 + * @return 退款单号 + */ + Long createPayRefund(PayRefundCreateReqDTO reqDTO); + + /** + * 渠道的退款通知 + * + * @param channelId 渠道编号 + * @param notify 通知 + */ + void notifyRefund(Long channelId, PayRefundRespDTO notify); + + /** + * 同步渠道退款的退款状态 + * + * @return 同步到状态的退款数量,包括退款成功、退款失败 + */ + int syncRefund(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java new file mode 100644 index 0000000..2085582 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java @@ -0,0 +1,331 @@ +package cn.iocoder.yudao.module.pay.service.refund; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; +import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 退款订单 Service 实现类 + * + * @author jason + */ +@Service +@Slf4j +@Validated +public class PayRefundServiceImpl implements PayRefundService { + + @Resource + private PayProperties payProperties; + + @Resource + private PayRefundMapper refundMapper; + @Resource + private PayNoRedisDAO noRedisDAO; + + @Resource + private PayOrderService orderService; + @Resource + private PayAppService appService; + @Resource + private PayChannelService channelService; + @Resource + private PayNotifyService notifyService; + + @Override + public PayRefundDO getRefund(Long id) { + return refundMapper.selectById(id); + } + + @Override + public PayRefundDO getRefundByNo(String no) { + return refundMapper.selectByNo(no); + } + + @Override + public Long getRefundCountByAppId(Long appId) { + return refundMapper.selectCountByAppId(appId); + } + + @Override + public PageResult getRefundPage(PayRefundPageReqVO pageReqVO) { + return refundMapper.selectPage(pageReqVO); + } + + @Override + public List getRefundList(PayRefundExportReqVO exportReqVO) { + return refundMapper.selectList(exportReqVO); + } + + @Override + public Long createPayRefund(PayRefundCreateReqDTO reqDTO) { + // 1.1 校验 App + PayAppDO app = appService.validPayApp(reqDTO.getAppId()); + // 1.2 校验支付订单 + PayOrderDO order = validatePayOrderCanRefund(reqDTO); + // 1.3 校验支付渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(order.getChannelId()); + PayClient client = channelService.getPayClient(channel.getId()); + if (client == null) { + log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); + throw exception(CHANNEL_NOT_FOUND); + } + // 1.4 校验退款订单是否已经存在 + PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId( + app.getId(), reqDTO.getMerchantRefundId()); + if (refund != null) { + throw exception(REFUND_EXISTS); + } + + // 2.1 插入退款单 + String no = noRedisDAO.generate(payProperties.getRefundNoPrefix()); + refund = PayRefundConvert.INSTANCE.convert(reqDTO) + .setNo(no).setOrderId(order.getId()).setOrderNo(order.getNo()) + .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) + // 商户相关的字段 + .setNotifyUrl(app.getRefundNotifyUrl()) + // 渠道相关字段 + .setChannelOrderNo(order.getChannelOrderNo()) + // 退款相关字段 + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice()); + refundMapper.insert(refund); + try { + // 2.2 向渠道发起退款申请 + PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO() + .setPayPrice(order.getPrice()) + .setRefundPrice(reqDTO.getPrice()) + .setOutTradeNo(order.getNo()) + .setOutRefundNo(refund.getNo()) + .setNotifyUrl(genChannelRefundNotifyUrl(channel)) + .setReason(reqDTO.getReason()); + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); + // 2.3 处理退款返回 + getSelf().notifyRefund(channel, refundRespDTO); + } catch (Throwable e) { + // 注意:这里仅打印异常,不进行抛出。 + // 原因是:虽然调用支付渠道进行退款发生异常(网络请求超时),实际退款成功。这个结果,后续通过退款回调、或者退款轮询补偿可以拿到。 + // 最终,在异常的情况下,支付中心会异步回调业务的退款回调接口,提供退款结果 + log.error("[createPayRefund][退款 id({}) requestDTO({}) 发生异常]", + refund.getId(), reqDTO, e); + } + + // 返回退款编号 + return refund.getId(); + } + + /** + * 校验支付订单是否可以退款 + * + * @param reqDTO 退款申请信息 + * @return 支付订单 + */ + private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { + PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); + if (order == null) { + throw exception(PAY_ORDER_NOT_FOUND); + } + // 校验状态,必须是已支付、或者已退款 + if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) { + throw exception(PAY_ORDER_REFUND_FAIL_STATUS_ERROR); + } + + // 校验金额,退款金额不能大于原定的金额 + if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ + throw exception(REFUND_PRICE_EXCEED); + } + // 是否有退款中的订单 + if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(), + PayRefundStatusEnum.WAITING.getStatus()) > 0) { + throw exception(REFUND_HAS_REFUNDING); + } + return order; + } + + /** + * 根据支付渠道的编码,生成支付渠道的回调地址 + * + * @param channel 支付渠道 + * @return 支付渠道的回调地址 配置地址 + "/" + channel id + */ + private String genChannelRefundNotifyUrl(PayChannelDO channel) { + return payProperties.getRefundNotifyUrl() + "/" + channel.getId(); + } + + @Override + public void notifyRefund(Long channelId, PayRefundRespDTO notify) { + // 校验支付渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(channelId); + // 更新退款订单 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify)); + } + + /** + * 通知并更新订单的退款结果 + * + * @param channel 支付渠道 + * @param notify 通知 + */ + @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效 + public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { + // 情况一:退款成功 + if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { + notifyRefundSuccess(channel, notify); + return; + } + // 情况二:退款失败 + if (PayRefundStatusRespEnum.isFailure(notify.getStatus())) { + notifyRefundFailure(channel, notify); + } + } + + private void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) { + // 1.1 查询 PayRefundDO + PayRefundDO refund = refundMapper.selectByAppIdAndNo( + channel.getAppId(), notify.getOutRefundNo()); + if (refund == null) { + throw exception(REFUND_NOT_FOUND); + } + if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 + log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId()); + return; + } + if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { + throw exception(REFUND_STATUS_IS_NOT_WAITING); + } + // 1.2 更新 PayRefundDO + PayRefundDO updateRefundObj = new PayRefundDO() + .setSuccessTime(notify.getSuccessTime()) + .setChannelRefundNo(notify.getChannelRefundNo()) + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus()) + .setChannelNotifyData(toJsonString(notify)); + int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); + if (updateCounts == 0) { // 校验状态,必须是等待状态 + throw exception(REFUND_STATUS_IS_NOT_WAITING); + } + log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId()); + + // 2. 更新订单 + orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice()); + + // 3. 插入退款通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.REFUND.getType(), + refund.getId()); + } + + private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) { + // 1.1 查询 PayRefundDO + PayRefundDO refund = refundMapper.selectByAppIdAndNo( + channel.getAppId(), notify.getOutRefundNo()); + if (refund == null) { + throw exception(REFUND_NOT_FOUND); + } + if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 + log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId()); + return; + } + if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { + throw exception(REFUND_STATUS_IS_NOT_WAITING); + } + // 1.2 更新 PayRefundDO + PayRefundDO updateRefundObj = new PayRefundDO() + .setChannelRefundNo(notify.getChannelRefundNo()) + .setStatus(PayRefundStatusEnum.FAILURE.getStatus()) + .setChannelNotifyData(toJsonString(notify)) + .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()); + int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); + if (updateCounts == 0) { // 校验状态,必须是等待状态 + throw exception(REFUND_STATUS_IS_NOT_WAITING); + } + log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId()); + + // 2. 插入退款通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.REFUND.getType(), + refund.getId()); + } + + @Override + public int syncRefund() { + // 1. 查询指定创建时间内的待退款订单 + List refunds = refundMapper.selectListByStatus(PayRefundStatusEnum.WAITING.getStatus()); + if (CollUtil.isEmpty(refunds)) { + return 0; + } + // 2. 遍历执行 + int count = 0; + for (PayRefundDO refund : refunds) { + count += syncRefund(refund) ? 1 : 0; + } + return count; + } + + /** + * 同步单个退款订单 + * + * @param refund 退款订单 + * @return 是否同步到 + */ + private boolean syncRefund(PayRefundDO refund) { + try { + // 1.1 查询退款订单信息 + PayClient payClient = channelService.getPayClient(refund.getChannelId()); + if (payClient == null) { + log.error("[syncRefund][渠道编号({}) 找不到对应的支付客户端]", refund.getChannelId()); + return false; + } + PayRefundRespDTO respDTO = payClient.getRefund(refund.getOrderNo(), refund.getNo()); + // 1.2 回调退款结果 + notifyRefund(refund.getChannelId(), respDTO); + + // 2. 如果同步到,则返回 true + return PayRefundStatusEnum.isSuccess(respDTO.getStatus()) + || PayRefundStatusEnum.isFailure(respDTO.getStatus()); + } catch (Throwable e) { + log.error("[syncRefund][refund({}) 同步退款状态异常]", refund.getId(), e); + return false; + } + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayRefundServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java new file mode 100644 index 0000000..9a58cf0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.pay.service.transfer; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; + +import javax.validation.Valid; + +/** + * 转账 Service 接口 + * + * @author jason + */ +public interface PayTransferService { + + /** + * 创建转账单,并发起转账 + * + * 此时,会发起转账渠道的调用 + * + * @param reqVO 请求 + * @param userIp 用户 ip + * @return 渠道的返回结果 + */ + PayTransferDO createTransfer(@Valid PayTransferCreateReqVO reqVO, String userIp); + + /** + * 创建转账单,并发起转账 + * + * @param reqDTO 创建请求 + * @return 转账单编号 + */ + Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); + + /** + * 获取转账单 + * @param id 转账单编号 + */ + PayTransferDO getTransfer(Long id); + + /** + * 获得转账单分页 + * + * @param pageReqVO 分页查询 + * @return 转账单分页 + */ + PageResult getTransferPage(PayTransferPageReqVO pageReqVO); + + /** + * 同步渠道转账单状态 + * + * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的 + */ + int syncTransfer(); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java new file mode 100644 index 0000000..73b726d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java @@ -0,0 +1,301 @@ +package cn.iocoder.yudao.module.pay.service.transfer; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; +import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.*; + +// TODO @jason:等彻底实现完,单测写写; + +/** + * 转账 Service 实现类 + * + * @author jason + */ +@Service +@Slf4j +public class PayTransferServiceImpl implements PayTransferService { + + private static final String TRANSFER_NO_PREFIX = "T"; + + @Resource + private PayTransferMapper transferMapper; + @Resource + private PayAppService appService; + @Resource + private PayChannelService channelService; + @Resource + private PayNotifyService notifyService; + @Resource + private PayNoRedisDAO noRedisDAO; + @Resource + private Validator validator; + + @Override + public PayTransferDO createTransfer(PayTransferCreateReqVO reqVO, String userIp) { + // 1. 校验参数 + reqVO.validate(validator); + + // 2. 创建转账单,发起转账 + PayTransferCreateReqDTO req = INSTANCE.convert(reqVO).setUserIp(userIp); + Long transferId = createTransfer(req); + + // 3. 返回转账单 + return getTransfer(transferId); + } + + @Override + public Long createTransfer(PayTransferCreateReqDTO reqDTO) { + // 1.1 校验 App + PayAppDO payApp = appService.validPayApp(reqDTO.getAppId()); + // 1.2 校验支付渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); + PayClient client = channelService.getPayClient(channel.getId()); + if (client == null) { + log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); + throw exception(CHANNEL_NOT_FOUND); + } + // 1.3 校验转账单已经发起过转账。 + PayTransferDO transfer = validateTransferCanCreate(reqDTO); + + if (transfer == null) { + // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账 + String no = noRedisDAO.generate(TRANSFER_NO_PREFIX); + transfer = INSTANCE.convert(reqDTO) + .setChannelId(channel.getId()) + .setNo(no).setStatus(WAITING.getStatus()) + .setNotifyUrl(payApp.getTransferNotifyUrl()); + transferMapper.insert(transfer); + } + try { + // 3. 调用三方渠道发起转账 + PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer) + .setOutTransferNo(transfer.getNo()); + PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); + // 4. 通知转账结果 + getSelf().notifyTransfer(channel, unifiedTransferResp); + } catch (Throwable e) { + // 注意这里仅打印异常,不进行抛出。 + // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。 + // 或者使用相同 no 再次发起转账请求 + log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e); + } + + return transfer.getId(); + } + + private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) { + PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId()); + if (transfer != null) { + // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果. + if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) { + throw exception(PAY_MERCHANT_TRANSFER_EXISTS); + } + if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) { + throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH); + } + if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) { + throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH); + } + } + // 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等 + return transfer; + } + + @Transactional(rollbackFor = Exception.class) + // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyTransfer(channel, notify) 调用,否则事务不生效 + public void notifyTransfer(PayChannelDO channel, PayTransferRespDTO notify) { + // 转账成功的回调 + if (PayTransferStatusRespEnum.isSuccess(notify.getStatus())) { + notifyTransferSuccess(channel, notify); + } + // 转账关闭的回调 + if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) { + notifyTransferClosed(channel, notify); + } + // 转账处理中的回调 + if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) { + notifyTransferInProgress(channel, notify); + } + // WAITING 状态无需处理 + } + + private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) { + // 1.校验 + PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新 + return; + } + if (!isWaiting(transfer.getStatus())) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); + } + // 2.更新 + int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(), + CollUtil.newArrayList(WAITING.getStatus()), + new PayTransferDO().setStatus(IN_PROGRESS.getStatus())); + if (updateCounts == 0) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); + } + log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId()); + + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); + } + + + private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { + // 1.校验 + PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新 + return; + } + if (!isPendingStatus(transfer.getStatus())) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); + } + // 2.更新 + int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(), + CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()), + new PayTransferDO().setStatus(SUCCESS.getStatus()).setSuccessTime(notify.getSuccessTime()) + .setChannelTransferNo(notify.getChannelTransferNo()) + .setChannelId(channel.getId()).setChannelCode(channel.getCode()) + .setChannelNotifyData(JsonUtils.toJsonString(notify))); + if (updateCounts == 0) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); + } + log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId()); + + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); + } + + private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { + // 1.校验 + PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (isClosed(transfer.getStatus())) { // 如果已是关闭状态,直接返回,不用重复更新 + log.info("[updateTransferClosed][transfer({}) 已经是关闭状态,无需更新]", transfer.getId()); + return; + } + if (!isPendingStatus(transfer.getStatus())) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); + } + + // 2.更新 + int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(), + CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()), + new PayTransferDO().setStatus(CLOSED.getStatus()).setChannelId(channel.getId()) + .setChannelCode(channel.getCode()).setChannelTransferNo(notify.getChannelTransferNo()) + .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()) + .setChannelNotifyData(JsonUtils.toJsonString(notify))); + if (updateCount == 0) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); + } + log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId()); + + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); + + } + + @Override + public PayTransferDO getTransfer(Long id) { + return transferMapper.selectById(id); + } + + @Override + public PageResult getTransferPage(PayTransferPageReqVO pageReqVO) { + return transferMapper.selectPage(pageReqVO); + } + + @Override + public int syncTransfer() { + List list = transferMapper.selectListByStatus(WAITING.getStatus()); + if (CollUtil.isEmpty(list)) { + return 0; + } + int count = 0; + for (PayTransferDO transfer : list) { + count += syncTransfer(transfer) ? 1 : 0; + } + return count; + } + + private boolean syncTransfer(PayTransferDO transfer) { + try { + // 1. 查询转账订单信息 + PayClient payClient = channelService.getPayClient(transfer.getChannelId()); + if (payClient == null) { + log.error("[syncTransfer][渠道编号({}) 找不到对应的支付客户端]", transfer.getChannelId()); + return false; + } + PayTransferRespDTO resp = payClient.getTransfer(transfer.getNo(), + PayTransferTypeEnum.typeOf(transfer.getType())); + + // 2. 回调转账结果 + notifyTransfer(transfer.getChannelId(), resp); + return true; + } catch (Throwable ex) { + log.error("[syncTransfer][transfer({}) 同步转账单状态异常]", transfer.getId(), ex); + return false; + } + } + + private void notifyTransfer(Long channelId, PayTransferRespDTO notify) { + // 校验渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(channelId); + // 通知转账结果给对应的业务 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyTransfer(channel, notify)); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayTransferServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageService.java new file mode 100644 index 0000000..72c5589 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageService.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackagePageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 钱包充值套餐 Service 接口 + * + * @author jason + */ +public interface PayWalletRechargePackageService { + + /** + * 获取钱包充值套餐 + * @param packageId 充值套餐编号 + */ + PayWalletRechargePackageDO getWalletRechargePackage(Long packageId); + + /** + * 校验钱包充值套餐的有效性, 无效的话抛出 ServiceException 异常 + * + * @param packageId 充值套餐编号 + */ + PayWalletRechargePackageDO validWalletRechargePackage(Long packageId); + + /** + * 创建充值套餐 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWalletRechargePackage(@Valid WalletRechargePackageCreateReqVO createReqVO); + + /** + * 更新充值套餐 + * + * @param updateReqVO 更新信息 + */ + void updateWalletRechargePackage(@Valid WalletRechargePackageUpdateReqVO updateReqVO); + + /** + * 删除充值套餐 + * + * @param id 编号 + */ + void deleteWalletRechargePackage(Long id); + + /** + * 获得充值套餐分页 + * + * @param pageReqVO 分页查询 + * @return 充值套餐分页 + */ + PageResult getWalletRechargePackagePage(WalletRechargePackagePageReqVO pageReqVO); + + /** + * 获得充值套餐列表 + * + * @param status 状态 + * @return 充值套餐列表 + */ + List getWalletRechargePackageList(Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageServiceImpl.java new file mode 100644 index 0000000..221919f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargePackageServiceImpl.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackagePageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.rechargepackage.WalletRechargePackageUpdateReqVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargePackageConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargePackageMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; + +/** + * 钱包充值套餐 Service 实现类 + * + * @author jason + */ +@Service +public class PayWalletRechargePackageServiceImpl implements PayWalletRechargePackageService { + + @Resource + private PayWalletRechargePackageMapper walletRechargePackageMapper; + + @Override + public PayWalletRechargePackageDO getWalletRechargePackage(Long packageId) { + return walletRechargePackageMapper.selectById(packageId); + } + + @Override + public PayWalletRechargePackageDO validWalletRechargePackage(Long packageId) { + PayWalletRechargePackageDO rechargePackageDO = walletRechargePackageMapper.selectById(packageId); + if (rechargePackageDO == null) { + throw exception(WALLET_RECHARGE_PACKAGE_NOT_FOUND); + } + if (CommonStatusEnum.DISABLE.getStatus().equals(rechargePackageDO.getStatus())) { + throw exception(WALLET_RECHARGE_PACKAGE_IS_DISABLE); + } + return rechargePackageDO; + } + + @Override + public Long createWalletRechargePackage(WalletRechargePackageCreateReqVO createReqVO) { + // 校验套餐名是否唯一 + validateRechargePackageNameUnique(null, createReqVO.getName()); + + // 插入 + PayWalletRechargePackageDO walletRechargePackage = PayWalletRechargePackageConvert.INSTANCE.convert(createReqVO); + walletRechargePackageMapper.insert(walletRechargePackage); + // 返回 + return walletRechargePackage.getId(); + } + + @Override + public void updateWalletRechargePackage(WalletRechargePackageUpdateReqVO updateReqVO) { + // 校验存在 + validateWalletRechargePackageExists(updateReqVO.getId()); + // 校验套餐名是否唯一 + validateRechargePackageNameUnique(updateReqVO.getId(), updateReqVO.getName()); + + // 更新 + PayWalletRechargePackageDO updateObj = PayWalletRechargePackageConvert.INSTANCE.convert(updateReqVO); + walletRechargePackageMapper.updateById(updateObj); + } + + private void validateRechargePackageNameUnique(Long id, String name) { + if (StrUtil.isBlank(name)) { + return; + } + PayWalletRechargePackageDO rechargePackage = walletRechargePackageMapper.selectByName(name); + if (rechargePackage == null) { + return ; + } + if (id == null) { + throw exception(WALLET_RECHARGE_PACKAGE_NAME_EXISTS); + } + if (!id.equals(rechargePackage.getId())) { + throw exception(WALLET_RECHARGE_PACKAGE_NAME_EXISTS); + } + } + + @Override + public void deleteWalletRechargePackage(Long id) { + // 校验存在 + validateWalletRechargePackageExists(id); + // 删除 + walletRechargePackageMapper.deleteById(id); + } + + private void validateWalletRechargePackageExists(Long id) { + if (walletRechargePackageMapper.selectById(id) == null) { + throw exception(WALLET_RECHARGE_PACKAGE_NOT_FOUND); + } + } + + @Override + public PageResult getWalletRechargePackagePage(WalletRechargePackagePageReqVO pageReqVO) { + return walletRechargePackageMapper.selectPage(pageReqVO); + } + + @Override + public List getWalletRechargePackageList(Integer status) { + return walletRechargePackageMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java new file mode 100644 index 0000000..f2de167 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; + +/** + * 钱包充值 Service 接口 + * + * @author jason + */ +public interface PayWalletRechargeService { + + /** + * 创建钱包充值记录(发起充值) + * + * @param userId 用户 id + * @param userType 用户类型 + * @param createReqVO 钱包充值请求 VO + * @param userIp 用户Ip + * @return 钱包充值记录 + */ + PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp, + AppPayWalletRechargeCreateReqVO createReqVO); + + /** + * 获得钱包充值记录分页 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param pageReqVO 分页请求 + * @param payStatus 是否支付 + * @return 钱包充值记录分页 + */ + PageResult getWalletRechargePackagePage(Long userId, Integer userType, + PageParam pageReqVO, Boolean payStatus); + + /** + * 更新钱包充值成功 + * + * @param id 钱包充值记录 id + * @param payOrderId 支付订单 id + */ + void updateWalletRechargerPaid(Long id, Long payOrderId); + + /** + * 发起钱包充值退款 + * + * @param id 钱包充值编号 + * @param userIp 用户 ip 地址 + */ + void refundWalletRecharge(Long id, String userIp); + + /** + * 更新钱包充值记录为已退款 + * + * @param id 钱包充值 id + * @param payRefundId 退款单id + */ + void updateWalletRechargeRefunded(Long id, Long payRefundId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java new file mode 100644 index 0000000..2de531c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java @@ -0,0 +1,285 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO; +import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Objects; + +import static cn.hutool.core.util.ObjectUtil.notEqual; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert.INSTANCE; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*; + +/** + * 钱包充值 Service 实现类 + * + * @author jason + */ +@Service +@Slf4j +public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { + + /** + * TODO 芋艿:放到 payconfig + */ + private static final Long WALLET_PAY_APP_ID = 8L; + + private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值"; + + @Resource + private PayWalletRechargeMapper walletRechargeMapper; + @Resource + private PayWalletService payWalletService; + @Resource + private PayOrderService payOrderService; + @Resource + private PayRefundService payRefundService; + @Resource + private PayWalletRechargePackageService payWalletRechargePackageService; + + @Override + @Transactional(rollbackFor = Exception.class) + public PayWalletRechargeDO createWalletRecharge(Long userId, Integer userType, String userIp, + AppPayWalletRechargeCreateReqVO reqVO) { + // 1.1 计算充值金额 + int payPrice; + int bonusPrice = 0; + if (Objects.nonNull(reqVO.getPackageId())) { + PayWalletRechargePackageDO rechargePackage = payWalletRechargePackageService.validWalletRechargePackage(reqVO.getPackageId()); + payPrice = rechargePackage.getPayPrice(); + bonusPrice = rechargePackage.getBonusPrice(); + } else { + payPrice = reqVO.getPayPrice(); + } + // 1.2 插入充值记录 + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); + PayWalletRechargeDO recharge = INSTANCE.convert(wallet.getId(), payPrice, bonusPrice, reqVO.getPackageId()); + walletRechargeMapper.insert(recharge); + + // 2.1 创建支付单 + Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO() + .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp) + .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号 + .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("") + .setPrice(recharge.getPayPrice()) + .setExpireTime(addTime(Duration.ofHours(2L)))); // TODO @芋艿:支付超时时间 + // 2.2 更新钱包充值记录中支付订单 + walletRechargeMapper.updateById(new PayWalletRechargeDO().setId(recharge.getId()).setPayOrderId(payOrderId)); + recharge.setPayOrderId(payOrderId); + return recharge; + } + + @Override + public PageResult getWalletRechargePackagePage(Long userId, Integer userType, + PageParam pageReqVO, Boolean payStatus) { + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); + return walletRechargeMapper.selectPage(pageReqVO, wallet.getId(), payStatus); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWalletRechargerPaid(Long id, Long payOrderId) { + // 1.1 获取钱包充值记录 + PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(id); + if (walletRecharge == null) { + log.error("[updateWalletRechargerPaid][钱包充值记录不存在,钱包充值记录 id({})]", id); + throw exception(WALLET_RECHARGE_NOT_FOUND); + } + // 1.2 校验钱包充值是否可以支付 + PayOrderDO payOrderDO = validateWalletRechargerCanPaid(walletRecharge, payOrderId); + + // 2. 更新钱包充值的支付状态 + int updateCount = walletRechargeMapper.updateByIdAndPaid(id, false, + new PayWalletRechargeDO().setId(id).setPayStatus(true).setPayTime(LocalDateTime.now()) + .setPayChannelCode(payOrderDO.getChannelCode())); + if (updateCount == 0) { + throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID); + } + + // 3. 更新钱包余额 + // TODO @jason:这样的话,未来提现会不会把充值的,也提现走哈。类似先充 100,送 110;然后提现 110; + // TODO 需要钱包中加个可提现余额 + payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(id), + PayWalletBizTypeEnum.RECHARGE, walletRecharge.getTotalPrice()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void refundWalletRecharge(Long id, String userIp) { + // 1.1 获取钱包充值记录 + PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(id); + if (walletRecharge == null) { + log.error("[refundWalletRecharge][钱包充值记录不存在,钱包充值记录 id({})]", id); + throw exception(WALLET_RECHARGE_NOT_FOUND); + } + // 1.2 校验钱包充值是否可以发起退款 + PayWalletDO wallet = validateWalletRechargeCanRefund(walletRecharge); + + // 2. 冻结退款的余额,暂时只处理赠送的余额也全部退回 + payWalletService.freezePrice(wallet.getId(), walletRecharge.getTotalPrice()); + + // 3. 创建退款单 + String walletRechargeId = String.valueOf(id); + String refundId = walletRechargeId + "-refund"; + Long payRefundId = payRefundService.createPayRefund(new PayRefundCreateReqDTO() + .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp) + .setMerchantOrderId(walletRechargeId) + .setMerchantRefundId(refundId) + .setReason("想退钱").setPrice(walletRecharge.getPayPrice())); + + // 4. 更新充值记录退款单号 + // TODO @jaosn:一般新建这种 update 对象,建议是,第一个 set id 属性,容易知道以它为更新 + walletRechargeMapper.updateById(new PayWalletRechargeDO().setPayRefundId(payRefundId) + .setRefundStatus(WAITING.getStatus()).setId(walletRecharge.getId())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWalletRechargeRefunded(Long id, Long payRefundId) { + // 1.1 获取钱包充值记录 + PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(id); + if (walletRecharge == null) { + log.error("[updateWalletRechargerPaid][钱包充值记录不存在,钱包充值记录 id({})]", id); + throw exception(WALLET_RECHARGE_NOT_FOUND); + } + // 1.2 校验钱包充值是否可以更新已退款 + PayRefundDO payRefund = validateWalletRechargeCanRefunded(walletRecharge, payRefundId); + + PayWalletRechargeDO updateObj = new PayWalletRechargeDO().setId(id); + // 退款成功 + if (PayRefundStatusEnum.isSuccess(payRefund.getStatus())) { + // 2.1 更新钱包余额 + payWalletService.reduceWalletBalance(walletRecharge.getWalletId(), id, + PayWalletBizTypeEnum.RECHARGE_REFUND, walletRecharge.getTotalPrice()); + + updateObj.setRefundStatus(SUCCESS.getStatus()).setRefundTime(payRefund.getSuccessTime()) + .setRefundTotalPrice(walletRecharge.getTotalPrice()).setRefundPayPrice(walletRecharge.getPayPrice()) + .setRefundBonusPrice(walletRecharge.getBonusPrice()); + } + // 退款失败 + if (PayRefundStatusRespEnum.isFailure(payRefund.getStatus())) { + // 2.2 解冻余额 + payWalletService.unfreezePrice(walletRecharge.getWalletId(), walletRecharge.getTotalPrice()); + + updateObj.setRefundStatus(FAILURE.getStatus()); + } + // 3. 更新钱包充值的退款字段 + walletRechargeMapper.updateByIdAndRefunded(id, WAITING.getStatus(), updateObj); + } + + private PayRefundDO validateWalletRechargeCanRefunded(PayWalletRechargeDO walletRecharge, Long payRefundId) { + // 1. 校验退款订单匹配 + if (notEqual(walletRecharge.getPayRefundId(), payRefundId)) { + log.error("[validateWalletRechargeCanRefunded][钱包充值({}) 退款单不匹配({}),请进行处理!钱包充值的数据是:{}]", + walletRecharge.getId(), payRefundId, toJsonString(walletRecharge)); + throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR); + } + + // 2.1 校验退款订单 + PayRefundDO payRefund = payRefundService.getRefund(payRefundId); + if (payRefund == null) { + log.error("[validateWalletRechargeCanRefunded][payRefund({})不存在]", payRefundId); + throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_NOT_FOUND); + } + // 2.2 校验退款金额一致 + if (notEqual(payRefund.getRefundPrice(), walletRecharge.getPayPrice())) { + log.error("[validateWalletRechargeCanRefunded][钱包({}) payRefund({}) 退款金额不匹配,请进行处理!钱包数据是:{},payRefund 数据是:{}]", + walletRecharge.getId(), payRefundId, toJsonString(walletRecharge), toJsonString(payRefund)); + throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH); + } + // 2.3 校验退款订单商户订单是否匹配 + if (notEqual(payRefund.getMerchantOrderId(), walletRecharge.getId().toString())) { + log.error("[validateWalletRechargeCanRefunded][钱包({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]", + walletRecharge.getId(), payRefundId, toJsonString(payRefund)); + throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR); + } + return payRefund; + } + + private PayWalletDO validateWalletRechargeCanRefund(PayWalletRechargeDO walletRecharge) { + // 校验充值订单是否支付 + if (!walletRecharge.getPayStatus()) { + throw exception(WALLET_RECHARGE_REFUND_FAIL_NOT_PAID); + } + // 校验充值订单是否已退款 + if (walletRecharge.getPayRefundId() != null) { + throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUNDED); + } + // 校验钱包余额是否足够 + PayWalletDO wallet = payWalletService.getWallet(walletRecharge.getWalletId()); + Assert.notNull(wallet, "用户钱包({}) 不存在", wallet.getId()); + if (wallet.getBalance() < walletRecharge.getTotalPrice()) { + throw exception(WALLET_RECHARGE_REFUND_BALANCE_NOT_ENOUGH); + } + // TODO @芋艿:需要考虑下,赠送的金额,会不会导致提现超过; + return wallet; + } + + private PayOrderDO validateWalletRechargerCanPaid(PayWalletRechargeDO walletRecharge, Long payOrderId) { + // 1.1 校验充值记录的支付状态 + if (walletRecharge.getPayStatus()) { + log.error("[validateWalletRechargerCanPaid][钱包({}) 不处于未支付状态! 钱包数据是:{}]", + walletRecharge.getId(), toJsonString(walletRecharge)); + throw exception(WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID); + } + // 1.2 校验支付订单匹配 + if (notEqual(walletRecharge.getPayOrderId(), payOrderId)) { // 支付单号 + log.error("[validateWalletRechargerCanPaid][钱包({}) 支付单不匹配({}),请进行处理! 钱包数据是:{}]", + walletRecharge.getId(), payOrderId, toJsonString(walletRecharge)); + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR); + } + + // 2.1 校验支付单是否存在 + PayOrderDO payOrder = payOrderService.getOrder(payOrderId); + if (payOrder == null) { + log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 不存在,请进行处理!]", + walletRecharge.getId(), payOrderId); + throw exception(PAY_ORDER_NOT_FOUND); + } + // 2.2 校验支付单已支付 + if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { + log.error("[validateWalletRechargerCanPaid][钱包({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", + walletRecharge.getId(), payOrderId, toJsonString(payOrder)); + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS); + } + // 2.3 校验支付金额一致 + if (notEqual(payOrder.getPrice(), walletRecharge.getPayPrice())) { + log.error("[validateDemoOrderCanPaid][钱包({}) payOrder({}) 支付金额不匹配,请进行处理!钱包 数据是:{},payOrder 数据是:{}]", + walletRecharge.getId(), payOrderId, toJsonString(walletRecharge), toJsonString(payOrder)); + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH); + } + // 2.4 校验支付订单的商户订单匹配 + if (notEqual(payOrder.getMerchantOrderId(), walletRecharge.getId().toString())) { + log.error("[validateDemoOrderCanPaid][钱包({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", + walletRecharge.getId(), payOrderId, toJsonString(payOrder)); + throw exception(WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR); + } + return payOrder; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java new file mode 100644 index 0000000..e98d826 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; + +/** + * 钱包 Service 接口 + * + * @author jason + */ +public interface PayWalletService { + + /** + * 获取钱包信息 + *

+ * 如果不存在,则创建钱包。由于用户注册时候不会创建钱包 + * + * @param userId 用户编号 + * @param userType 用户类型 + */ + PayWalletDO getOrCreateWallet(Long userId, Integer userType); + + /** + * 获取钱包信息 + * + * @param walletId 钱包 id + */ + PayWalletDO getWallet(Long walletId); + + /** + * 获得会员钱包分页 + * + * @param pageReqVO 分页查询 + * @return 会员钱包分页 + */ + PageResult getWalletPage(Integer userType, PayWalletPageReqVO pageReqVO); + + /** + * 钱包订单支付 + * + * @param userId 用户 id + * @param userType 用户类型 + * @param outTradeNo 外部订单号 + * @param price 金额 + */ + PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price); + + /** + * 钱包订单支付退款 + * + * @param outRefundNo 外部退款号 + * @param refundPrice 退款金额 + * @param reason 退款原因 + */ + PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason); + + /** + * 扣减钱包余额 + * + * @param walletId 钱包 id + * @param bizId 业务关联 id + * @param bizType 业务关联分类 + * @param price 扣减金额 + * @return 钱包流水 + */ + PayWalletTransactionDO reduceWalletBalance(Long walletId, Long bizId, + PayWalletBizTypeEnum bizType, Integer price); + + /** + * 增加钱包余额 + * + * @param walletId 钱包 id + * @param bizId 业务关联 id + * @param bizType 业务关联分类 + * @param price 增加金额 + * @return 钱包流水 + */ + PayWalletTransactionDO addWalletBalance(Long walletId, String bizId, + PayWalletBizTypeEnum bizType, Integer price); + + /** + * 冻结钱包部分余额 + * + * @param id 钱包编号 + * @param price 冻结金额 + */ + void freezePrice(Long id, Integer price); + + /** + * 解冻钱包余额 + * + * @param id 钱包编号 + * @param price 解冻金额 + */ + void unfreezePrice(Long id, Integer price); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java new file mode 100644 index 0000000..9ebe1ca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java @@ -0,0 +1,208 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.wallet.PayWalletPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT; +import static cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum.PAYMENT_REFUND; + +/** + * 钱包 Service 实现类 + * + * @author jason + */ +@Service +@Slf4j +public class PayWalletServiceImpl implements PayWalletService { + + @Resource + private PayWalletMapper walletMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private PayWalletTransactionService walletTransactionService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private PayOrderService orderService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private PayRefundService refundService; + + @Override + public PayWalletDO getOrCreateWallet(Long userId, Integer userType) { + PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType); + if (wallet == null) { + wallet = new PayWalletDO().setUserId(userId).setUserType(userType) + .setBalance(0).setTotalExpense(0).setTotalRecharge(0); + wallet.setCreateTime(LocalDateTime.now()); + walletMapper.insert(wallet); + } + return wallet; + } + + @Override + public PayWalletDO getWallet(Long walletId) { + return walletMapper.selectById(walletId); + } + + @Override + public PageResult getWalletPage(Integer userType,PayWalletPageReqVO pageReqVO) { + return walletMapper.selectPage(userType, pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) { + // 1. 判断支付交易拓展单是否存 + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); + if (orderExtension == null) { + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); + } + PayWalletDO wallet = getOrCreateWallet(userId, userType); + // 2. 扣减余额 + return reduceWalletBalance(wallet.getId(), orderExtension.getOrderId(), PAYMENT, price); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) { + // 1.1 判断退款单是否存在 + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); + if (payRefund == null) { + throw exception(REFUND_NOT_FOUND); + } + // 1.2 校验是否可以退款 + Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo()); + PayWalletDO wallet = walletMapper.selectById(walletId); + Assert.notNull(wallet, "钱包 {} 不存在", walletId); + + // 2. 增加余额 + return addWalletBalance(walletId, String.valueOf(payRefund.getId()), PAYMENT_REFUND, refundPrice); + } + + /** + * 校验是否能退款 + * + * @param refundId 支付退款单 id + * @param walletPayNo 钱包支付 no + */ + private Long validateWalletCanRefund(Long refundId, String walletPayNo) { + // 1. 校验钱包支付交易存在 + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo); + if (walletTransaction == null) { + throw exception(WALLET_TRANSACTION_NOT_FOUND); + } + // 2. 校验退款是否存在 + PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction( + String.valueOf(refundId), PAYMENT_REFUND); + if (refundTransaction != null) { + throw exception(WALLET_REFUND_EXIST); + } + return walletTransaction.getWalletId(); + } + + @Override + public PayWalletTransactionDO reduceWalletBalance(Long walletId, Long bizId, + PayWalletBizTypeEnum bizType, Integer price) { + // 1. 获取钱包 + PayWalletDO payWallet = getWallet(walletId); + if (payWallet == null) { + log.error("[reduceWalletBalance],用户钱包({})不存在.", walletId); + throw exception(WALLET_NOT_FOUND); + } + + // 2.1 扣除余额 + int updateCounts; + switch (bizType) { + case PAYMENT: { + updateCounts = walletMapper.updateWhenConsumption(payWallet.getId(), price); + break; + } + case RECHARGE_REFUND: { + updateCounts = walletMapper.updateWhenRechargeRefund(payWallet.getId(), price); + break; + } + default: { + // TODO 其它类型待实现 + throw new UnsupportedOperationException("待实现"); + } + } + if (updateCounts == 0) { + throw exception(WALLET_BALANCE_NOT_ENOUGH); + } + // 2.2 生成钱包流水 + Integer afterBalance = payWallet.getBalance() - price; + WalletTransactionCreateReqBO bo = new WalletTransactionCreateReqBO().setWalletId(payWallet.getId()) + .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId)) + .setBizType(bizType.getType()).setTitle(bizType.getDescription()); + return walletTransactionService.createWalletTransaction(bo); + } + + @Override + public PayWalletTransactionDO addWalletBalance(Long walletId, String bizId, + PayWalletBizTypeEnum bizType, Integer price) { + // 1.1 获取钱包 + PayWalletDO payWallet = getWallet(walletId); + if (payWallet == null) { + log.error("[addWalletBalance],用户钱包({})不存在.", walletId); + throw exception(WALLET_NOT_FOUND); + } + // 1.2 更新钱包金额 + switch (bizType) { + case PAYMENT_REFUND: { // 退款更新 + walletMapper.updateWhenConsumptionRefund(payWallet.getId(), price); + break; + } + case RECHARGE: { // 充值更新 + walletMapper.updateWhenRecharge(payWallet.getId(), price); + break; + } + default: { + // TODO 其它类型待实现 + throw new UnsupportedOperationException("待实现"); + } + } + + // 2. 生成钱包流水 + WalletTransactionCreateReqBO transactionCreateReqBO = new WalletTransactionCreateReqBO() + .setWalletId(payWallet.getId()).setPrice(price).setBalance(payWallet.getBalance() + price) + .setBizId(bizId).setBizType(bizType.getType()).setTitle(bizType.getDescription()); + return walletTransactionService.createWalletTransaction(transactionCreateReqBO); + } + + @Override + public void freezePrice(Long id, Integer price) { + int updateCounts = walletMapper.freezePrice(id, price); + if (updateCounts == 0) { + throw exception(WALLET_BALANCE_NOT_ENOUGH); + } + } + + @Override + public void unfreezePrice(Long id, Integer price) { + int updateCounts = walletMapper.unFreezePrice(id, price); + if (updateCounts == 0) { + throw exception(WALLET_FREEZE_PRICE_NOT_ENOUGH); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java new file mode 100644 index 0000000..a698973 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionSummaryRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; + +import javax.validation.Valid; + +import java.time.LocalDateTime; + +/** + * 钱包余额流水 Service 接口 + * + * @author jason + */ +public interface PayWalletTransactionService { + + /** + * 查询钱包余额流水分页 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param pageVO 分页查询参数 + */ + PageResult getWalletTransactionPage(Long userId, Integer userType, + AppPayWalletTransactionPageReqVO pageVO); + + /** + * 查询钱包余额流水分页 + * + * @param pageVO 分页查询参数 + */ + PageResult getWalletTransactionPage(PayWalletTransactionPageReqVO pageVO); + + /** + * 新增钱包余额流水 + * + * @param bo 创建钱包流水 bo + * @return 新建的钱包 do + */ + PayWalletTransactionDO createWalletTransaction(@Valid WalletTransactionCreateReqBO bo); + + /** + * 根据 no,获取钱包余流水 + * + * @param no 流水号 + */ + PayWalletTransactionDO getWalletTransactionByNo(String no); + + /** + * 获取钱包流水 + * + * @param bizId 业务编号 + * @param type 业务类型 + * @return 钱包流水 + */ + PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type); + + /** + * 获得钱包流水统计 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param createTime 时间段 + * @return 钱包流水统计 + */ + AppPayWalletTransactionSummaryRespVO getWalletTransactionSummary(Long userId, Integer userType, + LocalDateTime[] createTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java new file mode 100644 index 0000000..44a8c7c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.pay.service.wallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; +import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionSummaryRespVO; +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; +import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO.TYPE_EXPENSE; +import static cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO.TYPE_INCOME; + +/** + * 钱包流水 Service 实现类 + * + * @author jason + */ +@Service +@Slf4j +@Validated +public class PayWalletTransactionServiceImpl implements PayWalletTransactionService { + + /** + * 钱包流水的 no 前缀 + */ + private static final String WALLET_NO_PREFIX = "W"; + + @Resource + private PayWalletService payWalletService; + @Resource + private PayWalletTransactionMapper payWalletTransactionMapper; + @Resource + private PayNoRedisDAO noRedisDAO; + + @Override + public PageResult getWalletTransactionPage(Long userId, Integer userType, + AppPayWalletTransactionPageReqVO pageVO) { + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); + return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO.getType(), pageVO, pageVO.getCreateTime()); + } + + @Override + public PageResult getWalletTransactionPage(PayWalletTransactionPageReqVO pageVO) { + return payWalletTransactionMapper.selectPage(pageVO.getWalletId(), null, pageVO, null); + } + + @Override + public PayWalletTransactionDO createWalletTransaction(WalletTransactionCreateReqBO bo) { + PayWalletTransactionDO transaction = PayWalletTransactionConvert.INSTANCE.convert(bo) + .setNo(noRedisDAO.generate(WALLET_NO_PREFIX)); + payWalletTransactionMapper.insert(transaction); + return transaction; + } + + @Override + public PayWalletTransactionDO getWalletTransactionByNo(String no) { + return payWalletTransactionMapper.selectByNo(no); + } + + @Override + public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) { + return payWalletTransactionMapper.selectByBiz(bizId, type.getType()); + } + + @Override + public AppPayWalletTransactionSummaryRespVO getWalletTransactionSummary(Long userId, Integer userType, LocalDateTime[] createTime) { + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); + AppPayWalletTransactionSummaryRespVO summary = new AppPayWalletTransactionSummaryRespVO() + .setTotalExpense(1).setTotalIncome(100); + return new AppPayWalletTransactionSummaryRespVO() + .setTotalExpense(payWalletTransactionMapper.selectPriceSum(wallet.getId(), TYPE_EXPENSE, createTime)) + .setTotalIncome(payWalletTransactionMapper.selectPriceSum(wallet.getId(), TYPE_INCOME, createTime)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/WalletTransactionCreateReqBO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/WalletTransactionCreateReqBO.java new file mode 100644 index 0000000..a305ceb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/WalletTransactionCreateReqBO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.pay.service.wallet.bo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 创建钱包流水 BO + * + * @author jason + */ +@Data +public class WalletTransactionCreateReqBO { + + /** + * 钱包编号 + * + */ + @NotNull(message = "钱包编号不能为空") + private Long walletId; + + /** + * 交易金额,单位分 + * + * 正值表示余额增加,负值表示余额减少 + */ + @NotNull(message = "交易金额不能为空") + private Integer price; + + /** + * 交易后余额,单位分 + */ + @NotNull(message = "交易后余额不能为空") + private Integer balance; + + /** + * 关联业务分类 + * + * 枚举 {@link PayWalletBizTypeEnum#getType()} + */ + @NotNull(message = "关联业务分类不能为空") + @InEnum(PayWalletBizTypeEnum.class) + private Integer bizType; + + /** + * 关联业务编号 + */ + @NotEmpty(message = "关联业务编号不能为空") + private String bizId; + + /** + * 流水说明 + */ + @NotEmpty(message = "流水说明不能为空") + private String title; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDOTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDOTest.java new file mode 100644 index 0000000..73b4f6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDOTest.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.pay.dal.dataobject.merchant; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; +import org.junit.jupiter.api.Test; + +public class PayChannelDOTest { + + @Test + public void testSerialization() { + PayChannelDO payChannelDO = new PayChannelDO(); + // 创建配置 + WXPayClientConfig config = new WXPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WXPayClientConfig.API_VERSION_V2); + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); + payChannelDO.setConfig(config); + + // 序列化 + String text = JsonUtils.toJsonString(payChannelDO); + System.out.println(text); + + // 反序列化 + payChannelDO = JsonUtils.parseObject(text, PayChannelDO.class); + System.out.println(payChannelDO.getConfig().getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/mysql/merchant/PayChannelMapperIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/mysql/merchant/PayChannelMapperIntegrationTest.java new file mode 100644 index 0000000..2150a8a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/dal/mysql/merchant/PayChannelMapperIntegrationTest.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.pay.dal.mysql.merchant; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import cn.iocoder.yudao.module.pay.test.BaseDbIntegrationTest; +import org.junit.jupiter.api.Test; + +import javax.annotation.Resource; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.List; + +@Resource +public class PayChannelMapperIntegrationTest extends BaseDbIntegrationTest { + + @Resource + private PayChannelMapper payChannelMapper; + + /** + * 插入 {@link PayChannelEnum#WX_PUB} 初始配置 + */ + @Test + public void testInsertWxPub() throws FileNotFoundException { + PayChannelDO payChannelDO = new PayChannelDO(); + payChannelDO.setCode(PayChannelEnum.WX_PUB.getCode()); + payChannelDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + payChannelDO.setFeeRate(1D); + payChannelDO.setAppId(6L); + // 配置 + WXPayClientConfig config = new WXPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WXPayClientConfig.API_VERSION_V2); + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); + config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); + config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); + config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); + payChannelDO.setConfig(config); + // 执行插入 + payChannelMapper.insert(payChannelDO); + } + + // TODO @ouyang:Zfb 改成 AlipayQr + /** + * 插入 {@link PayChannelEnum#ALIPAY_QR} 初始配置 + */ + @Test + public void testInsertZfb() { + PayChannelDO payChannelDO = new PayChannelDO(); + payChannelDO.setCode(PayChannelEnum.ALIPAY_QR.getCode()); + payChannelDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + payChannelDO.setFeeRate(1D); + payChannelDO.setAppId(6L); + // 配置 + AlipayPayClientConfig config = new AlipayPayClientConfig(); + config.setAppId("2021000118634035"); + config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX); + config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); + config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); + config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); + // 创建客户端 + payChannelDO.setConfig(config); + // 执行插入 + payChannelMapper.insert(payChannelDO); + } + + /** + * 查询所有支付配置,看看是否都是 ok 的 + */ + @Test + public void testSelectList() { + List payChannels = payChannelMapper.selectList(); + System.out.println(payChannels.size()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceIntegrationTest.java new file mode 100644 index 0000000..55a37ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceIntegrationTest.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.pay.service.order; + +import cn.iocoder.yudao.module.pay.service.channel.PayAppServiceImpl; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelServiceImpl; +import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO; +import cn.iocoder.yudao.module.pay.test.BaseDbIntegrationTest; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.pay.config.YudaoPayAutoConfiguration; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; + +@Import({PayOrderServiceImpl.class, PayAppServiceImpl.class, + PayChannelServiceImpl.class, YudaoPayAutoConfiguration.class}) +public class PayOrderServiceIntegrationTest extends BaseDbIntegrationTest { + + @Resource + private PayOrderService payOrderService; + + @Test + public void testCreatePayOrder() { + // 构造请求 + PayOrderCreateReqDTO reqDTO = new PayOrderCreateReqDTO(); + reqDTO.setAppId(6L); + reqDTO.setUserIp("127.0.0.1"); + reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); + reqDTO.setSubject("标题"); + reqDTO.setBody("内容"); + reqDTO.setPrice(100); + reqDTO.setExpireTime(DateUtils.addTime(Duration.ofDays(1))); + // 发起请求 + payOrderService.createPayOrder(reqDTO); + } + + @Test + public void testSubmitPayOrder() { + // 构造请求 + PayOrderSubmitReqDTO reqDTO = new PayOrderSubmitReqDTO(); + reqDTO.setId(10L); + reqDTO.setAppId(6L); + reqDTO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqDTO.setUserIp("127.0.0.1"); + // 发起请求 + payOrderService.submitPayOrder(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/package-info.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/package-info.java new file mode 100644 index 0000000..2cad91e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/service/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.pay.service; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbAndRedisIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbAndRedisIntegrationTest.java new file mode 100644 index 0000000..cefc11a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbAndRedisIntegrationTest.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.pay.test; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseDbAndRedisIntegrationTest { + + @Import({ + // DB 配置类 + DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + + // Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbIntegrationTest.java new file mode 100644 index 0000000..380efa3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseDbIntegrationTest.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.test; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseDbIntegrationTest { + + @Import({ + // DB 配置类 + DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseRedisIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseRedisIntegrationTest.java new file mode 100644 index 0000000..8e05bc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/java/cn/iocoder/yudao/module/pay/test/BaseRedisIntegrationTest.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.pay.test; + +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseRedisIntegrationTest { + + @Import({ + // Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动配置类 + }) + public static class Application { + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml new file mode 100644 index 0000000..a4d4369 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml @@ -0,0 +1,83 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 + slave: # 模拟从库,可根据自己需要修改 + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志 + global-config: + db-config: + id-type: AUTO # 自增 ID + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + mapper-locations: classpath*:mapper/*.xml + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 + base-package: cn.iocoder.yudao.module + pay: + pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify + refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java new file mode 100644 index 0000000..826cb42 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java @@ -0,0 +1,260 @@ +package cn.iocoder.yudao.module.pay.service.app; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link PayAppServiceImpl} 的单元测试 + * + * @author aquan + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import(PayAppServiceImpl.class) +public class PayAppServiceTest extends BaseDbUnitTest { + + @Resource + private PayAppServiceImpl appService; + + @Resource + private PayAppMapper appMapper; + + @MockBean + private PayOrderService orderService; + @MockBean + private PayRefundService refundService; + + @Test + public void testCreateApp_success() { + // 准备参数 + PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class, o -> + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())) + .setOrderNotifyUrl(randomURL()) + .setRefundNotifyUrl(randomURL())); + + // 调用 + Long appId = appService.createApp(reqVO); + // 断言 + assertNotNull(appId); + PayAppDO app = appMapper.selectById(appId); + assertPojoEquals(reqVO, app); + } + + @Test + public void testUpdateApp_success() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setOrderNotifyUrl(randomURL()).setRefundNotifyUrl(randomURL()); + o.setId(dbApp.getId()); // 设置更新的 ID + }); + + // 调用 + appService.updateApp(reqVO); + // 校验是否更新正确 + PayAppDO app = appMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, app); + } + + @Test + public void testUpdateApp_notExists() { + // 准备参数 + PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); + // 调用, 并断言异常 + assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_FOUND); + } + + @Test + public void testUpdateAppStatus() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> + o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + + // 准备参数 + Long id = dbApp.getId(); + Integer status = CommonStatusEnum.ENABLE.getStatus(); + // 调用 + appService.updateAppStatus(id, status); + // 断言 + PayAppDO app = appMapper.selectById(id); // 获取最新的 + assertEquals(status, app.getStatus()); + } + + @Test + public void testDeleteApp_success() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + + // 调用 + appService.deleteApp(id); + // 校验数据不存在了 + assertNull(appMapper.selectById(id)); + } + + @Test + public void testDeleteApp_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> appService.deleteApp(id), APP_NOT_FOUND); + } + + @Test + public void testDeleteApp_existOrder() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + // mock 订单有订单 + when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L); + + // 调用, 并断言异常 + assertServiceException(() -> appService.deleteApp(id), APP_EXIST_ORDER_CANT_DELETE); + } + + @Test + public void testDeleteApp_existRefund() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + // mock 订单有订单 + when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L); + + // 调用, 并断言异常 + assertServiceException(() -> appService.deleteApp(id), APP_EXIST_REFUND_CANT_DELETE); + } + + @Test + public void testApp() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + + // 调用 + PayAppDO app = appService.getApp(id); + // 校验数据一致 + assertPojoEquals(app, dbApp); + } + + @Test + public void testAppMap() { + // mock 数据 + PayAppDO dbApp01 = randomPojo(PayAppDO.class); + appMapper.insert(dbApp01);// @Sql: 先插入出一条存在的数据 + PayAppDO dbApp02 = randomPojo(PayAppDO.class); + appMapper.insert(dbApp02);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp01.getId(); + + // 调用 + Map appMap = appService.getAppMap(singleton(id)); + // 校验数据一致 + assertEquals(1, appMap.size()); + assertPojoEquals(dbApp01, appMap.get(id)); + } + + @Test + public void testGetAppPage() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 + o.setName("灿灿姐的杂货铺"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2021,11,20)); + }); + + appMapper.insert(dbApp); + // 测试 name 不匹配 + appMapper.insert(cloneIgnoreId(dbApp, o -> o.setName("敏敏姐的杂货铺"))); + // 测试 status 不匹配 + appMapper.insert(cloneIgnoreId(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + appMapper.insert(cloneIgnoreId(dbApp, o -> o.setCreateTime(buildTime(2021,12,21)))); + // 准备参数 + PayAppPageReqVO reqVO = new PayAppPageReqVO(); + reqVO.setName("灿灿姐的杂货铺"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2021, 11, 19, 2021, 11, 21)); + + // 调用 + PageResult pageResult = appService.getAppPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbApp, pageResult.getList().get(0)); + } + + @Test + public void testValidPayApp_success() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, + o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + + // 调用 + PayAppDO app = appService.validPayApp(id); + // 校验数据一致 + assertPojoEquals(app, dbApp); + } + + @Test + public void testValidPayApp_notFound() { + assertServiceException(() -> appService.validPayApp(randomLongId()), APP_NOT_FOUND); + } + + @Test + public void testValidPayApp_disable() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, + o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + + // 调用,并断言异常 + assertServiceException(() -> appService.validPayApp(id), APP_IS_DISABLE); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java new file mode 100644 index 0000000..09631d3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java @@ -0,0 +1,343 @@ +package cn.iocoder.yudao.module.pay.service.channel; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; +import com.alibaba.fastjson.JSON; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@Import({PayChannelServiceImpl.class}) +public class PayChannelServiceTest extends BaseDbUnitTest { + + @Resource + private PayChannelServiceImpl channelService; + + @Resource + private PayChannelMapper channelMapper; + + @MockBean + private PayClientFactory payClientFactory; + @MockBean + private Validator validator; + + @Test + public void testCreateChannel_success() { + // 准备参数 + WxPayClientConfig config = randomWxPayClientConfig(); + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setStatus(randomCommonStatus()); + o.setCode(PayChannelEnum.WX_PUB.getCode()); + o.setConfig(JsonUtils.toJsonString(config)); + }); + + // 调用 + Long channelId = channelService.createChannel(reqVO); + // 校验记录的属性是否正确 + PayChannelDO channel = channelMapper.selectById(channelId); + assertPojoEquals(reqVO, channel, "config"); + assertPojoEquals(config, channel.getConfig()); + // 校验缓存 + assertNull(channelService.getClientCache().getIfPresent(channelId)); + } + + @Test + public void testCreateChannel_exists() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, + o -> o.setConfig(randomWxPayClientConfig())); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setAppId(dbChannel.getAppId()); + o.setCode(dbChannel.getCode()); + }); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.createChannel(reqVO), CHANNEL_EXIST_SAME_CHANNEL_ERROR); + } + + @Test + public void testUpdateChannel_success() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + AlipayPayClientConfig config = randomAlipayPayClientConfig(); + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> { + o.setId(dbChannel.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + o.setConfig(JsonUtils.toJsonString(config)); + }); + + // 调用 + channelService.updateChannel(reqVO); + // 校验是否更新正确 + PayChannelDO channel = channelMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, channel, "config"); + assertPojoEquals(config, channel.getConfig()); + // 校验缓存 + assertNull(channelService.getClientCache().getIfPresent(channel.getId())); + } + + @Test + public void testUpdateChannel_notExists() { + // 准备参数 + AlipayPayClientConfig payClientPublicKeyConfig = randomAlipayPayClientConfig(); + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(payClientPublicKeyConfig)); + }); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_FOUND); + } + + @Test + public void testDeleteChannel_success() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbChannel.getId(); + + // 调用 + channelService.deleteChannel(id); + // 校验数据不存在了 + assertNull(channelMapper.selectById(id)); + // 校验缓存 + assertNull(channelService.getClientCache().getIfPresent(id)); + } + + @Test + public void testDeleteChannel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_FOUND); + } + + @Test + public void testGetChannel() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbChannel.getId(); + + // 调用 + PayChannelDO channel = channelService.getChannel(id); + // 校验是否更新正确 + assertPojoEquals(dbChannel, channel); + } + + @Test + public void testGetChannelListByAppIds() { + // mock 数据 + PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据 + PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.WX_PUB.getCode()); + o.setConfig(randomWxPayClientConfig()); + }); + channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long appId = dbChannel01.getAppId(); + + // 调用 + List channels = channelService.getChannelListByAppIds(Collections.singleton(appId)); + // 校验是否更新正确 + assertEquals(1, channels.size()); + assertPojoEquals(dbChannel01, channels.get(0)); + } + + @Test + public void testGetChannelByAppIdAndCode() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long appId = dbChannel.getAppId(); + String code = dbChannel.getCode(); + + // 调用 + PayChannelDO channel = channelService.getChannelByAppIdAndCode(appId, code); + // 断言 + assertPojoEquals(channel, dbChannel); + } + + @Test + public void testValidPayChannel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_NOT_FOUND); + } + + @Test + public void testValidPayChannel_isDisable() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbChannel.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_IS_DISABLE); + } + + @Test + public void testValidPayChannel_success() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbChannel.getId(); + + // 调用 + PayChannelDO channel = channelService.validPayChannel(id); + // 断言异常 + assertPojoEquals(channel, dbChannel); + } + + @Test + public void testValidPayChannel_appIdAndCode() { + // mock 数据 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long appId = dbChannel.getAppId(); + String code = dbChannel.getCode(); + + // 调用 + PayChannelDO channel = channelService.validPayChannel(appId, code); + // 断言异常 + assertPojoEquals(channel, dbChannel); + } + + @Test + public void testGetEnableChannelList() { + // 准备参数 + Long appId = randomLongId(); + // mock 数据 01(enable 不匹配) + PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + }); + channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据 + // mock 数据 02(appId 不匹配) + PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据 + // mock 数据 03 + PayChannelDO dbChannel03 = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + o.setAppId(appId); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + channelMapper.insert(dbChannel03);// @Sql: 先插入出一条存在的数据 + + // 调用 + List channel = channelService.getEnableChannelList(appId); + // 断言异常 + assertPojoEquals(channel, dbChannel03); + } + + @Test + public void testGetPayClient() { + // mock 数据 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setConfig(randomAlipayPayClientConfig()); + }); + channelMapper.insert(channel); + // mock 参数 + Long id = channel.getId(); + // mock 方法 + PayClient mockClient = mock(PayClient.class); + when(payClientFactory.getPayClient(eq(id))).thenReturn(mockClient); + + // 调用 + PayClient client = channelService.getPayClient(id); + // 断言 + assertSame(client, mockClient); + verify(payClientFactory).createOrUpdatePayClient(eq(id), eq(channel.getCode()), + eq(channel.getConfig())); + } + + public WxPayClientConfig randomWxPayClientConfig() { + return new WxPayClientConfig() + .setAppId(randomString()) + .setMchId(randomString()) + .setApiVersion(WxPayClientConfig.API_VERSION_V2) + .setMchKey(randomString()); + } + + public AlipayPayClientConfig randomAlipayPayClientConfig() { + return new AlipayPayClientConfig() + .setServerUrl(randomURL()) + .setAppId(randomString()) + .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) + .setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY) + .setPrivateKey(randomString()) + .setAlipayPublicKey(randomString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java new file mode 100644 index 0000000..cf32b3e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java @@ -0,0 +1,353 @@ +package cn.iocoder.yudao.module.pay.service.notify; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper; +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; +import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.pay.service.refund.PayRefundServiceImpl; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +/** + * {@link PayRefundServiceImpl} 的单元测试类 + * + * @author 芋艿 + */ +@Disabled // TODO 芋艿:后续 fix 补充的单测 +@Import({PayJobConfiguration.class, PayNotifyServiceImpl.class, PayNotifyLockRedisDAO.class}) +public class PayNotifyServiceTest extends BaseDbUnitTest { + + @Resource + private PayNotifyServiceImpl notifyService; + + @MockBean + private PayOrderService orderService; + @MockBean + private PayRefundService refundService; + + @Resource + private PayNotifyTaskMapper notifyTaskMapper; + @Resource + private PayNotifyLogMapper notifyLogMapper; + + @MockBean + private RedissonClient redissonClient; + + @Test + public void testCreatePayNotifyTask_order() { + PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class))) + .thenReturn(payNotifyService); + + // 准备参数 + Integer type = PayNotifyTypeEnum.ORDER.getType(); + Long dataId = 1L; + // mock 方法(order) + PayOrderDO order = randomPojo(PayOrderDO.class); + when(orderService.getOrder(eq(1L))).thenReturn(order); + // mock 方法(lock) + mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增 + + // 调用 + notifyService.createPayNotifyTask(type, dataId); + // 断言,task + PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null); + assertNotNull(dbTask.getNextNotifyTime()); + assertThat(dbTask) + .extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes", + "appId", "merchantOrderId", "notifyUrl") + .containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9, + order.getAppId(), order.getMerchantOrderId(), order.getNotifyUrl()); + // 断言,调用 + verify(payNotifyService).executeNotify0(eq(dbTask)); + } + } + + @Test + public void testCreatePayNotifyTask_refund() { + PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class))) + .thenReturn(payNotifyService); + + // 准备参数 + Integer type = PayNotifyTypeEnum.REFUND.getType(); + Long dataId = 1L; + // mock 方法(refund) + PayRefundDO refund = randomPojo(PayRefundDO.class); + when(refundService.getRefund(eq(1L))).thenReturn(refund); + // mock 方法(lock) + mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增 + + // 调用 + notifyService.createPayNotifyTask(type, dataId); + // 断言,task + PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null); + assertNotNull(dbTask.getNextNotifyTime()); + assertThat(dbTask) + .extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes", + "appId", "merchantOrderId", "notifyUrl") + .containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9, + refund.getAppId(), refund.getMerchantOrderId(), refund.getNotifyUrl()); + // 断言,调用 + verify(payNotifyService).executeNotify0(eq(dbTask)); + } + } + + @Test + public void testExecuteNotify() throws InterruptedException { + // mock 数据(notify) + PayNotifyTaskDO dbTask01 = randomPojo(PayNotifyTaskDO.class, + o -> o.setStatus(PayNotifyStatusEnum.WAITING.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); + notifyTaskMapper.insert(dbTask01); + PayNotifyTaskDO dbTask02 = randomPojo(PayNotifyTaskDO.class, + o -> o.setStatus(PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); + notifyTaskMapper.insert(dbTask02); + PayNotifyTaskDO dbTask03 = randomPojo(PayNotifyTaskDO.class, + o -> o.setStatus(PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); + notifyTaskMapper.insert(dbTask03); + PayNotifyTaskDO dbTask04 = randomPojo(PayNotifyTaskDO.class, // 不满足状态 + o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); + notifyTaskMapper.insert(dbTask04); + PayNotifyTaskDO dbTask05 = randomPojo(PayNotifyTaskDO.class, // 不满足状态 + o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); + notifyTaskMapper.insert(dbTask05); + PayNotifyTaskDO dbTask06 = randomPojo(PayNotifyTaskDO.class, // 不满足时间 + o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()) + .setNextNotifyTime(addTime(Duration.ofMinutes(1)))); + notifyTaskMapper.insert(dbTask06); + // mock 方法(lock) + mockLock(dbTask01.getId()); + mockLock(dbTask02.getId()); + mockLock(dbTask03.getId()); + + // 调用 + int count = notifyService.executeNotify(); + // 断言,数量 + assertEquals(count, 3); + } + + @Test // 由于 HttpUtil 不好 mock,所以只测试异常的情况 + public void testExecuteNotify0_exception() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, o -> o.setType(-1) + .setNotifyTimes(0).setMaxNotifyTimes(9)); + notifyTaskMapper.insert(task); + + // 调用 + notifyService.executeNotify0(task); + // 断言,task + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime()); + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime()); + assertEquals(dbTask.getNotifyTimes(), 1); + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()); + // 断言,log + PayNotifyLogDO dbLog = notifyLogMapper.selectOne(null); + assertEquals(dbLog.getTaskId(), task.getId()); + assertEquals(dbLog.getNotifyTimes(), 1); + assertTrue(dbLog.getResponse().contains("未知的通知任务类型:")); + assertEquals(dbLog.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()); + } + + @Test + public void testProcessNotifyResult_success() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9)); + notifyTaskMapper.insert(task); + // 准备参数 + CommonResult invokeResult = CommonResult.success(randomString()); + + // 调用 + notifyService.processNotifyResult(task, invokeResult, null); + // 断言 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime()); + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime()); + assertEquals(dbTask.getNotifyTimes(), 1); + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.SUCCESS.getStatus()); + } + + @Test + public void testProcessNotifyResult_failure() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, + o -> o.setNotifyTimes(8).setMaxNotifyTimes(9)); + notifyTaskMapper.insert(task); + // 准备参数 + CommonResult invokeResult = CommonResult.error(BAD_REQUEST); + + // 调用 + notifyService.processNotifyResult(task, invokeResult, null); + // 断言 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime()); + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime()); + assertEquals(dbTask.getNotifyTimes(), 9); + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.FAILURE.getStatus()); + } + + @Test + public void testProcessNotifyResult_requestFailure() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9)); + notifyTaskMapper.insert(task); + // 准备参数 + CommonResult invokeResult = CommonResult.error(BAD_REQUEST); + + // 调用 + notifyService.processNotifyResult(task, invokeResult, null); + // 断言 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime()); + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime()); + assertEquals(dbTask.getNotifyTimes(), 1); + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); + } + + @Test + public void testProcessNotifyResult_requestSuccess() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9)); + notifyTaskMapper.insert(task); + // 准备参数 + CommonResult invokeResult = CommonResult.error(BAD_REQUEST); + RuntimeException invokeException = new RuntimeException(); + + // 调用 + notifyService.processNotifyResult(task, invokeResult, invokeException); + // 断言 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId()); + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime()); + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime()); + assertEquals(dbTask.getNotifyTimes(), 1); + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()); + } + + @Test + public void testGetNotifyTask() { + // mock 数据(task) + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class); + notifyTaskMapper.insert(task); + // 准备参数 + Long id = task.getId(); + + // 调用 + PayNotifyTaskDO dbTask = notifyService.getNotifyTask(id); + // 断言 + assertPojoEquals(dbTask, task); + } + + @Test + public void testGetNotifyTaskPage() { + // mock 数据 + PayNotifyTaskDO dbTask = randomPojo(PayNotifyTaskDO.class, o -> { // 等会查询到 + o.setAppId(1L); + o.setType(PayNotifyTypeEnum.REFUND.getType()); + o.setDataId(100L); + o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); + o.setMerchantOrderId("P110"); + o.setCreateTime(buildTime(2023, 2, 3)); + }); + notifyTaskMapper.insert(dbTask); + // 测试 appId 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setAppId(2L))); + // 测试 type 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setType(PayNotifyTypeEnum.ORDER.getType()))); + // 测试 dataId 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setDataId(200L))); + // 测试 status 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()))); + // 测试 merchantOrderId 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setMerchantOrderId(randomString()))); + // 测试 createTime 不匹配 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setCreateTime(buildTime(2023, 1, 1)))); + // 准备参数 + PayNotifyTaskPageReqVO reqVO = new PayNotifyTaskPageReqVO(); + reqVO.setAppId(1L); + reqVO.setType(PayNotifyTypeEnum.REFUND.getType()); + reqVO.setDataId(100L); + reqVO.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); + reqVO.setMerchantOrderId("P110"); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = notifyService.getNotifyTaskPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbTask, pageResult.getList().get(0)); + } + + @Test + public void testGetNotifyLogList() { + // mock 数据 + PayNotifyLogDO dbLog = randomPojo(PayNotifyLogDO.class); + notifyLogMapper.insert(dbLog); + PayNotifyLogDO dbLog02 = randomPojo(PayNotifyLogDO.class); + notifyLogMapper.insert(dbLog02); + // 准备参数 + Long taskId = dbLog.getTaskId(); + + // 调用 + List logList = notifyService.getNotifyLogList(taskId); + // 断言 + assertEquals(logList.size(), 1); + assertPojoEquals(dbLog, logList.get(0)); + } + + private void mockLock(Long id) { + RLock lock = mock(RLock.class); + if (id == null) { + when(redissonClient.getLock(anyString())) + .thenReturn(lock); + } else { + when(redissonClient.getLock(eq("pay_notify:lock:" + id))) + .thenReturn(lock); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java new file mode 100644 index 0000000..2c9db46 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java @@ -0,0 +1,1102 @@ +package cn.iocoder.yudao.module.pay.service.order; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; +import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper; +import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * {@link PayOrderServiceImpl} 的单元测试类 + * + * @author 芋艿 + */ +@Import({PayOrderServiceImpl.class, PayNoRedisDAO.class}) +public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { + + @Resource + private PayOrderServiceImpl orderService; + + @Resource + private PayOrderMapper orderMapper; + @Resource + private PayOrderExtensionMapper orderExtensionMapper; + + @MockBean + private PayProperties properties; + @MockBean + private PayAppService appService; + @MockBean + private PayChannelService channelService; + @MockBean + private PayNotifyService notifyService; + + @BeforeEach + public void setUp() { + when(properties.getOrderNotifyUrl()).thenReturn("http://127.0.0.1"); + } + + @Test + public void testGetOrder_id() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class); + orderMapper.insert(order); + // 准备参数 + Long id = order.getId(); + + // 调用 + PayOrderDO dbOrder = orderService.getOrder(id); + // 断言 + assertPojoEquals(dbOrder, order); + } + + @Test + public void testGetOrder_appIdAndMerchantOrderId() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class); + orderMapper.insert(order); + // 准备参数 + Long appId = order.getAppId(); + String merchantOrderId = order.getMerchantOrderId(); + + // 调用 + PayOrderDO dbOrder = orderService.getOrder(appId, merchantOrderId); + // 断言 + assertPojoEquals(dbOrder, order); + } + + @Test + public void testGetOrderCountByAppId() { + // mock 数据(PayOrderDO) + PayOrderDO order01 = randomPojo(PayOrderDO.class); + orderMapper.insert(order01); + PayOrderDO order02 = randomPojo(PayOrderDO.class); + orderMapper.insert(order02); + // 准备参数 + Long appId = order01.getAppId(); + + // 调用 + Long count = orderService.getOrderCountByAppId(appId); + // 断言 + assertEquals(count, 1L); + } + + @Test + public void testGetOrderPage() { + // mock 数据 + PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 + o.setAppId(1L); + o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + o.setMerchantOrderId("110"); + o.setChannelOrderNo("220"); + o.setNo("330"); + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + o.setCreateTime(buildTime(2018, 1, 15)); + }); + orderMapper.insert(dbOrder); + // 测试 appId 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); + // 测试 channelCode 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); + // 测试 merchantOrderId 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString()))); + // 测试 channelOrderNo 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString()))); + // 测试 no 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString()))); + // 测试 status 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()))); + // 测试 createTime 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1)))); + // 准备参数 + PayOrderPageReqVO reqVO = new PayOrderPageReqVO(); + reqVO.setAppId(1L); + reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqVO.setMerchantOrderId("11"); + reqVO.setChannelOrderNo("22"); + reqVO.setNo("33"); + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30)); + + // 调用 + PageResult pageResult = orderService.getOrderPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbOrder, pageResult.getList().get(0)); + } + + @Test + public void testGetOrderList() { + // mock 数据 + PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 + o.setAppId(1L); + o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + o.setMerchantOrderId("110"); + o.setChannelOrderNo("220"); + o.setNo("330"); + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + o.setCreateTime(buildTime(2018, 1, 15)); + }); + orderMapper.insert(dbOrder); + // 测试 appId 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setAppId(2L))); + // 测试 channelCode 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); + // 测试 merchantOrderId 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString()))); + // 测试 channelOrderNo 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelOrderNo(randomString()))); + // 测试 no 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNo(randomString()))); + // 测试 status 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()))); + // 测试 createTime 不匹配 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1)))); + // 准备参数 + PayOrderExportReqVO reqVO = new PayOrderExportReqVO(); + reqVO.setAppId(1L); + reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqVO.setMerchantOrderId("11"); + reqVO.setChannelOrderNo("22"); + reqVO.setNo("33"); + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30)); + + // 调用 + List list = orderService.getOrderList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbOrder, list.get(0)); + } + + @Test + public void testCreateOrder_success() { + // mock 参数 + PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("10") + .setSubject(randomString()).setBody(randomString())); + // mock 方法 + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1")); + when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app); + + // 调用 + Long orderId = orderService.createOrder(reqDTO); + // 断言 + PayOrderDO order = orderMapper.selectById(orderId); + assertPojoEquals(order, reqDTO); + assertEquals(order.getAppId(), 1L); + assertEquals(order.getNotifyUrl(), "http://127.0.0.1"); + assertEquals(order.getStatus(), PayOrderStatusEnum.WAITING.getStatus()); + assertEquals(order.getRefundPrice(), 0); + } + + @Test + public void testCreateOrder_exists() { + // mock 参数 + PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("10")); + // mock 数据 + PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> o.setAppId(1L).setMerchantOrderId("10")); + orderMapper.insert(dbOrder); + + // 调用 + Long orderId = orderService.createOrder(reqDTO); + // 断言 + PayOrderDO order = orderMapper.selectById(orderId); + assertPojoEquals(dbOrder, order); + } + + @Test + public void testSubmitOrder_notFound() { + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class); + String userIp = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_NOT_FOUND); + } + + @Test + public void testSubmitOrder_notWaiting() { + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus())); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())); + String userIp = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_NOT_WAITING); + } + + @Test + public void testSubmitOrder_isSuccess() { + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())); + String userIp = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_STATUS_IS_SUCCESS); + } + + @Test + public void testSubmitOrder_expired() { + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofDays(-1)))); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())); + String userIp = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), PAY_ORDER_IS_EXPIRED); + } + + @Test + public void testSubmitOrder_channelNotFound() { + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1)))); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()) + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + String userIp = randomString(); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode()))) + .thenReturn(channel); + + // 调用, 并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), CHANNEL_NOT_FOUND); + } + + @Test // 调用 unifiedOrder 接口,返回存在渠道错误 + public void testSubmitOrder_channelError() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1)))); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()) + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + String userIp = randomString(); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode()))) + .thenReturn(channel); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法() + PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> + o.setChannelErrorCode("001").setChannelErrorMsg("模拟异常")); + when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> { + assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo()); + assertThat(payOrderUnifiedReqDTO) + .extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime") + .containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10", + reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime()); + return true; + }))).thenReturn(unifiedOrderResp); + + // 调用,并断言异常 + assertServiceException(() -> orderService.submitOrder(reqVO, userIp), + PAY_ORDER_SUBMIT_CHANNEL_ERROR, "001", "模拟异常"); + // 断言,数据记录(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null); + assertNotNull(orderExtension); + assertThat(orderExtension).extracting("no", "orderId").isNotNull(); + assertThat(orderExtension) + .extracting("channelId", "channelCode","userIp" ,"status", "channelExtras", + "channelErrorCode", "channelErrorMsg", "channelNotifyData") + .containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp, + PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(), + null, null, null); + } + } + + @Test + public void testSubmitOrder_success() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setAppId(1L).setExpireTime(addTime(Duration.ofDays(1)))); + orderMapper.insert(order); + // 准备参数 + PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()) + .setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + String userIp = randomString(); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode()))) + .thenReturn(channel); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(支付渠道的调用) + PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null) + .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou")); + when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> { + assertNotNull(payOrderUnifiedReqDTO.getOutTradeNo()); + assertThat(payOrderUnifiedReqDTO) + .extracting("subject", "body", "notifyUrl", "returnUrl", "price", "expireTime") + .containsExactly(order.getSubject(), order.getBody(), "http://127.0.0.1/10", + reqVO.getReturnUrl(), order.getPrice(), order.getExpireTime()); + return true; + }))).thenReturn(unifiedOrderResp); + + // 调用 + PayOrderSubmitRespVO result = orderService.submitOrder(reqVO, userIp); + // 断言,数据记录(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null); + assertNotNull(orderExtension); + assertThat(orderExtension).extracting("no", "orderId").isNotNull(); + assertThat(orderExtension) + .extracting("channelId", "channelCode","userIp" ,"status", "channelExtras", + "channelErrorCode", "channelErrorMsg", "channelNotifyData") + .containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp, + PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(), + null, null, null); + // 断言,返回(PayOrderSubmitRespVO) + assertThat(result) + .extracting("status", "displayMode", "displayContent") + .containsExactly(PayOrderStatusEnum.WAITING.getStatus(), PayOrderDisplayModeEnum.URL.getMode(), "tudou"); + // 断言,调用 + verify(payOrderServiceImpl).notifyOrder(same(channel), same(unifiedOrderResp)); + } + } + + @Test + public void testValidateOrderActuallyPaid_dbPaid() { + // 准备参数 + Long id = randomLongId(); + // mock 方法(OrderExtension 已支付) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setOrderId(id).setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); + orderExtensionMapper.insert(orderExtension); + + // 调用,并断言异常 + assertServiceException(() -> orderService.validateOrderActuallyPaid(id), + PAY_ORDER_EXTENSION_IS_PAID); + } + + @Test + public void testValidateOrderActuallyPaid_remotePaid() { + // 准备参数 + Long id = randomLongId(); + // mock 方法(OrderExtension 已支付) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setOrderId(id).setStatus(PayOrderStatusEnum.WAITING.getStatus())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient 已支付) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client); + when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()))); + + // 调用,并断言异常 + assertServiceException(() -> orderService.validateOrderActuallyPaid(id), + PAY_ORDER_EXTENSION_IS_PAID); + } + + @Test + public void testValidateOrderActuallyPaid_success() { + // 准备参数 + Long id = randomLongId(); + // mock 方法(OrderExtension 已支付) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setOrderId(id).setStatus(PayOrderStatusEnum.WAITING.getStatus())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient 已支付) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(orderExtension.getChannelId()))).thenReturn(client); + when(client.getOrder(eq(orderExtension.getNo()))).thenReturn(randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); + + // 调用,并断言异常 + orderService.validateOrderActuallyPaid(id); + } + + @Test + public void testNotifyOrder_channelId() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + // 准备参数 + Long channelId = 10L; + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + orderService.notifyOrder(channelId, notify); + // 断言 + verify(payOrderServiceImpl).notifyOrder(same(channel), same(notify)); + } + } + + @Test + public void testNotifyOrderSuccess_orderExtension_notFound() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus())); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_EXTENSION_NOT_FOUND); + } + + @Test + public void testNotifyOrderSuccess_orderExtension_closed() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + + @Test + public void testNotifyOrderSuccess_order_notFound() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_NOT_FOUND); + // 断言 PayOrderExtensionDO :数据更新被回滚 + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); + } + + @Test + public void testNotifyOrderSuccess_order_closed() { + testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.CLOSED.getStatus()); + } + + @Test + public void testNotifyOrderSuccess_order_refund() { + testNotifyOrderSuccess_order_closedOrRefund(PayOrderStatusEnum.REFUND.getStatus()); + } + + private void testNotifyOrderSuccess_order_closedOrRefund(Integer status) { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status)); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setNo("P110") + .setOrderId(order.getId())); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_STATUS_IS_NOT_WAITING); + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); + } + + @Test + public void testNotifyOrderSuccess_order_paid() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setNo("P110") + .setOrderId(order.getId())); + orderExtensionMapper.insert(orderExtension); + // 重要:需要将 order 的 extensionId 更新下 + order.setExtensionId(orderExtension.getId()); + orderMapper.updateById(order); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + orderService.notifyOrder(channel, notify); + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); + // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS + assertPojoEquals(order, orderMapper.selectOne(null)); + // 断言,调用 + verify(notifyService, never()).createPayNotifyTask(anyInt(), anyLong()); + } + + @Test + public void testNotifyOrderSuccess_order_waiting() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setPrice(10)); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setNo("P110") + .setOrderId(order.getId())); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setFeeRate(10D)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + orderService.notifyOrder(channel, notify); + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS + orderExtension.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setChannelNotifyData(toJsonString(notify)); + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null), + "updateTime", "updater"); + // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS + order.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setChannelId(10L).setChannelCode(channel.getCode()) + .setSuccessTime(notify.getSuccessTime()).setExtensionId(orderExtension.getId()).setNo(orderExtension.getNo()) + .setChannelOrderNo(notify.getChannelOrderNo()).setChannelUserId(notify.getChannelUserId()) + .setChannelFeeRate(10D).setChannelFeePrice(1); + assertPojoEquals(order, orderMapper.selectOne(null), + "updateTime", "updater"); + // 断言,调用 + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.ORDER.getType()), + eq(orderExtension.getOrderId())); + } + + @Test + public void testNotifyOrderClosed_orderExtension_notFound() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_EXTENSION_NOT_FOUND); + } + + @Test + public void testNotifyOrderClosed_orderExtension_closed() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言 + orderService.notifyOrder(channel, notify); + // 断言 PayOrderExtensionDO :数据未更新,因为它是 CLOSED + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); + } + + @Test + public void testNotifyOrderClosed_orderExtension_paid() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言 + orderService.notifyOrder(channel, notify); + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); + } + + @Test + public void testNotifyOrderClosed_orderExtension_refund() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) + .setOutTradeNo("P110")); + + // 调用,并断言异常 + assertServiceException(() -> orderService.notifyOrder(channel, notify), + PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); + } + + @Test + public void testNotifyOrderClosed_orderExtension_waiting() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setNo("P110")); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) + .setOutTradeNo("P110")); + + // 调用 + orderService.notifyOrder(channel, notify); + // 断言 PayOrderExtensionDO + orderExtension.setStatus(PayOrderStatusEnum.CLOSED.getStatus()).setChannelNotifyData(toJsonString(notify)) + .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()); + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null), + "updateTime", "updater"); + } + + @Test + public void testUpdateOrderRefundPrice_notFound() { + // 准备参数 + Long id = randomLongId(); + Integer incrRefundPrice = randomInteger(); + + // 调用,并断言异常 + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), + PAY_ORDER_NOT_FOUND); + } + + @Test + public void testUpdateOrderRefundPrice_waiting() { + testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.WAITING.getStatus()); + } + + @Test + public void testUpdateOrderRefundPrice_closed() { + testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus()); + } + + private void testUpdateOrderRefundPrice_waitingOrClosed(Integer status) { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(status)); + orderMapper.insert(order); + // 准备参数 + Long id = order.getId(); + Integer incrRefundPrice = randomInteger(); + + // 调用,并断言异常 + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), + PAY_ORDER_REFUND_FAIL_STATUS_ERROR); + } + + @Test + public void testUpdateOrderRefundPrice_priceExceed() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setRefundPrice(1).setPrice(10)); + orderMapper.insert(order); + // 准备参数 + Long id = order.getId(); + Integer incrRefundPrice = 10; + + // 调用,并断言异常 + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), + REFUND_PRICE_EXCEED); + } + + @Test + public void testUpdateOrderRefundPrice_refund() { + testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.REFUND.getStatus()); + } + + @Test + public void testUpdateOrderRefundPrice_success() { + testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.SUCCESS.getStatus()); + } + + private void testUpdateOrderRefundPrice_refundOrSuccess(Integer status) { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(status).setRefundPrice(1).setPrice(10)); + orderMapper.insert(order); + // 准备参数 + Long id = order.getId(); + Integer incrRefundPrice = 8; + + // 调用 + orderService.updateOrderRefundPrice(id, incrRefundPrice); + // 断言 + order.setRefundPrice(9).setStatus(PayOrderStatusEnum.REFUND.getStatus()); + assertPojoEquals(order, orderMapper.selectOne(null), + "updateTime", "updater"); + } + + @Test + public void testGetOrderExtension() { + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class); + orderExtensionMapper.insert(orderExtension); + // 准备参数 + Long id = orderExtension.getId(); + + // 调用 + PayOrderExtensionDO dbOrderExtension = orderService.getOrderExtension(id); + // 断言 + assertPojoEquals(dbOrderExtension, orderExtension); + } + + @Test + public void testSyncOrder_payClientNotFound() { + // 准备参数 + LocalDateTime minCreateTime = LocalDateTime.now().minus(Duration.ofMinutes(10)); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setCreateTime(LocalDateTime.now())); + orderExtensionMapper.insert(orderExtension); + + // 调用 + int count = orderService.syncOrder(minCreateTime); + // 断言 + assertEquals(count, 0); + } + + @Test + public void testSyncOrder_exception() { + // 准备参数 + LocalDateTime minCreateTime = LocalDateTime.now().minus(Duration.ofMinutes(10)); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setChannelId(10L) + .setCreateTime(LocalDateTime.now())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 异常) + when(client.getOrder(any())).thenThrow(new RuntimeException()); + + // 调用 + int count = orderService.syncOrder(minCreateTime); + // 断言 + assertEquals(count, 0); + } + + @Test + public void testSyncOrder_orderSuccess() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + + // 准备参数 + LocalDateTime minCreateTime = LocalDateTime.now().minus(Duration.ofMinutes(10)); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setChannelId(10L).setNo("P110") + .setCreateTime(LocalDateTime.now())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 成功返回) + PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); + when(client.getOrder(eq("P110"))).thenReturn(respDTO); + // mock 方法(PayChannelDO) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + int count = orderService.syncOrder(minCreateTime); + // 断言 + assertEquals(count, 1); + verify(payOrderServiceImpl).notifyOrder(same(channel), same(respDTO)); + } + } + + @Test + public void testSyncOrder_orderClosed() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + + // 准备参数 + LocalDateTime minCreateTime = LocalDateTime.now().minus(Duration.ofMinutes(10)); + // mock 数据(PayOrderExtensionDO) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setChannelId(10L).setNo("P110") + .setCreateTime(LocalDateTime.now())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 成功返回) + PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())); + when(client.getOrder(eq("P110"))).thenReturn(respDTO); + // mock 方法(PayChannelDO) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + int count = orderService.syncOrder(minCreateTime); + // 断言 + assertEquals(count, 0); + verify(payOrderServiceImpl, never()).notifyOrder(same(channel), same(respDTO)); + } + } + + @Test + public void testExpireOrder_orderExtension_isSuccess() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofMinutes(-1)))); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO 已支付) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) + .setOrderId(order.getId())); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + + // 调用 + int count = orderService.expireOrder(); + // 断言 + assertEquals(count, 0); + // 断言 order 没有变化,因为没更新 + assertPojoEquals(order, orderMapper.selectOne(null)); + } + + @Test + public void testExpireOrder_payClient_notFound() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofMinutes(-1)))); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO 等待中) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setOrderId(order.getId()) + .setChannelId(10L)); + orderExtensionMapper.insert(orderExtension); + + // 调用 + int count = orderService.expireOrder(); + // 断言 + assertEquals(count, 0); + // 断言 order 没有变化,因为没更新 + assertPojoEquals(order, orderMapper.selectOne(null)); + } + + @Test + public void testExpireOrder_getOrder_isRefund() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofMinutes(-1)))); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO 等待中) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setOrderId(order.getId()).setNo("P110") + .setChannelId(10L)); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 退款返回) + PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus())); + when(client.getOrder(eq("P110"))).thenReturn(respDTO); + + // 调用 + int count = orderService.expireOrder(); + // 断言 + assertEquals(count, 0); + // 断言 order 没有变化,因为没更新 + assertPojoEquals(order, orderMapper.selectOne(null)); + } + + @Test + public void testExpireOrder_getOrder_isSuccess() { + PayOrderServiceImpl payOrderServiceImpl = mock(PayOrderServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayOrderServiceImpl.class))) + .thenReturn(payOrderServiceImpl); + + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofMinutes(-1)))); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO 等待中) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setOrderId(order.getId()).setNo("P110") + .setChannelId(10L)); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 成功返回) + PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())); + when(client.getOrder(eq("P110"))).thenReturn(respDTO); + // mock 方法(PayChannelDO) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + int count = orderService.expireOrder(); + // 断言 + assertEquals(count, 0); + // 断言 order 没有变化,因为没更新 + assertPojoEquals(order, orderMapper.selectOne(null)); + verify(payOrderServiceImpl).notifyOrder(same(channel), same(respDTO)); + } + } + + @Test + public void testExpireOrder_success() { + // mock 数据(PayOrderDO) + PayOrderDO order = randomPojo(PayOrderDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setExpireTime(addTime(Duration.ofMinutes(-1)))); + orderMapper.insert(order); + // mock 数据(PayOrderExtensionDO 等待中) + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) + .setOrderId(order.getId()).setNo("P110") + .setChannelId(10L)); + orderExtensionMapper.insert(orderExtension); + // mock 方法(PayClient) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(PayClient 关闭返回) + PayOrderRespDTO respDTO = randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())); + when(client.getOrder(eq("P110"))).thenReturn(respDTO); + + // 调用 + int count = orderService.expireOrder(); + // 断言 + assertEquals(count, 1); + // 断言 extension 变化 + orderExtension.setStatus(PayOrderStatusEnum.CLOSED.getStatus()) + .setChannelNotifyData(toJsonString(respDTO)); + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null), + "updateTime", "updater"); + // 断言 order 变化 + order.setStatus(PayOrderStatusEnum.CLOSED.getStatus()); + assertPojoEquals(order, orderMapper.selectOne(null), + "updateTime", "updater"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java new file mode 100644 index 0000000..a9296f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java @@ -0,0 +1,700 @@ +package cn.iocoder.yudao.module.pay.service.refund; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; +import cn.iocoder.yudao.module.pay.service.app.PayAppService; +import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +/** + * {@link PayRefundServiceImpl} 的单元测试类 + * + * @author 芋艿 + */ +@Import({PayRefundServiceImpl.class, PayNoRedisDAO.class}) +public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { + + @Resource + private PayRefundServiceImpl refundService; + + @Resource + private PayRefundMapper refundMapper; + + @MockBean + private PayProperties payProperties; + @MockBean + private PayOrderService orderService; + @MockBean + private PayAppService appService; + @MockBean + private PayChannelService channelService; + @MockBean + private PayNotifyService notifyService; + + @BeforeEach + public void setUp() { + when(payProperties.getRefundNotifyUrl()).thenReturn("http://127.0.0.1"); + } + + @Test + public void testGetRefund() { + // mock 数据 + PayRefundDO refund = randomPojo(PayRefundDO.class); + refundMapper.insert(refund); + // 准备参数 + Long id = refund.getId(); + + // 调用 + PayRefundDO dbRefund = refundService.getRefund(id); + // 断言 + assertPojoEquals(dbRefund, refund); + } + + @Test + public void testGetRefundCountByAppId() { + // mock 数据 + PayRefundDO refund01 = randomPojo(PayRefundDO.class); + refundMapper.insert(refund01); + PayRefundDO refund02 = randomPojo(PayRefundDO.class); + refundMapper.insert(refund02); + // 准备参数 + Long appId = refund01.getAppId(); + + // 调用 + Long count = refundService.getRefundCountByAppId(appId); + // 断言 + assertEquals(count, 1); + } + + @Test + public void testGetRefundPage() { + // mock 数据 + PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 + o.setAppId(1L); + o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + o.setMerchantOrderId("MOT0000001"); + o.setMerchantRefundId("MRF0000001"); + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + o.setChannelOrderNo("CH0000001"); + o.setChannelRefundNo("CHR0000001"); + o.setCreateTime(buildTime(2021, 1, 10)); + }); + refundMapper.insert(dbRefund); + // 测试 appId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); + // 测试 channelCode 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); + // 测试 merchantOrderId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString()))); + // 测试 merchantRefundId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString()))); + // 测试 channelOrderNo 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString()))); + // 测试 channelRefundNo 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString()))); + // 测试 status 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); + // 测试 createTime 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1)))); + // 准备参数 + PayRefundPageReqVO reqVO = new PayRefundPageReqVO(); + reqVO.setAppId(1L); + reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqVO.setMerchantOrderId("MOT0000001"); + reqVO.setMerchantRefundId("MRF0000001"); + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + reqVO.setChannelOrderNo("CH0000001"); + reqVO.setChannelRefundNo("CHR0000001"); + reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11)); + + // 调用 + PageResult pageResult = refundService.getRefundPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbRefund, pageResult.getList().get(0)); + } + + @Test + public void testGetRefundList() { + // mock 数据 + PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 + o.setAppId(1L); + o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + o.setMerchantOrderId("MOT0000001"); + o.setMerchantRefundId("MRF0000001"); + o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + o.setChannelOrderNo("CH0000001"); + o.setChannelRefundNo("CHR0000001"); + o.setCreateTime(buildTime(2021, 1, 10)); + }); + refundMapper.insert(dbRefund); + // 测试 appId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); + // 测试 channelCode 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); + // 测试 merchantOrderId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString()))); + // 测试 merchantRefundId 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString()))); + // 测试 channelOrderNo 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString()))); + // 测试 channelRefundNo 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString()))); + // 测试 status 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); + // 测试 createTime 不匹配 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1)))); + // 准备参数 + PayRefundExportReqVO reqVO = new PayRefundExportReqVO(); + reqVO.setAppId(1L); + reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqVO.setMerchantOrderId("MOT0000001"); + reqVO.setMerchantRefundId("MRF0000001"); + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); + reqVO.setChannelOrderNo("CH0000001"); + reqVO.setChannelRefundNo("CHR0000001"); + reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11)); + + // 调用 + List list = refundService.getRefundList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbRefund, list.get(0)); + } + + @Test + public void testCreateRefund_orderNotFound() { + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L)); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + PAY_ORDER_NOT_FOUND); + } + + @Test + public void testCreateRefund_orderWaiting() { + testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.WAITING.getStatus()); + } + + @Test + public void testCreateRefund_orderClosed() { + testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus()); + } + + private void testCreateRefund_orderWaitingOrClosed(Integer status) { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100")); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status)); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + PAY_ORDER_REFUND_FAIL_STATUS_ERROR); + } + + @Test + public void testCreateRefund_refundPriceExceed() { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1)); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + REFUND_PRICE_EXCEED); + } + + @Test + public void testCreateRefund_orderHasRefunding() { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1)); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + // mock 数据(refund 在退款中) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> + o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus())); + refundMapper.insert(refund); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + REFUND_PRICE_EXCEED); + } + + @Test + public void testCreateRefund_channelNotFound() { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1) + .setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(1L))).thenReturn(channel); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + CHANNEL_NOT_FOUND); + } + + @Test + public void testCreateRefund_refundExists() { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) + .setMerchantRefundId("200").setReason("测试退款")); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1) + .setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(1L))).thenReturn(channel); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 数据(refund 已存在) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> + o.setAppId(1L).setMerchantRefundId("200")); + refundMapper.insert(refund); + + // 调用,并断言异常 + assertServiceException(() -> refundService.createPayRefund(reqDTO), + REFUND_EXISTS); + } + + @Test + public void testCreateRefund_invokeException() { + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) + .setMerchantRefundId("200").setReason("测试退款")); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1) + .setChannelId(10L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(client 调用发生异常) + when(client.unifiedRefund(any(PayRefundUnifiedReqDTO.class))).thenThrow(new RuntimeException()); + + // 调用 + Long refundId = refundService.createPayRefund(reqDTO); + // 断言 + PayRefundDO refundDO = refundMapper.selectById(refundId); + assertPojoEquals(reqDTO, refundDO); + assertNotNull(refundDO.getNo()); + assertThat(refundDO) + .extracting("orderId", "orderNo", "channelId", "channelCode", + "notifyUrl", "channelOrderNo", "status", "payPrice", "refundPrice") + .containsExactly(order.getId(), order.getNo(), channel.getId(), channel.getCode(), + app.getRefundNotifyUrl(), order.getChannelOrderNo(), PayRefundStatusEnum.WAITING.getStatus(), + order.getPrice(), reqDTO.getPrice()); + } + + @Test + public void testCreateRefund_invokeSuccess() { + PayRefundServiceImpl payRefundServiceImpl = mock(PayRefundServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayRefundServiceImpl.class))) + .thenReturn(payRefundServiceImpl); + + // 准备参数 + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) + .setMerchantRefundId("200").setReason("测试退款")); + // mock 方法(app) + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); + when(appService.validPayApp(eq(1L))).thenReturn(app); + // mock 数据(order) + PayOrderDO order = randomPojo(PayOrderDO.class, o -> + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) + .setPrice(10).setRefundPrice(1) + .setChannelId(10L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(client 成功) + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class); + when(client.unifiedRefund(argThat(unifiedReqDTO -> { + assertNotNull(unifiedReqDTO.getOutRefundNo()); + assertThat(unifiedReqDTO) + .extracting("payPrice", "refundPrice", "outTradeNo", + "notifyUrl", "reason") + .containsExactly(order.getPrice(), reqDTO.getPrice(), order.getNo(), + "http://127.0.0.1/10", reqDTO.getReason()); + return true; + }))).thenReturn(refundRespDTO); + + // 调用 + Long refundId = refundService.createPayRefund(reqDTO); + // 断言 + PayRefundDO refundDO = refundMapper.selectById(refundId); + assertPojoEquals(reqDTO, refundDO); + assertNotNull(refundDO.getNo()); + assertThat(refundDO) + .extracting("orderId", "orderNo", "channelId", "channelCode", + "notifyUrl", "channelOrderNo", "status", "payPrice", "refundPrice") + .containsExactly(order.getId(), order.getNo(), channel.getId(), channel.getCode(), + app.getRefundNotifyUrl(), order.getChannelOrderNo(), PayRefundStatusEnum.WAITING.getStatus(), + order.getPrice(), reqDTO.getPrice()); + // 断言调用 + verify(payRefundServiceImpl).notifyRefund(same(channel), same(refundRespDTO)); + } + } + + @Test + public void testNotifyRefund() { + PayRefundServiceImpl payRefundServiceImpl = mock(PayRefundServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayRefundServiceImpl.class))) + .thenReturn(payRefundServiceImpl); + + // 准备参数 + Long channelId = 10L; + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + refundService.notifyRefund(channelId, refundRespDTO); + // 断言 + verify(payRefundServiceImpl).notifyRefund(same(channel), same(refundRespDTO)); + } + } + + @Test + public void testNotifyRefundSuccess_notFound() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()).setOutRefundNo("R100")); + + // 调用,并断言异常 + assertServiceException(() -> refundService.notifyRefund(channel, refundRespDTO), + REFUND_NOT_FOUND); + } + + @Test + public void testNotifyRefundSuccess_isSuccess() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus())); + refundMapper.insert(refund); + + // 调用 + refundService.notifyRefund(channel, refundRespDTO); + // 断言,refund 没有更新,因为已经退款成功 + assertPojoEquals(refund, refundMapper.selectById(refund.getId())); + } + + @Test + public void testNotifyRefundSuccess_failure() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.FAILURE.getStatus())); + refundMapper.insert(refund); + + // 调用,并断言异常 + assertServiceException(() -> refundService.notifyRefund(channel, refundRespDTO), + REFUND_STATUS_IS_NOT_WAITING); + } + + @Test + public void testNotifyRefundSuccess_updateOrderException() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setOrderId(100L).setRefundPrice(23)); + refundMapper.insert(refund); + // mock 方法(order + 更新异常) + doThrow(new RuntimeException()).when(orderService) + .updateOrderRefundPrice(eq(100L), eq(23)); + + // 调用,并断言异常 + assertThrows(RuntimeException.class, () -> refundService.notifyRefund(channel, refundRespDTO)); + // 断言,refund 没有更新,因为事务回滚了 + assertPojoEquals(refund, refundMapper.selectById(refund.getId())); + } + + @Test + public void testNotifyRefundSuccess_success() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setOrderId(100L).setRefundPrice(23)); + refundMapper.insert(refund); + + // 调用 + refundService.notifyRefund(channel, refundRespDTO); + // 断言,refund + refund.setSuccessTime(refundRespDTO.getSuccessTime()) + .setChannelRefundNo(refundRespDTO.getChannelRefundNo()) + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus()) + .setChannelNotifyData(toJsonString(refundRespDTO)); + assertPojoEquals(refund, refundMapper.selectById(refund.getId()), + "updateTime", "updater"); + // 断言,调用 + verify(orderService).updateOrderRefundPrice(eq(100L), eq(23)); + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()), + eq(refund.getId())); + } + + @Test + public void testNotifyRefundFailure_notFound() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()).setOutRefundNo("R100")); + + // 调用,并断言异常 + assertServiceException(() -> refundService.notifyRefund(channel, refundRespDTO), + REFUND_NOT_FOUND); + } + + @Test + public void testNotifyRefundFailure_isFailure() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 退款失败) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.FAILURE.getStatus())); + refundMapper.insert(refund); + + // 调用 + refundService.notifyRefund(channel, refundRespDTO); + // 断言,refund 没有更新,因为已经退款失败 + assertPojoEquals(refund, refundMapper.selectById(refund.getId())); + } + + @Test + public void testNotifyRefundFailure_isSuccess() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus())); + refundMapper.insert(refund); + + // 调用,并断言异常 + assertServiceException(() -> refundService.notifyRefund(channel, refundRespDTO), + REFUND_STATUS_IS_NOT_WAITING); + } + + @Test + public void testNotifyRefundFailure_success() { + // 准备参数 + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L).setAppId(1L)); + PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class, + o -> o.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()).setOutRefundNo("R100")); + // mock 数据(refund + 已支付) + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setNo("R100") + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setOrderId(100L).setRefundPrice(23)); + refundMapper.insert(refund); + + // 调用 + refundService.notifyRefund(channel, refundRespDTO); + // 断言,refund + refund.setChannelRefundNo(refundRespDTO.getChannelRefundNo()) + .setStatus(PayRefundStatusEnum.FAILURE.getStatus()) + .setChannelNotifyData(toJsonString(refundRespDTO)) + .setChannelErrorCode(refundRespDTO.getChannelErrorCode()) + .setChannelErrorMsg(refundRespDTO.getChannelErrorMsg()); + assertPojoEquals(refund, refundMapper.selectById(refund.getId()), + "updateTime", "updater"); + // 断言,调用 + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()), + eq(refund.getId())); + } + + @Test + public void testSyncRefund_notFound() { + // 准备参数 + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L) + .setStatus(PayRefundStatusEnum.WAITING.getStatus())); + refundMapper.insert(refund); + + // 调用 + int count = refundService.syncRefund(); + // 断言 + assertEquals(count, 0); + } + + @Test + public void testSyncRefund_waiting() { + assertEquals(testSyncRefund_waitingOrSuccessOrFailure(PayRefundStatusRespEnum.WAITING.getStatus()), 0); + } + + @Test + public void testSyncRefund_success() { + assertEquals(testSyncRefund_waitingOrSuccessOrFailure(PayRefundStatusRespEnum.SUCCESS.getStatus()), 1); + } + + @Test + public void testSyncRefund_failure() { + assertEquals(testSyncRefund_waitingOrSuccessOrFailure(PayRefundStatusRespEnum.FAILURE.getStatus()), 1); + } + + private int testSyncRefund_waitingOrSuccessOrFailure(Integer status) { + PayRefundServiceImpl payRefundServiceImpl = mock(PayRefundServiceImpl.class); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayRefundServiceImpl.class))) + .thenReturn(payRefundServiceImpl); + + // 准备参数 + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setChannelId(10L) + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setOrderNo("P110").setNo("R220")); + refundMapper.insert(refund); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(client 返回指定状态) + PayRefundRespDTO respDTO = randomPojo(PayRefundRespDTO.class, o -> o.setStatus(status)); + when(client.getRefund(eq("P110"), eq("R220"))).thenReturn(respDTO); + // mock 方法(channel) + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); + when(channelService.validPayChannel(eq(10L))).thenReturn(channel); + + // 调用 + return refundService.syncRefund(); + } + } + + @Test + public void testSyncRefund_exception() { + // 准备参数 + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> o.setAppId(1L).setChannelId(10L) + .setStatus(PayRefundStatusEnum.WAITING.getStatus()) + .setOrderNo("P110").setNo("R220")); + refundMapper.insert(refund); + // mock 方法(client) + PayClient client = mock(PayClient.class); + when(channelService.getPayClient(eq(10L))).thenReturn(client); + // mock 方法(client 抛出异常) + when(client.getRefund(eq("P110"), eq("R220"))).thenThrow(new RuntimeException()); + + // 调用 + int count = refundService.syncRefund(); + // 断言 + assertEquals(count, 0); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..c656a9f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,47 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..91fff0c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,7 @@ +DELETE FROM pay_app; +DELETE FROM pay_channel; +DELETE FROM pay_order; +DELETE FROM pay_order_extension; +DELETE FROM pay_refund; +DELETE FROM pay_notify_task; +DELETE FROM pay_notify_log; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..6ae2ce2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,146 @@ +CREATE TABLE IF NOT EXISTS "pay_app" ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(64) NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(255) DEFAULT NULL, + `order_notify_url` varchar(1024) NOT NULL, + `refund_notify_url` varchar(1024) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '支付应用'; + +CREATE TABLE IF NOT EXISTS "pay_channel" ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar(32) NOT NULL, + "status" tinyint(4) NOT NULL, + "remark" varchar(255) DEFAULT NULL, + "fee_rate" double NOT NULL DEFAULT 0, + "app_id" bigint(20) NOT NULL, + "config" varchar(10240) NOT NULL, + "creator" varchar(64) NULL DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) NULL DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit(1) NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT = '支付渠道'; + +CREATE TABLE IF NOT EXISTS `pay_order` ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `app_id` bigint(20) NOT NULL, + `channel_id` bigint(20) DEFAULT NULL, + `channel_code` varchar(32) DEFAULT NULL, + `merchant_order_id` varchar(64) NOT NULL, + `subject` varchar(32) NOT NULL, + `body` varchar(128) NOT NULL, + `notify_url` varchar(1024) NOT NULL, + `price` bigint(20) NOT NULL, + `channel_fee_rate` double DEFAULT 0, + `channel_fee_price` bigint(20) DEFAULT 0, + `status` tinyint(4) NOT NULL, + `user_ip` varchar(50) NOT NULL, + `expire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `success_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, + `notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, + `extension_id` bigint(20) DEFAULT NULL, + `no` varchar(64) NULL, + `refund_price` bigint(20) NOT NULL, + `channel_user_id` varchar(255) DEFAULT NULL, + `channel_order_no` varchar(64) DEFAULT NULL, + `creator` varchar(64) DEFAULT '', + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) DEFAULT '', + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '支付订单'; + +CREATE TABLE IF NOT EXISTS `pay_order_extension` ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `no` varchar(64) NOT NULL, + `order_id` bigint(20) NOT NULL, + `channel_id` bigint(20) NOT NULL, + `channel_code` varchar(32) NOT NULL, + `user_ip` varchar(50) NULL DEFAULT NULL, + `status` tinyint(4) NOT NULL, + `channel_extras` varchar(1024) NULL DEFAULT NULL, + `channel_error_code` varchar(64) NULL, + `channel_error_msg` varchar(64) NULL, + `channel_notify_data` varchar(1024) NULL, + `creator` varchar(64) NULL DEFAULT '', + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) NULL DEFAULT '', + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '支付订单拓展'; + +CREATE TABLE IF NOT EXISTS `pay_refund` ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `no` varchar(64) NOT NULL, + `app_id` bigint(20) NOT NULL, + `channel_id` bigint(20) NOT NULL, + `channel_code` varchar(32) NOT NULL, + `order_id` bigint(20) NOT NULL, + `order_no` varchar(64) NOT NULL, + `merchant_order_id` varchar(64) NOT NULL, + `merchant_refund_id` varchar(64) NOT NULL, + `notify_url` varchar(1024) NOT NULL, + `status` tinyint(4) NOT NULL, + `pay_price` bigint(20) NOT NULL, + `refund_price` bigint(20) NOT NULL, + `reason` varchar(256) NOT NULL, + `user_ip` varchar(50) NULL DEFAULT NULL, + `channel_order_no` varchar(64) NOT NULL, + `channel_refund_no` varchar(64) NULL DEFAULT NULL, + `success_time` datetime(0) NULL DEFAULT NULL, + `channel_error_code` varchar(128) NULL DEFAULT NULL, + `channel_error_msg` varchar(256) NULL DEFAULT NULL, + `channel_notify_data` varchar(1024) NULL, + `creator` varchar(64) NULL DEFAULT '', + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) NULL DEFAULT '', + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '退款订单'; + +CREATE TABLE IF NOT EXISTS `pay_notify_task` ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `app_id` bigint(20) NOT NULL, + `type` tinyint(4) NOT NULL, + `data_id` bigint(20) NOT NULL, + `merchant_order_id` varchar(64) NOT NULL, + `status` tinyint(4) NOT NULL, + `next_notify_time` datetime(0) NULL DEFAULT NULL, + `last_execute_time` datetime(0) NULL DEFAULT NULL, + `notify_times` int NOT NULL, + `max_notify_times` int NOT NULL, + `notify_url` varchar(1024) NOT NULL, + `creator` varchar(64) NULL DEFAULT '', + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) NULL DEFAULT '', + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT FALSE, + `tenant_id` bigint(20) NOT NULL DEFAULT 0, + PRIMARY KEY ("id") +) COMMENT = '支付通知任务'; + +CREATE TABLE IF NOT EXISTS `pay_notify_log` ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `task_id` bigint(20) NOT NULL, + `notify_times` int NOT NULL, + `response` varchar(1024) NOT NULL, + `status` tinyint(4) NOT NULL, + `creator` varchar(64) NULL DEFAULT '', + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) NULL DEFAULT '', + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '支付通知日志'; diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml new file mode 100644 index 0000000..93193d0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml @@ -0,0 +1,76 @@ + + + + cn.iocoder.boot + yudao-module-pay + ${revision} + + 4.0.0 + + yudao-spring-boot-starter-biz-pay + ${project.artifactId} + 支付拓展,接入国内多个支付渠道 + 1. 支付宝,基于官方 SDK 接入 + 2. 微信支付,基于 weixin-java-pay 接入 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter + + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.slf4j + slf4j-api + + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-core + + + + + com.alipay.sdk + alipay-sdk-java + 4.35.79.ALL + + + org.bouncycastle + bcprov-jdk15on + + + + + com.github.binarywang + weixin-java-pay + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java new file mode 100644 index 0000000..e57f4ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.pay.config; + +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * 支付配置类 + * + * @author 芋道源码 + */ +@AutoConfiguration +public class YudaoPayAutoConfiguration { + + @Bean + public PayClientFactory payClientFactory() { + return new PayClientFactoryImpl(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java new file mode 100644 index 0000000..86e3566 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.framework.pay.core.client; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; + +import java.util.Map; + +/** + * 支付客户端,用于对接各支付渠道的 SDK,实现发起支付、退款等功能 + * + * @author 芋道源码 + */ +public interface PayClient { + + /** + * 获得渠道编号 + * + * @return 渠道编号 + */ + Long getId(); + + // ============ 支付相关 ========== + + /** + * 调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 支付订单信息 + */ + PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO); + + /** + * 解析 order 回调数据 + * + * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 + * @param body HTTP 回调接口的 request body + * @return 支付订单信息 + */ + PayOrderRespDTO parseOrderNotify(Map params, String body); + + /** + * 获得支付订单信息 + * + * @param outTradeNo 外部订单号 + * @return 支付订单信息 + */ + PayOrderRespDTO getOrder(String outTradeNo); + + // ============ 退款相关 ========== + + /** + * 调用支付渠道,进行退款 + * + * @param reqDTO 统一退款请求信息 + * @return 退款信息 + */ + PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO); + + /** + * 解析 refund 回调数据 + * + * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 + * @param body HTTP 回调接口的 request body + * @return 支付订单信息 + */ + PayRefundRespDTO parseRefundNotify(Map params, String body); + + /** + * 获得退款订单信息 + * + * @param outTradeNo 外部订单号 + * @param outRefundNo 外部退款号 + * @return 退款订单信息 + */ + PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); + + /** + * 调用渠道,进行转账 + * + * @param reqDTO 统一转账请求信息 + * @return 转账信息 + */ + PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO); + + /** + * 获得转账订单信息 + * + * @param outTradeNo 外部订单号 + * @param type 转账类型 + * @return 转账信息 + */ + PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java new file mode 100644 index 0000000..5a38430 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.framework.pay.core.client; + +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * 支付客户端的配置,本质是支付渠道的配置 + * 每个不同的渠道,需要不同的配置,通过子类来定义 + * + * @author 芋道源码 + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +// @JsonTypeInfo 注解的作用,Jackson 多态 +// 1. 序列化到时数据库时,增加 @class 属性。 +// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 +public interface PayClientConfig { + + /** + * 参数校验 + * + * @param validator 校验对象 + */ + void validate(Validator validator); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java new file mode 100644 index 0000000..53f1a8c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.pay.core.client; + +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; + +/** + * 支付客户端的工厂接口 + * + * @author 芋道源码 + */ +public interface PayClientFactory { + + /** + * 获得支付客户端 + * + * @param channelId 渠道编号 + * @return 支付客户端 + */ + PayClient getPayClient(Long channelId); + + /** + * 创建支付客户端 + * + * @param channelId 渠道编号 + * @param channelCode 渠道编码 + * @param config 支付配置 + */ + void createOrUpdatePayClient(Long channelId, String channelCode, + Config config); + + /** + * 注册支付客户端 Class,用于模块中实现的 PayClient + * + * @param channel 支付渠道的编码的枚举 + * @param payClientClass 支付客户端 class + */ + void registerPayClientClass(PayChannelEnum channel, Class payClientClass); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java new file mode 100644 index 0000000..82050a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java @@ -0,0 +1,141 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.order; + +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 渠道支付订单 Response DTO + * + * @author 芋道源码 + */ +@Data +public class PayOrderRespDTO { + + /** + * 支付状态 + * + * 枚举:{@link PayOrderStatusRespEnum} + */ + private Integer status; + + /** + * 外部订单号 + * + * 对应 PayOrderExtensionDO 的 no 字段 + */ + private String outTradeNo; + + /** + * 支付渠道编号 + */ + private String channelOrderNo; + /** + * 支付渠道用户编号 + */ + private String channelUserId; + + /** + * 支付成功时间 + */ + private LocalDateTime successTime; + + /** + * 原始的同步/异步通知结果 + */ + private Object rawData; + + // ========== 主动发起支付时,会返回的字段 ========== + + /** + * 展示模式 + * + * 枚举 {@link PayOrderDisplayModeEnum} 类 + */ + private String displayMode; + /** + * 展示内容 + */ + private String displayContent; + + /** + * 调用渠道的错误码 + * + * 注意:这里返回的是业务异常,而是不系统异常。 + * 如果是系统异常,则会抛出 {@link PayException} + */ + private String channelErrorCode; + /** + * 调用渠道报错时,错误信息 + */ + private String channelErrorMsg; + + public PayOrderRespDTO() { + } + + /** + * 创建【WAITING】状态的订单返回 + */ + public static PayOrderRespDTO waitingOf(String displayMode, String displayContent, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = PayOrderStatusRespEnum.WAITING.getStatus(); + respDTO.displayMode = displayMode; + respDTO.displayContent = displayContent; + // 相对通用的字段 + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【SUCCESS】状态的订单返回 + */ + public static PayOrderRespDTO successOf(String channelOrderNo, String channelUserId, LocalDateTime successTime, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = PayOrderStatusRespEnum.SUCCESS.getStatus(); + respDTO.channelOrderNo = channelOrderNo; + respDTO.channelUserId = channelUserId; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建指定状态的订单返回,适合支付渠道回调时 + */ + public static PayOrderRespDTO of(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = status; + respDTO.channelOrderNo = channelOrderNo; + respDTO.channelUserId = channelUserId; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时 + */ + public static PayOrderRespDTO closedOf(String channelErrorCode, String channelErrorMsg, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = PayOrderStatusRespEnum.CLOSED.getStatus(); + respDTO.channelErrorCode = channelErrorCode; + respDTO.channelErrorMsg = channelErrorMsg; + // 相对通用的字段 + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java new file mode 100644 index 0000000..f269d2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.order; + +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import lombok.Data; +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 统一下单 Request DTO + * + * @author 芋道源码 + */ +@Data +public class PayOrderUnifiedReqDTO { + + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + // ========== 商户相关字段 ========== + + /** + * 外部订单号 + * + * 对应 PayOrderExtensionDO 的 no 字段 + */ + @NotEmpty(message = "外部订单编号不能为空") + private String outTradeNo; + /** + * 商品标题 + */ + @NotEmpty(message = "商品标题不能为空") + @Length(max = 32, message = "商品标题不能超过 32") + private String subject; + /** + * 商品描述信息 + */ + @Length(max = 128, message = "商品描述信息长度不能超过128") + private String body; + /** + * 支付结果的 notify 回调地址 + */ + @NotEmpty(message = "支付结果的回调地址不能为空") + @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") + private String notifyUrl; + /** + * 支付结果的 return 回调地址 + */ + @URL(message = "支付结果的 return 回调地址必须是 URL 格式") + private String returnUrl; + + // ========== 订单相关字段 ========== + + /** + * 支付金额,单位:分 + */ + @NotNull(message = "支付金额不能为空") + @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") + private Integer price; + + /** + * 支付过期时间 + */ + @NotNull(message = "支付过期时间不能为空") + private LocalDateTime expireTime; + + // ========== 拓展参数 ========== + /** + * 支付渠道的额外参数 + * + * 例如说,微信公众号需要传递 openid 参数 + */ + private Map channelExtras; + + /** + * 展示模式 + * + * 如果不传递,则每个支付渠道使用默认的方式 + * + * 枚举 {@link PayOrderDisplayModeEnum} + */ + private String displayMode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java new file mode 100644 index 0000000..3184f27 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java @@ -0,0 +1,115 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.refund; + +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 渠道退款订单 Response DTO + * + * @author jason + */ +@Data +public class PayRefundRespDTO { + + /** + * 退款状态 + * + * 枚举 {@link PayRefundStatusRespEnum} + */ + private Integer status; + + /** + * 外部退款号 + * + * 对应 PayRefundDO 的 no 字段 + */ + private String outRefundNo; + + /** + * 渠道退款单号 + * + * 对应 PayRefundDO.channelRefundNo 字段 + */ + private String channelRefundNo; + + /** + * 退款成功时间 + */ + private LocalDateTime successTime; + + /** + * 原始的异步通知结果 + */ + private Object rawData; + + /** + * 调用渠道的错误码 + * + * 注意:这里返回的是业务异常,而是不系统异常。 + * 如果是系统异常,则会抛出 {@link PayException} + */ + private String channelErrorCode; + /** + * 调用渠道报错时,错误信息 + */ + private String channelErrorMsg; + + private PayRefundRespDTO() { + } + + /** + * 创建【WAITING】状态的退款返回 + */ + public static PayRefundRespDTO waitingOf(String channelRefundNo, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.WAITING.getStatus(); + respDTO.channelRefundNo = channelRefundNo; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【SUCCESS】状态的退款返回 + */ + public static PayRefundRespDTO successOf(String channelRefundNo, LocalDateTime successTime, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.SUCCESS.getStatus(); + respDTO.channelRefundNo = channelRefundNo; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【FAILURE】状态的退款返回 + */ + public static PayRefundRespDTO failureOf(String outRefundNo, Object rawData) { + return failureOf(null, null, + outRefundNo, rawData); + } + + /** + * 创建【FAILURE】状态的退款返回 + */ + public static PayRefundRespDTO failureOf(String channelErrorCode, String channelErrorMsg, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus(); + respDTO.channelErrorCode = channelErrorCode; + respDTO.channelErrorMsg = channelErrorMsg; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java new file mode 100644 index 0000000..4f5e203 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.refund; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 统一 退款 Request DTO + * + * @author jason + */ +@Accessors(chain = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +public class PayRefundUnifiedReqDTO { + + /** + * 外部订单号 + * + * 对应 PayOrderExtensionDO 的 no 字段 + */ + @NotEmpty(message = "外部订单编号不能为空") + private String outTradeNo; + + /** + * 外部退款号 + * + * 对应 PayRefundDO 的 no 字段 + */ + @NotEmpty(message = "退款请求单号不能为空") + private String outRefundNo; + + /** + * 退款原因 + */ + @NotEmpty(message = "退款原因不能为空") + private String reason; + + /** + * 支付金额,单位:分 + * + * 目前微信支付在退款的时候,必须传递该字段 + */ + @NotNull(message = "支付金额不能为空") + @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") + private Integer payPrice; + /** + * 退款金额,单位:分 + */ + @NotNull(message = "退款金额不能为空") + @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") + private Integer refundPrice; + + /** + * 退款结果的 notify 回调地址 + */ + @NotEmpty(message = "支付结果的回调地址不能为空") + @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") + private String notifyUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java new file mode 100644 index 0000000..0f9b482 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.transfer; + +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 统一转账 Response DTO + * + * @author jason + */ +@Data +public class PayTransferRespDTO { + + /** + * 转账状态 + * + * 关联 {@link PayTransferStatusRespEnum#getStatus()} + */ + private Integer status; + + /** + * 外部转账单号 + * + */ + private String outTransferNo; + + /** + * 支付渠道编号 + */ + private String channelTransferNo; + + /** + * 支付成功时间 + */ + private LocalDateTime successTime; + + /** + * 原始的返回结果 + */ + private Object rawData; + + /** + * 调用渠道的错误码 + */ + private String channelErrorCode; + /** + * 调用渠道报错时,错误信息 + */ + private String channelErrorMsg; + + /** + * 创建【WAITING】状态的转账返回 + */ + public static PayTransferRespDTO waitingOf(String channelTransferNo, + String outTransferNo, Object rawData) { + PayTransferRespDTO respDTO = new PayTransferRespDTO(); + respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus(); + respDTO.channelTransferNo = channelTransferNo; + respDTO.outTransferNo = outTransferNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【IN_PROGRESS】状态的转账返回 + */ + public static PayTransferRespDTO dealingOf(String channelTransferNo, + String outTransferNo, Object rawData) { + PayTransferRespDTO respDTO = new PayTransferRespDTO(); + respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus(); + respDTO.channelTransferNo = channelTransferNo; + respDTO.outTransferNo = outTransferNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【CLOSED】状态的转账返回 + */ + public static PayTransferRespDTO closedOf(String channelErrorCode, String channelErrorMsg, + String outTransferNo, Object rawData) { + PayTransferRespDTO respDTO = new PayTransferRespDTO(); + respDTO.status = PayTransferStatusRespEnum.CLOSED.getStatus(); + respDTO.channelErrorCode = channelErrorCode; + respDTO.channelErrorMsg = channelErrorMsg; + // 相对通用的字段 + respDTO.outTransferNo = outTransferNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【SUCCESS】状态的转账返回 + */ + public static PayTransferRespDTO successOf(String channelTransferNo, LocalDateTime successTime, + String outTransferNo, Object rawData) { + PayTransferRespDTO respDTO = new PayTransferRespDTO(); + respDTO.status = PayTransferStatusRespEnum.SUCCESS.getStatus(); + respDTO.channelTransferNo = channelTransferNo; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outTransferNo = outTransferNo; + respDTO.rawData = rawData; + return respDTO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java new file mode 100644 index 0000000..9a13dda --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto.transfer; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.*; + +/** + * 统一转账 Request DTO + * + * @author jason + */ +@Data +public class PayTransferUnifiedReqDTO { + + /** + * 转账类型 + * + * 关联 {@link PayTransferTypeEnum#getType()} + */ + @NotNull(message = "转账类型不能为空") + @InEnum(PayTransferTypeEnum.class) + private Integer type; + + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + @NotEmpty(message = "外部转账单编号不能为空") + private String outTransferNo; + + /** + * 转账金额,单位:分 + */ + @NotNull(message = "转账金额不能为空") + @Min(value = 1, message = "转账金额必须大于零") + private Integer price; + + /** + * 转账标题 + */ + @NotEmpty(message = "转账标题不能为空") + @Length(max = 128, message = "转账标题不能超过 128") + private String subject; + + /** + * 收款人姓名 + */ + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class}) + private String userName; + + /** + * 支付宝登录号 + */ + @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class}) + private String alipayLogonId; + + /** + * 微信 openId + */ + @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class}) + private String openid; + + /** + * 支付渠道的额外参数 + */ + private Map channelExtras; +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java new file mode 100644 index 0000000..75f4c39 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.framework.pay.core.client.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 支付系统异常 Exception + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PayException extends RuntimeException { + + public PayException(Throwable cause) { + super(cause); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java new file mode 100644 index 0000000..82d68b5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java @@ -0,0 +1,250 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author 芋道源码 + */ +@Slf4j +public abstract class AbstractPayClient implements PayClient { + + /** + * 渠道编号 + */ + private final Long channelId; + /** + * 渠道编码 + */ + @SuppressWarnings("FieldCanBeLocal") + private final String channelCode; + /** + * 支付配置 + */ + protected Config config; + + public AbstractPayClient(Long channelId, String channelCode, Config config) { + this.channelId = channelId; + this.channelCode = channelCode; + this.config = config; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.debug("[init][客户端({}) 初始化完成]", getId()); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + public final void refresh(Config config) { + // 判断是否更新 + if (config.equals(this.config)) { + return; + } + log.info("[refresh][客户端({})发生变化,重新初始化]", getId()); + this.config = config; + // 初始化 + this.init(); + } + + @Override + public Long getId() { + return channelId; + } + + // ============ 支付相关 ========== + + @Override + public final PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + ValidationUtils.validate(reqDTO); + // 执行统一下单 + PayOrderRespDTO resp; + try { + resp = doUnifiedOrder(reqDTO); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + // 系统异常,则包装成 PayException 异常抛出 + log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]", + getId(), toJsonString(reqDTO), ex); + throw buildPayException(ex); + } + return resp; + } + + protected abstract PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) + throws Throwable; + + @Override + public final PayOrderRespDTO parseOrderNotify(Map params, String body) { + try { + return doParseOrderNotify(params, body); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]", + getId(), params, body, ex); + throw buildPayException(ex); + } + } + + protected abstract PayOrderRespDTO doParseOrderNotify(Map params, String body) + throws Throwable; + + @Override + public final PayOrderRespDTO getOrder(String outTradeNo) { + try { + return doGetOrder(outTradeNo); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[getOrder][客户端({}) outTradeNo({}) 查询支付单异常]", + getId(), outTradeNo, ex); + throw buildPayException(ex); + } + } + + protected abstract PayOrderRespDTO doGetOrder(String outTradeNo) + throws Throwable; + + // ============ 退款相关 ========== + + @Override + public final PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { + ValidationUtils.validate(reqDTO); + // 执行统一退款 + PayRefundRespDTO resp; + try { + resp = doUnifiedRefund(reqDTO); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + // 系统异常,则包装成 PayException 异常抛出 + log.error("[unifiedRefund][客户端({}) request({}) 发起退款异常]", + getId(), toJsonString(reqDTO), ex); + throw buildPayException(ex); + } + return resp; + } + + protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; + + @Override + public final PayRefundRespDTO parseRefundNotify(Map params, String body) { + try { + return doParseRefundNotify(params, body); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]", + getId(), params, body, ex); + throw buildPayException(ex); + } + } + + protected abstract PayRefundRespDTO doParseRefundNotify(Map params, String body) + throws Throwable; + + @Override + public final PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo) { + try { + return doGetRefund(outTradeNo, outRefundNo); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[getRefund][客户端({}) outTradeNo({}) outRefundNo({}) 查询退款单异常]", + getId(), outTradeNo, outRefundNo, ex); + throw buildPayException(ex); + } + } + + protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) + throws Throwable; + + @Override + public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { + validatePayTransferReqDTO(reqDTO); + PayTransferRespDTO resp; + try { + resp = doUnifiedTransfer(reqDTO); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + // 系统异常,则包装成 PayException 异常抛出 + log.error("[unifiedTransfer][客户端({}) request({}) 发起转账异常]", + getId(), toJsonString(reqDTO), ex); + throw buildPayException(ex); + } + return resp; + } + private void validatePayTransferReqDTO(PayTransferUnifiedReqDTO reqDTO) { + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); + switch (transferType) { + case ALIPAY_BALANCE: { + ValidationUtils.validate(reqDTO, PayTransferTypeEnum.Alipay.class); + break; + } + case WX_BALANCE: { + ValidationUtils.validate(reqDTO, PayTransferTypeEnum.WxPay.class); + break; + } + default: { + throw exception(NOT_IMPLEMENTED); + } + } + } + + @Override + public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { + try { + return doGetTransfer(outTradeNo, type); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[getTransfer][客户端({}) outTradeNo({}) type({}) 查询转账单异常]", + getId(), outTradeNo, type, ex); + throw buildPayException(ex); + } + } + + protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) + throws Throwable; + + protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) + throws Throwable; + + // ========== 各种工具方法 ========== + + private PayException buildPayException(Throwable ex) { + if (ex instanceof PayException) { + return (PayException) ex; + } + throw new PayException(ex); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java new file mode 100644 index 0000000..4831903 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl; + +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import lombok.Data; + +import javax.validation.Validator; + +/** + * 无需任何配置 PayClientConfig 实现类 + * + * @author jason + */ +@Data +public class NonePayClientConfig implements PayClientConfig { + + /** + * 配置名称 + *

+ * 如果不加任何属性,JsonUtils.parseObject2 解析会报错,所以暂时加个名称 + */ + private String name; + + public NonePayClientConfig(){ + this.name = "none-config"; + } + + @Override + public void validate(Validator validator) { + // 无任何配置不需要校验 + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java new file mode 100644 index 0000000..815f8d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.*; +import cn.iocoder.yudao.framework.pay.core.client.impl.mock.MockPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.*; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum.*; + +/** + * 支付客户端的工厂实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class PayClientFactoryImpl implements PayClientFactory { + + /** + * 支付客户端 Map + * + * key:渠道编号 + */ + private final ConcurrentMap> clients = new ConcurrentHashMap<>(); + + /** + * 支付客户端 Class Map + */ + private final Map> clientClass = new ConcurrentHashMap<>(); + + public PayClientFactoryImpl() { + // 微信支付客户端 + clientClass.put(WX_PUB, WxPubPayClient.class); + clientClass.put(WX_LITE, WxLitePayClient.class); + clientClass.put(WX_APP, WxAppPayClient.class); + clientClass.put(WX_BAR, WxBarPayClient.class); + clientClass.put(WX_NATIVE, WxNativePayClient.class); + clientClass.put(WX_WAP, WxWapPayClient.class); + // 支付包支付客户端 + clientClass.put(ALIPAY_WAP, AlipayWapPayClient.class); + clientClass.put(ALIPAY_QR, AlipayQrPayClient.class); + clientClass.put(ALIPAY_APP, AlipayAppPayClient.class); + clientClass.put(ALIPAY_PC, AlipayPcPayClient.class); + clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class); + // Mock 支付客户端 + clientClass.put(MOCK, MockPayClient.class); + } + + @Override + public void registerPayClientClass(PayChannelEnum channel, Class payClientClass) { + clientClass.put(channel, payClientClass); + } + + @Override + public PayClient getPayClient(Long channelId) { + AbstractPayClient client = clients.get(channelId); + if (client == null) { + log.error("[getPayClient][渠道编号({}) 找不到客户端]", channelId); + } + return client; + } + + @Override + @SuppressWarnings("unchecked") + public void createOrUpdatePayClient(Long channelId, String channelCode, + Config config) { + AbstractPayClient client = (AbstractPayClient) clients.get(channelId); + if (client == null) { + client = this.createPayClient(channelId, channelCode, config); + client.init(); + clients.put(client.getId(), client); + } else { + client.refresh(config); + } + } + + @SuppressWarnings("unchecked") + private AbstractPayClient createPayClient(Long channelId, String channelCode, + Config config) { + PayChannelEnum channelEnum = PayChannelEnum.getByCode(channelCode); + Assert.notNull(channelEnum, String.format("支付渠道(%s) 为空", channelCode)); + Class payClientClass = clientClass.get(channelEnum); + Assert.notNull(payClientClass, String.format("支付渠道(%s) Class 为空", channelCode)); + return (AbstractPayClient) ReflectUtil.newInstance(payClientClass, channelId, config); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java new file mode 100644 index 0000000..4dcf236 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java @@ -0,0 +1,342 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayConfig; +import com.alipay.api.AlipayResponse; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.*; +import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.api.request.*; +import com.alipay.api.response.*; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; + +/** + * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) + * + * @author jason + */ +@Slf4j +public abstract class AbstractAlipayPayClient extends AbstractPayClient { + + @Getter // 仅用于单测场景 + protected DefaultAlipayClient client; + + public AbstractAlipayPayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { + super(channelId, channelCode, config); + } + + @Override + @SneakyThrows + protected void doInit() { + AlipayConfig alipayConfig = new AlipayConfig(); + BeanUtil.copyProperties(config, alipayConfig, false); + this.client = new DefaultAlipayClient(alipayConfig); + } + + // ============ 支付相关 ========== + + /** + * 构造支付关闭的 {@link PayOrderRespDTO} 对象 + * + * @return 支付关闭的 {@link PayOrderRespDTO} 对象 + */ + protected PayOrderRespDTO buildClosedPayOrderRespDTO(PayOrderUnifiedReqDTO reqDTO, AlipayResponse response) { + Assert.isFalse(response.isSuccess()); + return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + reqDTO.getOutTradeNo(), response); + } + + @Override + public PayOrderRespDTO doParseOrderNotify(Map params, String body) throws Throwable { + // 1. 校验回调数据 + Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); + AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), + StandardCharsets.UTF_8.name(), config.getSignType()); + + // 2. 解析订单的状态 + // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂 + Integer status = parseStatus(bodyObj.get("trade_status")); + // 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功 + if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) { + status = PayOrderStatusRespEnum.REFUND.getStatus(); + } + Assert.notNull(status, (Supplier) () -> { + throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); + }); + return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), + bodyObj.get("out_trade_no"), body); + } + + @Override + protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { + // 1.1 构建 AlipayTradeRefundModel 请求 + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + model.setOutTradeNo(outTradeNo); + // 1.2 构建 AlipayTradeQueryRequest 请求 + AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); + request.setBizModel(model); + AlipayTradeQueryResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { + // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + if (!response.isSuccess()) { // 不成功,例如说订单不存在 + return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); + } + // 2.2 解析订单的状态 + Integer status = parseStatus(response.getTradeStatus()); + Assert.notNull(status, () -> { + throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); + }); + return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), + outTradeNo, response); + } + + private static Integer parseStatus(String tradeStatus) { + return Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus() + : ObjectUtils.equalsAny(tradeStatus, "TRADE_FINISHED", "TRADE_SUCCESS") ? PayOrderStatusRespEnum.SUCCESS.getStatus() + : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null; + } + + // ============ 退款相关 ========== + + /** + * 支付宝统一的退款接口 alipay.trade.refund + * + * @param reqDTO 退款请求 request DTO + * @return 退款请求 Response + */ + @Override + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 构建 AlipayTradeRefundModel 请求 + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setOutRequestNo(reqDTO.getOutRefundNo()); + model.setRefundAmount(formatAmount(reqDTO.getRefundPrice())); + model.setRefundReason(reqDTO.getReason()); + // 1.2 构建 AlipayTradePayRequest 请求 + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + request.setBizModel(model); + + // 2.1 执行请求 + AlipayTradeRefundResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + if (!response.isSuccess()) { + // 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询 + if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) { + return PayRefundRespDTO.waitingOf(null, reqDTO.getOutRefundNo(), response); + } + return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response); + } + // 2.2 创建返回结果 + // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。 + // 另外,支付宝没有退款单号,所以不用设置 + return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()), + reqDTO.getOutRefundNo(), response); + } + + @Override + public PayRefundRespDTO doParseRefundNotify(Map params, String body) { + // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 + // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 + // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 + // 所以,这里在解析时,即使是退款导致的订单状态同步,我们也忽略不做为“退款同步”,而是订单的回调。 + // 实际上,支付宝退款只要发起成功,就可以认为退款成功,不需要等待回调。 + throw new UnsupportedOperationException("支付宝无退款回调"); + } + + @Override + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws AlipayApiException { + // 1.1 构建 AlipayTradeFastpayRefundQueryModel 请求 + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); + model.setOutTradeNo(outTradeNo); + model.setOutRequestNo(outRefundNo); + model.setQueryOptions(Collections.singletonList("gmt_refund_pay")); + // 1.2 构建 AlipayTradeFastpayRefundQueryRequest 请求 + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + request.setBizModel(model); + + // 2.1 执行请求 + AlipayTradeFastpayRefundQueryResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + if (!response.isSuccess()) { + // 明确不存在的情况,应该就是失败,可进行关闭 + if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) { + return PayRefundRespDTO.failureOf(outRefundNo, response); + } + // 可能存在“ACQ.SYSTEM_ERROR”系统错误等情况,所以返回 WAIT 继续等待 + return PayRefundRespDTO.waitingOf(null, outRefundNo, response); + } + // 2.2 创建返回结果 + if (Objects.equals(response.getRefundStatus(), "REFUND_SUCCESS")) { + return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()), + outRefundNo, response); + } + return PayRefundRespDTO.waitingOf(null, outRefundNo, response); + } + + @Override + protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 校验公钥类型 必须使用公钥证书模式 + if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) { + throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式"); + } + // 1.2 构建 AlipayFundTransUniTransferModel + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); + // ① 通用的参数 + model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额 + model.setOrderTitle(reqDTO.getSubject()); // 转账业务的标题,用于在支付宝用户的账单里显示。 + model.setOutBizNo(reqDTO.getOutTransferNo()); + model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD + model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER + if (reqDTO.getChannelExtras() != null) { + model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); + } + // ② 个性化的参数 + Participant payeeInfo = new Participant(); + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); + switch (transferType) { + // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦? + // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试?? + case ALIPAY_BALANCE: { + payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); + payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号 + payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名 + model.setPayeeInfo(payeeInfo); + break; + } + case BANK_CARD: { + payeeInfo.setIdentityType("BANKCARD_ACCOUNT"); + // TODO 待实现 + throw exception(NOT_IMPLEMENTED); + } + default: { + throw exception0(BAD_REQUEST.getCode(), "不正确的转账类型: {}", transferType); + } + } + // 1.3 构建 AlipayFundTransUniTransferRequest + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + request.setBizModel(model); + // 执行请求 + AlipayFundTransUniTransferResponse response = client.certificateExecute(request); + // 处理结果 + if (!response.isSuccess()) { + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账 + // 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询 + if (ObjectUtils.equalsAny(response.getSubCode(),"PAYMENT_INFO_INCONSISTENCY", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { + return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response); + } + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + reqDTO.getOutTransferNo(), response); + } else { + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + reqDTO.getOutTransferNo(), response); + } + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 + return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response); + } + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), + response.getOutBizNo(), response); + } + + } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) throws Throwable { + // 1.1 构建 AlipayFundTransCommonQueryModel + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); + model.setProductCode(type == PayTransferTypeEnum.BANK_CARD ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD"); + model.setBizScene("DIRECT_TRANSFER"); //业务场景 + model.setOutBizNo(outTradeNo); + // 1.2 构建 AlipayFundTransCommonQueryRequest + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); + request.setBizModel(model); + + // 2.1 执行请求 + AlipayFundTransCommonQueryResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + // 2.2 处理返回结果 + if (response.isSuccess()) { + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); + } + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 + return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response); + } + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()), + response.getOutBizNo(), response); + } else { + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 + // 当出现 ORDER_NOT_EXIST 可能是转账还在处理中,也可能是转账处理失败. 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 + if (ObjectUtils.equalsAny(response.getSubCode(), "ORDER_NOT_EXIST", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { + return PayTransferRespDTO.waitingOf(null, outTradeNo, response); + } + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); + } + } + + // ========== 各种工具方法 ========== + + protected String formatAmount(Integer amount) { + return String.valueOf(amount / 100.0); + } + + protected String formatTime(LocalDateTime time) { + return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER); + } + + protected LocalDateTime parseTime(String str) { + return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java new file mode 100644 index 0000000..4e5a37e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeAppPayModel; +import com.alipay.api.request.AlipayTradeAppPayRequest; +import com.alipay.api.response.AlipayTradeAppPayResponse; +import lombok.extern.slf4j.Slf4j; + +/** + * 支付宝【App 支付】的 PayClient 实现类 + * + * 文档:App 支付 + * + * // TODO 芋艿:未详细测试,因为手头没 App + * + * @author 芋道源码 + */ +@Slf4j +public class AlipayAppPayClient extends AbstractAlipayPayClient { + + public AlipayAppPayClient(Long channelId, AlipayPayClientConfig config) { + super(channelId, PayChannelEnum.ALIPAY_APP.getCode(), config); + } + + @Override + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 构建 AlipayTradeAppPayModel 请求 + AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); + // ① 通用的参数 + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setSubject(reqDTO.getSubject()); + model.setBody(reqDTO.getBody() + "test"); + model.setTotalAmount(formatAmount(reqDTO.getPrice())); + model.setTimeExpire(formatTime(reqDTO.getExpireTime())); + model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码:无线快捷支付产品 + // ② 个性化的参数【无】 + // ③ 支付宝扫码支付只有一种展示 + String displayMode = PayOrderDisplayModeEnum.APP.getMode(); + + // 1.2 构建 AlipayTradePrecreateRequest 请求 + AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); + request.setBizModel(model); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); + + // 2.1 执行请求 + AlipayTradeAppPayResponse response = client.sdkExecute(request); + // 2.2 处理结果 + if (!response.isSuccess()) { + return buildClosedPayOrderRespDTO(reqDTO, response); + } + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), + reqDTO.getOutTradeNo(), response); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java new file mode 100644 index 0000000..1f90d6b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePayModel; +import com.alipay.api.request.AlipayTradePayRequest; +import com.alipay.api.response.AlipayTradePayResponse; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; + +/** + * 支付宝【条码支付】的 PayClient 实现类 + * + * 文档:当面付 + * + * @author 芋道源码 + */ +@Slf4j +public class AlipayBarPayClient extends AbstractAlipayPayClient { + + public AlipayBarPayClient(Long channelId, AlipayPayClientConfig config) { + super(channelId, PayChannelEnum.ALIPAY_BAR.getCode(), config); + } + + @Override + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { + String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "auth_code"); + if (StrUtil.isEmpty(authCode)) { + throw exception0(BAD_REQUEST.getCode(), "条形码不能为空"); + } + + // 1.1 构建 AlipayTradePayModel 请求 + AlipayTradePayModel model = new AlipayTradePayModel(); + // ① 通用的参数 + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setSubject(reqDTO.getSubject()); + model.setBody(reqDTO.getBody()); + model.setTotalAmount(formatAmount(reqDTO.getPrice())); + model.setScene("bar_code"); // 当面付条码支付场景 + // ② 个性化的参数 + model.setAuthCode(authCode); + // ③ 支付宝条码支付只有一种展示 + String displayMode = PayOrderDisplayModeEnum.BAR_CODE.getMode(); + + // 1.2 构建 AlipayTradePayRequest 请求 + AlipayTradePayRequest request = new AlipayTradePayRequest(); + request.setBizModel(model); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); + + // 2.1 执行请求 + AlipayTradePayResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { + // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + // 2.2 处理结果 + if (!response.isSuccess()) { + return buildClosedPayOrderRespDTO(reqDTO, response); + } + if ("10000".equals(response.getCode())) { // 免密支付 + LocalDateTime successTime = LocalDateTimeUtil.of(response.getGmtPayment()); + return PayOrderRespDTO.successOf(response.getTradeNo(), response.getBuyerUserId(), successTime, + response.getOutTradeNo(), response) + .setDisplayMode(displayMode).setDisplayContent(""); + } + // 大额支付,需要用户输入密码,所以返回 waiting。此时,前端一般会进行轮询 + return PayOrderRespDTO.waitingOf(displayMode, "", + reqDTO.getOutTradeNo(), response); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java new file mode 100644 index 0000000..066ff01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import lombok.Data; + +import javax.validation.ConstraintViolation; +import javax.validation.Validator; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + * 支付宝的 PayClientConfig 实现类 + * 属性主要来自 {@link com.alipay.api.AlipayConfig} 的必要属性 + * + * @author 芋道源码 + */ +@Data +public class AlipayPayClientConfig implements PayClientConfig { + + /** + * 公钥类型 - 公钥模式 + */ + public static final Integer MODE_PUBLIC_KEY = 1; + /** + * 公钥类型 - 证书模式 + */ + public static final Integer MODE_CERTIFICATE = 2; + + /** + * 签名算法类型 - RSA + */ + public static final String SIGN_TYPE_DEFAULT = "RSA2"; + + /** + * 网关地址 + * + * 1. 生产环境 + * 2. 沙箱环境 + */ + @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) + private String serverUrl; + + /** + * 开放平台上创建的应用的 ID + */ + @NotBlank(message = "开放平台上创建的应用的 ID不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) + private String appId; + + /** + * 签名算法类型,推荐:RSA2 + *

+ * {@link #SIGN_TYPE_DEFAULT} + */ + @NotBlank(message = "签名算法类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) + private String signType; + + /** + * 公钥类型 + * 1. {@link #MODE_PUBLIC_KEY} 情况,privateKey + alipayPublicKey + * 2. {@link #MODE_CERTIFICATE} 情况,appCertContent + alipayPublicCertContent + rootCertContent + */ + @NotNull(message = "公钥类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) + private Integer mode; + + // ========== 公钥模式 ========== + /** + * 商户私钥 + */ + @NotBlank(message = "商户私钥不能为空", groups = {ModePublicKey.class}) + private String privateKey; + + /** + * 支付宝公钥字符串 + */ + @NotBlank(message = "支付宝公钥字符串不能为空", groups = {ModePublicKey.class}) + private String alipayPublicKey; + + // ========== 证书模式 ========== + /** + * 指定商户公钥应用证书内容字符串 + */ + @NotBlank(message = "指定商户公钥应用证书内容不能为空", groups = {ModeCertificate.class}) + private String appCertContent; + /** + * 指定支付宝公钥证书内容字符串 + */ + @NotBlank(message = "指定支付宝公钥证书内容不能为空", groups = {ModeCertificate.class}) + private String alipayPublicCertContent; + /** + * 指定根证书内容字符串 + */ + @NotBlank(message = "指定根证书内容字符串不能为空", groups = {ModeCertificate.class}) + private String rootCertContent; + + public interface ModePublicKey { + } + + public interface ModeCertificate { + } + + @Override + public void validate(Validator validator) { + ValidationUtils.validate(validator, this, + MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java new file mode 100644 index 0000000..6dbd19b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.Method; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePagePayModel; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.alipay.api.response.AlipayTradePagePayResponse; +import lombok.extern.slf4j.Slf4j; + +import java.util.Objects; + +/** + * 支付宝【PC 网站】的 PayClient 实现类 + * + * 文档:电脑网站支付 + * + * @author XGD + */ +@Slf4j +public class AlipayPcPayClient extends AbstractAlipayPayClient { + + public AlipayPcPayClient(Long channelId, AlipayPayClientConfig config) { + super(channelId, PayChannelEnum.ALIPAY_PC.getCode(), config); + } + + @Override + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 构建 AlipayTradePagePayModel 请求 + AlipayTradePagePayModel model = new AlipayTradePagePayModel(); + // ① 通用的参数 + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setSubject(reqDTO.getSubject()); + model.setBody(reqDTO.getBody()); + model.setTotalAmount(formatAmount(reqDTO.getPrice())); + model.setTimeExpire(formatTime(reqDTO.getExpireTime())); + model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前 PC 支付场景下仅支持 FAST_INSTANT_TRADE_PAY + // ② 个性化的参数 + // 如果想弄更多个性化的参数,可参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分进行拓展 + model.setQrPayMode("2"); // 跳转模式 - 订单码,效果参见:https://help.pingxx.com/article/1137360/ + // ③ 支付宝 PC 支付有两种展示模式:FORM、URL + String displayMode = ObjectUtil.defaultIfNull(reqDTO.getDisplayMode(), + PayOrderDisplayModeEnum.URL.getMode()); + + // 1.2 构建 AlipayTradePagePayRequest 请求 + AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); + request.setBizModel(model); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); + + // 2.1 执行请求 + AlipayTradePagePayResponse response; + if (Objects.equals(displayMode, PayOrderDisplayModeEnum.FORM.getMode())) { + response = client.pageExecute(request, Method.POST.name()); // 需要特殊使用 POST 请求 + } else { + response = client.pageExecute(request, Method.GET.name()); + } + // 2.2 处理结果 + if (!response.isSuccess()) { + return buildClosedPayOrderRespDTO(reqDTO, response); + } + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), + reqDTO.getOutTradeNo(), response); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java new file mode 100644 index 0000000..bb3ad17 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePrecreateModel; +import com.alipay.api.request.AlipayTradePrecreateRequest; +import com.alipay.api.response.AlipayTradePrecreateResponse; +import lombok.extern.slf4j.Slf4j; + +import java.util.Objects; + +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; + +/** + * 支付宝【扫码支付】的 PayClient 实现类 + * + * 文档:扫码支付 + * + * @author 芋道源码 + */ +@Slf4j +public class AlipayQrPayClient extends AbstractAlipayPayClient { + + public AlipayQrPayClient(Long channelId, AlipayPayClientConfig config) { + super(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config); + } + + @Override + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 构建 AlipayTradePrecreateModel 请求 + AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); + // ① 通用的参数 + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setSubject(reqDTO.getSubject()); + model.setBody(reqDTO.getBody()); + model.setTotalAmount(formatAmount(reqDTO.getPrice())); + model.setProductCode("FACE_TO_FACE_PAYMENT"); // 销售产品码. 目前扫码支付场景下仅支持 FACE_TO_FACE_PAYMENT + // ② 个性化的参数【无】 + // ③ 支付宝扫码支付只有一种展示,考虑到前端可能希望二维码扫描后,手机打开 + String displayMode = PayOrderDisplayModeEnum.QR_CODE.getMode(); + + // 1.2 构建 AlipayTradePrecreateRequest 请求 + AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); + request.setBizModel(model); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); + + // 2.1 执行请求 + AlipayTradePrecreateResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { + // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + // 2.2 处理结果 + if (!response.isSuccess()) { + return buildClosedPayOrderRespDTO(reqDTO, response); + } + return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(), + reqDTO.getOutTradeNo(), response); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java new file mode 100644 index 0000000..2bc2163 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.http.Method; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeWapPayModel; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.alipay.api.response.AlipayTradeWapPayResponse; +import lombok.extern.slf4j.Slf4j; + +/** + * 支付宝【Wap 网站】的 PayClient 实现类 + * + * 文档:手机网站支付接口 + * + * @author 芋道源码 + */ +@Slf4j +public class AlipayWapPayClient extends AbstractAlipayPayClient { + + public AlipayWapPayClient(Long channelId, AlipayPayClientConfig config) { + super(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config); + } + + @Override + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { + // 1.1 构建 AlipayTradeWapPayModel 请求 + AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); + // ① 通用的参数 + model.setOutTradeNo(reqDTO.getOutTradeNo()); + model.setSubject(reqDTO.getSubject()); + model.setBody(reqDTO.getBody()); + model.setTotalAmount(formatAmount(reqDTO.getPrice())); + model.setProductCode("QUICK_WAP_PAY"); // 销售产品码. 目前 Wap 支付场景下仅支持 QUICK_WAP_PAY + // ② 个性化的参数【无】 + // ③ 支付宝 Wap 支付只有一种展示:URL + String displayMode = PayOrderDisplayModeEnum.URL.getMode(); + + // 1.2 构建 AlipayTradeWapPayRequest 请求 + AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); + request.setBizModel(model); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); + model.setQuitUrl(reqDTO.getReturnUrl()); + model.setTimeExpire(formatTime(reqDTO.getExpireTime())); + + // 2.1 执行请求 + AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name()); + // 2.2 处理结果 + if (!response.isSuccess()) { + return buildClosedPayOrderRespDTO(reqDTO, response); + } + return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), + reqDTO.getOutTradeNo(), response); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java new file mode 100644 index 0000000..1ad1ad7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.mock; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 模拟支付的 PayClient 实现类 + * + * 模拟支付返回结果都是成功,方便大家日常流畅 + * + * @author jason + */ +public class MockPayClient extends AbstractPayClient { + + private static final String MOCK_RESP_SUCCESS_DATA = "MOCK_SUCCESS"; + + public MockPayClient(Long channelId, NonePayClientConfig config) { + super(channelId, PayChannelEnum.MOCK.getCode(), config); + } + + @Override + protected void doInit() { + } + + @Override + protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + return PayOrderRespDTO.successOf("MOCK-P-" + reqDTO.getOutTradeNo(), "", LocalDateTime.now(), + reqDTO.getOutTradeNo(), MOCK_RESP_SUCCESS_DATA); + } + + @Override + protected PayOrderRespDTO doGetOrder(String outTradeNo) { + return PayOrderRespDTO.successOf("MOCK-P-" + outTradeNo, "", LocalDateTime.now(), + outTradeNo, MOCK_RESP_SUCCESS_DATA); + } + + @Override + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { + return PayRefundRespDTO.successOf("MOCK-R-" + reqDTO.getOutRefundNo(), LocalDateTime.now(), + reqDTO.getOutRefundNo(), MOCK_RESP_SUCCESS_DATA); + } + + @Override + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { + return PayRefundRespDTO.successOf("MOCK-R-" + outRefundNo, LocalDateTime.now(), + outRefundNo, MOCK_RESP_SUCCESS_DATA); + } + + @Override + protected PayRefundRespDTO doParseRefundNotify(Map params, String body) { + throw new UnsupportedOperationException("模拟支付无退款回调"); + } + + @Override + protected PayOrderRespDTO doParseOrderNotify(Map params, String body) { + throw new UnsupportedOperationException("模拟支付无支付回调"); + } + + @Override + protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { + throw new UnsupportedOperationException("待实现"); + } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java new file mode 100644 index 0000000..163f97c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -0,0 +1,484 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.date.TemporalAccessorUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; +import com.github.binarywang.wxpay.bean.request.*; +import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Map; +import java.util.Objects; + +import static cn.hutool.core.date.DatePattern.*; +import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig.API_VERSION_V2; + +/** + * 微信支付抽象类,实现微信统一的接口、以及部分实现(退款) + * + * @author 遇到源码 + */ +@Slf4j +public abstract class AbstractWxPayClient extends AbstractPayClient { + + protected WxPayService client; + + public AbstractWxPayClient(Long channelId, String channelCode, WxPayClientConfig config) { + super(channelId, channelCode, config); + } + + /** + * 初始化 client 客户端 + * + * @param tradeType 交易类型 + */ + protected void doInit(String tradeType) { + // 创建 config 配置 + WxPayConfig payConfig = new WxPayConfig(); + BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "privateCertContent"); + payConfig.setTradeType(tradeType); + // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决 + if (Base64.isBase64(config.getKeyContent())) { + payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath()); + } + if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { + payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); + } + if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { + payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); + } +// payConfig.setCertSerialNo(); + + // 创建 client 客户端 + client = new WxPayServiceImpl(); + client.setConfig(payConfig); + } + + // ============ 支付相关 ========== + + @Override + protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception { + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doUnifiedOrderV2(reqDTO); + case WxPayClientConfig.API_VERSION_V3: + return doUnifiedOrderV3(reqDTO); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayOrderRespDTO.closedOf(errorCode, errorMessage, + reqDTO.getOutTradeNo(), e.getXmlString()); + } + } + + /** + * 【V2】调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 各支付渠道的返回结果 + */ + protected abstract PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) + throws Exception; + + /** + * 【V3】调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 各支付渠道的返回结果 + */ + protected abstract PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) + throws WxPayException; + + /** + * 【V2】创建微信下单请求 + * + * @param reqDTO 下信息 + * @return 下单请求 + */ + protected WxPayUnifiedOrderRequest buildPayUnifiedOrderRequestV2(PayOrderUnifiedReqDTO reqDTO) { + return WxPayUnifiedOrderRequest.newBuilder() + .outTradeNo(reqDTO.getOutTradeNo()) + .body(reqDTO.getSubject()) + .detail(reqDTO.getBody()) + .totalFee(reqDTO.getPrice()) // 单位分 + .timeExpire(formatDateV2(reqDTO.getExpireTime())) + .spbillCreateIp(reqDTO.getUserIp()) + .notifyUrl(reqDTO.getNotifyUrl()) + .build(); + } + + /** + * 【V3】创建微信下单请求 + * + * @param reqDTO 下信息 + * @return 下单请求 + */ + protected WxPayUnifiedOrderV3Request buildPayUnifiedOrderRequestV3(PayOrderUnifiedReqDTO reqDTO) { + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); + request.setOutTradeNo(reqDTO.getOutTradeNo()); + request.setDescription(reqDTO.getSubject()); + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getPrice())); // 单位分 + request.setTimeExpire(formatDateV3(reqDTO.getExpireTime())); + request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + return request; + } + + @Override + public PayOrderRespDTO doParseOrderNotify(Map params, String body) throws WxPayException { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doParseOrderNotifyV2(body); + case WxPayClientConfig.API_VERSION_V3: + return doParseOrderNotifyV3(body); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } + + private PayOrderRespDTO doParseOrderNotifyV2(String body) throws WxPayException { + // 1. 解析回调 + WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body); + // 2. 构建结果 + // V2 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂 + Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ? + PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); + return PayOrderRespDTO.of(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), + response.getOutTradeNo(), body); + } + + private PayOrderRespDTO doParseOrderNotifyV3(String body) throws WxPayException { + // 1. 解析回调 + WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); + WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult(); + // 2. 构建结果 + Integer status = parseStatus(result.getTradeState()); + String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null; + return PayOrderRespDTO.of(status, result.getTransactionId(), openid, parseDateV3(result.getSuccessTime()), + result.getOutTradeNo(), body); + } + + @Override + protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doGetOrderV2(outTradeNo); + case WxPayClientConfig.API_VERSION_V3: + return doGetOrderV3(outTradeNo); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + if (ObjectUtils.equalsAny(e.getErrCode(), "ORDERNOTEXIST", "ORDER_NOT_EXIST")) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayOrderRespDTO.closedOf(errorCode, errorMessage, + outTradeNo, e.getXmlString()); + } + throw e; + } + } + + private PayOrderRespDTO doGetOrderV2(String outTradeNo) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayOrderQueryRequest request = WxPayOrderQueryRequest.newBuilder() + .outTradeNo(outTradeNo).build(); + // 执行请求 + WxPayOrderQueryResult response = client.queryOrder(request); + + // 转换结果 + Integer status = parseStatus(response.getTradeState()); + return PayOrderRespDTO.of(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), + outTradeNo, response); + } + + private PayOrderRespDTO doGetOrderV3(String outTradeNo) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request() + .setOutTradeNo(outTradeNo); + // 执行请求 + WxPayOrderQueryV3Result response = client.queryOrderV3(request); + + // 转换结果 + Integer status = parseStatus(response.getTradeState()); + String openid = response.getPayer() != null ? response.getPayer().getOpenid() : null; + return PayOrderRespDTO.of(status, response.getTransactionId(), openid, parseDateV3(response.getSuccessTime()), + outTradeNo, response); + } + + private static Integer parseStatus(String tradeState) { + switch (tradeState) { + case "NOTPAY": + case "USERPAYING": // 支付中,等待用户输入密码(条码支付独有) + return PayOrderStatusRespEnum.WAITING.getStatus(); + case "SUCCESS": + return PayOrderStatusRespEnum.SUCCESS.getStatus(); + case "REFUND": + return PayOrderStatusRespEnum.REFUND.getStatus(); + case "CLOSED": + case "REVOKED": // 已撤销(刷卡支付独有) + case "PAYERROR": // 支付失败(其它原因,如银行返回失败) + return PayOrderStatusRespEnum.CLOSED.getStatus(); + default: + throw new IllegalArgumentException(StrUtil.format("未知的支付状态({})", tradeState)); + } + } + + // ============ 退款相关 ========== + + @Override + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doUnifiedRefundV2(reqDTO); + case WxPayClientConfig.API_VERSION_V3: + return doUnifiedRefundV3(reqDTO); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayRefundRespDTO.failureOf(errorCode, errorMessage, + reqDTO.getOutRefundNo(), e.getXmlString()); + } + } + + private PayRefundRespDTO doUnifiedRefundV2(PayRefundUnifiedReqDTO reqDTO) throws Throwable { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundRequest request = new WxPayRefundRequest() + .setOutTradeNo(reqDTO.getOutTradeNo()) + .setOutRefundNo(reqDTO.getOutRefundNo()) + .setRefundFee(reqDTO.getRefundPrice()) + .setRefundDesc(reqDTO.getReason()) + .setTotalFee(reqDTO.getPayPrice()) + .setNotifyUrl(reqDTO.getNotifyUrl()); + // 2.1 执行请求 + WxPayRefundResult response = client.refundV2(request); + // 2.2 创建返回结果 + if (Objects.equals("SUCCESS", response.getResultCode())) { // V2 情况下,不直接返回退款成功,而是等待异步通知 + return PayRefundRespDTO.waitingOf(response.getRefundId(), + reqDTO.getOutRefundNo(), response); + } + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); + } + + private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundV3Request request = new WxPayRefundV3Request() + .setOutTradeNo(reqDTO.getOutTradeNo()) + .setOutRefundNo(reqDTO.getOutRefundNo()) + .setAmount(new WxPayRefundV3Request.Amount().setRefund(reqDTO.getRefundPrice()) + .setTotal(reqDTO.getPayPrice()).setCurrency("CNY")) + .setReason(reqDTO.getReason()) + .setNotifyUrl(reqDTO.getNotifyUrl()); + // 2.1 执行请求 + WxPayRefundV3Result response = client.refundV3(request); + // 2.2 创建返回结果 + if (Objects.equals("SUCCESS", response.getStatus())) { + return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()), + reqDTO.getOutRefundNo(), response); + } + if (Objects.equals("PROCESSING", response.getStatus())) { + return PayRefundRespDTO.waitingOf(response.getRefundId(), + reqDTO.getOutRefundNo(), response); + } + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); + } + + @Override + public PayRefundRespDTO doParseRefundNotify(Map params, String body) throws WxPayException { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doParseRefundNotifyV2(body); + case WxPayClientConfig.API_VERSION_V3: + return parseRefundNotifyV3(body); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } + + private PayRefundRespDTO doParseRefundNotifyV2(String body) throws WxPayException { + // 1. 解析回调 + WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body); + WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo(); + // 2. 构建结果 + if (Objects.equals("SUCCESS", result.getRefundStatus())) { + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV2B(result.getSuccessTime()), + result.getOutRefundNo(), response); + } + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); + } + + private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { + // 1. 解析回调 + WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); + WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult(); + // 2. 构建结果 + if (Objects.equals("SUCCESS", result.getRefundStatus())) { + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV3(result.getSuccessTime()), + result.getOutRefundNo(), response); + } + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); + } + + @Override + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doGetRefundV2(outTradeNo, outRefundNo); + case WxPayClientConfig.API_VERSION_V3: + return doGetRefundV3(outTradeNo, outRefundNo); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + if (ObjectUtils.equalsAny(e.getErrCode(), "REFUNDNOTEXIST", "RESOURCE_NOT_EXISTS")) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayRefundRespDTO.failureOf(errorCode, errorMessage, + outRefundNo, e.getXmlString()); + } + throw e; + } + } + + private PayRefundRespDTO doGetRefundV2(String outTradeNo, String outRefundNo) throws WxPayException { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundQueryRequest request = WxPayRefundQueryRequest.newBuilder() + .outTradeNo(outTradeNo) + .outRefundNo(outRefundNo) + .build(); + // 2.1 执行请求 + WxPayRefundQueryResult response = client.refundQuery(request); + // 2.2 创建返回结果 + if (!Objects.equals("SUCCESS", response.getResultCode())) { + return PayRefundRespDTO.waitingOf(null, + outRefundNo, response); + } + WxPayRefundQueryResult.RefundRecord refund = CollUtil.findOne(response.getRefundRecords(), + record -> record.getOutRefundNo().equals(outRefundNo)); + if (refund == null) { + return PayRefundRespDTO.failureOf(outRefundNo, response); + } + switch (refund.getRefundStatus()) { + case "SUCCESS": + return PayRefundRespDTO.successOf(refund.getRefundId(), parseDateV2B(refund.getRefundSuccessTime()), + outRefundNo, response); + case "PROCESSING": + return PayRefundRespDTO.waitingOf(refund.getRefundId(), + outRefundNo, response); + case "CHANGE": // 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款 + case "FAIL": + return PayRefundRespDTO.failureOf(outRefundNo, response); + default: + throw new IllegalArgumentException(String.format("未知的退款状态(%s)", refund.getRefundStatus())); + } + } + + private PayRefundRespDTO doGetRefundV3(String outTradeNo, String outRefundNo) throws WxPayException { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundQueryV3Request request = new WxPayRefundQueryV3Request(); + request.setOutRefundNo(outRefundNo); + // 2.1 执行请求 + WxPayRefundQueryV3Result response = client.refundQueryV3(request); + // 2.2 创建返回结果 + switch (response.getStatus()) { + case "SUCCESS": + return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()), + outRefundNo, response); + case "PROCESSING": + return PayRefundRespDTO.waitingOf(response.getRefundId(), + outRefundNo, response); + case "ABNORMAL": // 退款异常 + case "CLOSED": + return PayRefundRespDTO.failureOf(outRefundNo, response); + default: + throw new IllegalArgumentException(String.format("未知的退款状态(%s)", response.getStatus())); + } + } + + @Override + protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { + throw new UnsupportedOperationException("待实现"); + } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + + // ========== 各种工具方法 ========== + + static String formatDateV2(LocalDateTime time) { + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN); + } + + static LocalDateTime parseDateV2(String time) { + return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN); + } + + static LocalDateTime parseDateV2B(String time) { + return LocalDateTimeUtil.parse(time, NORM_DATETIME_PATTERN); + } + + static String formatDateV3(LocalDateTime time) { + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN); + } + + static LocalDateTime parseDateV3(String time) { + return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN); + } + + static String getErrorCode(WxPayException e) { + if (StrUtil.isNotEmpty(e.getErrCode())) { + return e.getErrCode(); + } + if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { + return "CUSTOM_ERROR"; + } + return e.getReturnCode(); + } + + static String getErrorMessage(WxPayException e) { + if (StrUtil.isNotEmpty(e.getErrCode())) { + return e.getErrCodeDes(); + } + if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { + return e.getCustomErrorMsg(); + } + return e.getReturnMsg(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java new file mode 100644 index 0000000..396694a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 微信支付【App 支付】的 PayClient 实现类 + * + * 文档:App 支付 + * + * // TODO 芋艿:未详细测试,因为手头没 App + * + * @author 芋道源码 + */ +@Slf4j +public class WxAppPayClient extends AbstractWxPayClient { + + public WxAppPayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_APP.getCode(), config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.APP); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO); + // 执行请求 + WxPayMpOrderResult response = client.createOrder(request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), + reqDTO.getOutTradeNo(), response); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderV3Request 对象 + WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO); + // 执行请求 + WxPayUnifiedOrderV3Result.AppResult response = client.createOrderV3(TradeTypeEnum.APP, request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), + reqDTO.getOutTradeNo(), response); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java new file mode 100644 index 0000000..d01b504 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 微信支付【付款码支付】的 PayClient 实现类 + * + * 文档:付款码支付 + * + * @author 芋道源码 + */ +@Slf4j +public class WxBarPayClient extends AbstractWxPayClient { + + /** + * 微信付款码的过期时间 + */ + private static final Duration AUTH_CODE_EXPIRE = Duration.ofMinutes(3); + + public WxBarPayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_BAR.getCode(), config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.MICROPAY); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 由于付款码需要不断轮询,所以需要在较短的时间完成支付 + LocalDateTime expireTime = LocalDateTimeUtils.addTime(AUTH_CODE_EXPIRE); + if (expireTime.isAfter(reqDTO.getExpireTime())) { + expireTime = reqDTO.getExpireTime(); + } + // 构建 WxPayMicropayRequest 对象 + WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() + .outTradeNo(reqDTO.getOutTradeNo()) + .body(reqDTO.getSubject()) + .detail(reqDTO.getBody()) + .totalFee(reqDTO.getPrice()) // 单位分 + .timeExpire(formatDateV2(expireTime)) + .spbillCreateIp(reqDTO.getUserIp()) + .authCode(getAuthCode(reqDTO)) + .build(); + // 执行请求,重试直到失败(过期),或者成功 + WxPayException lastWxPayException = null; + for (int i = 1; i < Byte.MAX_VALUE; i++) { + try { + WxPayMicropayResult response = client.micropay(request); + // 支付成功,例如说:1)用户输入了密码;2)用户免密支付 + return PayOrderRespDTO.successOf(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), + response.getOutTradeNo(), response) + .setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode()); + } catch (WxPayException ex) { + lastWxPayException = ex; + // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理 + // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。 + // 2. USERPAYING:用户支付中,需要输入密码:等待 5 秒,然后调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。 + // 3. BANKERROR:银行系统异常:请立即调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。 + if (!StrUtil.equalsAny(ex.getErrCode(), "SYSTEMERROR", "USERPAYING", "BANKERROR")) { + throw ex; + } + // 等待 5 秒,继续下一轮重新发起支付 + log.info("[doUnifiedOrderV2][发起微信 Bar 支付第({})失败,等待下一轮重试,请求({}),响应({})]", i, + toJsonString(request), ex.getMessage()); + ThreadUtil.sleep(5, TimeUnit.SECONDS); + } + } + throw lastWxPayException; + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + return doUnifiedOrderV2(reqDTO); + } + + // ========== 各种工具方法 ========== + + static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) { + String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode"); + if (StrUtil.isEmpty(authCode)) { + throw invalidParamException("支付请求的 authCode 不能为空!"); + } + return authCode; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java new file mode 100644 index 0000000..9929955 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import lombok.extern.slf4j.Slf4j; + +/** + * 微信支付【小程序】的 PayClient 实现类 + * + * 由于公众号和小程序的微信支付逻辑一致,所以直接进行继承 + * + * 文档:JSAPI 下单 + * + * @author zwy + */ +@Slf4j +public class WxLitePayClient extends WxPubPayClient { + + public WxLitePayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_LITE.getCode(), config); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java new file mode 100644 index 0000000..5a07350 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +/** + * 微信支付【Native 二维码】的 PayClient 实现类 + * + * 文档:Native 下单 + * + * @author zwy + */ +@Slf4j +public class WxNativePayClient extends AbstractWxPayClient { + + public WxNativePayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_NATIVE.getCode(), config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.NATIVE); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO); + // 执行请求 + WxPayNativeOrderResult response = client.createOrder(request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(), + reqDTO.getOutTradeNo(), response); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderV3Request 对象 + WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO); + // 执行请求 + String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response, + reqDTO.getOutTradeNo(), response); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java new file mode 100644 index 0000000..77027ae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import lombok.Data; + +import javax.validation.Validator; +import javax.validation.constraints.NotBlank; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +/** + * 微信支付的 PayClientConfig 实现类 + * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 + * + * @author 芋道源码 + */ +@Data +public class WxPayClientConfig implements PayClientConfig { + + /** + * API 版本 - V2 + * + * V2 协议说明 + */ + public static final String API_VERSION_V2 = "v2"; + /** + * API 版本 - V3 + * + * V3 协议说明 + */ + public static final String API_VERSION_V3 = "v3"; + + /** + * 公众号或者小程序的 appid + * + * 只有公众号或小程序需要该字段 + */ + @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class}) + private String appId; + /** + * 商户号 + */ + @NotBlank(message = "商户号不能为空", groups = {V2.class, V3.class}) + private String mchId; + /** + * API 版本 + */ + @NotBlank(message = "API 版本不能为空", groups = {V2.class, V3.class}) + private String apiVersion; + + // ========== V2 版本的参数 ========== + + /** + * 商户密钥 + */ + @NotBlank(message = "商户密钥不能为空", groups = V2.class) + private String mchKey; + /** + * apiclient_cert.p12 证书文件的对应字符串【base64 格式】 + * + * 为什么采用 base64 格式?因为 p12 读取后是二进制,需要转换成 base64 格式才好传输和存储 + */ + @NotBlank(message = "apiclient_cert.p12 不能为空", groups = V2.class) + private String keyContent; + + // ========== V3 版本的参数 ========== + /** + * apiclient_key.pem 证书文件的对应字符串 + */ + @NotBlank(message = "apiclient_key 不能为空", groups = V3.class) + private String privateKeyContent; + /** + * apiclient_cert.pem 证书文件的对应的字符串 + */ + @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class) + private String privateCertContent; + /** + * apiV3 密钥值 + */ + @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class) + private String apiV3Key; + + /** + * 分组校验 v2版本 + */ + public interface V2 { + } + + /** + * 分组校验 v3版本 + */ + public interface V3 { + } + + @Override + public void validate(Validator validator) { + ValidationUtils.validate(validator, this, + API_VERSION_V2.equals(this.getApiVersion()) ? V2.class : V3.class); + } + + public static void main(String[] args) throws FileNotFoundException { + String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"; + /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem"; + /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"; + System.out.println(IoUtil.readUtf8(new FileInputStream(path))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java new file mode 100644 index 0000000..390c513 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 微信支付(公众号)的 PayClient 实现类 + * + * 文档:JSAPI 下单 + * + * @author 芋道源码 + */ +@Slf4j +public class WxPubPayClient extends AbstractWxPayClient { + + public WxPubPayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_PUB.getCode(), config); + } + + protected WxPubPayClient(Long channelId, String channelCode, WxPayClientConfig config) { + super(channelId, channelCode, config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.JSAPI); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO) + .setOpenid(getOpenid(reqDTO)); + // 执行请求 + WxPayMpOrderResult response = client.createOrder(request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), + reqDTO.getOutTradeNo(), response); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO) + .setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); + // 执行请求 + WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), + reqDTO.getOutTradeNo(), response); + } + + // ========== 各种工具方法 ========== + + static String getOpenid(PayOrderUnifiedReqDTO reqDTO) { + String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid"); + if (StrUtil.isEmpty(openid)) { + throw invalidParamException("支付请求的 openid 不能为空!"); + } + return openid; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxWapPayClient.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxWapPayClient.java new file mode 100644 index 0000000..d7bd996 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxWapPayClient.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +/** + * 微信支付(H5 网页)的 PayClient 实现类 + * + * 文档:H5下单API + * + * @author YYQ + */ +@Slf4j +public class WxWapPayClient extends AbstractWxPayClient { + + public WxWapPayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_WAP.getCode(), config); + } + + protected WxWapPayClient(Long channelId, String channelCode, WxPayClientConfig config) { + super(channelId, channelCode, config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.MWEB); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO); + // 执行请求 + WxPayMwebOrderResult response = client.createOrder(request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.URL.getMode(), response.getMwebUrl(), + reqDTO.getOutTradeNo(), response); + } + + @Override + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO); + // 执行请求 + String response = client.createOrderV3(TradeTypeEnum.H5, request); + + // 转换结果 + return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.URL.getMode(), response, + reqDTO.getOutTradeNo(), response); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java new file mode 100644 index 0000000..925fb45 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.framework.pay.core.enums.channel; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付渠道的编码的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayChannelEnum { + + WX_PUB("wx_pub", "微信 JSAPI 支付", WxPayClientConfig.class), // 公众号网页 + WX_LITE("wx_lite", "微信小程序支付", WxPayClientConfig.class), + WX_APP("wx_app", "微信 App 支付", WxPayClientConfig.class), + WX_NATIVE("wx_native", "微信 Native 支付", WxPayClientConfig.class), + WX_WAP("wx_wap", "微信 Wap 网站支付", WxPayClientConfig.class), // H5 网页 + WX_BAR("wx_bar", "微信付款码支付", WxPayClientConfig.class), + + ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付", AlipayPayClientConfig.class), + ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付", AlipayPayClientConfig.class), + ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), + ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), + ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), + MOCK("mock", "模拟支付", NonePayClientConfig.class), + + WALLET("wallet", "钱包支付", NonePayClientConfig.class); + + /** + * 编码 + * + * 参考 支付渠道属性值 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + /** + * 配置类 + */ + private final Class configClass; + + /** + * 微信支付 + */ + public static final String WECHAT = "WECHAT"; + + /** + * 支付宝支付 + */ + public static final String ALIPAY = "ALIPAY"; + + public static PayChannelEnum getByCode(String code) { + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); + } + + public static boolean isAlipay(String channelCode) { + return channelCode != null && channelCode.startsWith("alipay"); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java new file mode 100644 index 0000000..129c406 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.framework.pay.core.enums.order; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付 UI 展示模式 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayOrderDisplayModeEnum { + + URL("url"), // Redirect 跳转链接的方式 + IFRAME("iframe"), // IFrame 内嵌链接的方式【目前暂时用不到】 + FORM("form"), // HTML 表单提交 + QR_CODE("qr_code"), // 二维码的文字内容 + QR_CODE_URL("qr_code_url"), // 二维码的图片链接 + BAR_CODE("bar_code"), // 条形码 + APP("app"), // 应用:Android、iOS、微信小程序、微信公众号等,需要做自定义处理的 + ; + + /** + * 展示模式 + */ + private final String mode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java new file mode 100644 index 0000000..eac381c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.pay.core.enums.order; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 渠道的支付状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayOrderStatusRespEnum { + + WAITING(0, "未支付"), + SUCCESS(10, "支付成功"), + REFUND(20, "已退款"), + CLOSED(30, "支付关闭"), + ; + + private final Integer status; + private final String name; + + /** + * 判断是否支付成功 + * + * @param status 状态 + * @return 是否支付成功 + */ + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + /** + * 判断是否已退款 + * + * @param status 状态 + * @return 是否支付成功 + */ + public static boolean isRefund(Integer status) { + return Objects.equals(status, REFUND.getStatus()); + } + + /** + * 判断是否支付关闭 + * + * @param status 状态 + * @return 是否支付关闭 + */ + public static boolean isClosed(Integer status) { + return Objects.equals(status, CLOSED.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java new file mode 100644 index 0000000..8ad61a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.pay.core.enums.refund; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 渠道的退款状态枚举 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum PayRefundStatusRespEnum { + + WAITING(0, "等待退款"), + SUCCESS(10, "退款成功"), + FAILURE(20, "退款失败"); + + private final Integer status; + private final String name; + + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + public static boolean isFailure(Integer status) { + return Objects.equals(status, FAILURE.getStatus()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java new file mode 100644 index 0000000..35ea344 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.framework.pay.core.enums.transfer; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 渠道的转账状态枚举 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum PayTransferStatusRespEnum { + + WAITING(0, "等待转账"), + + /** + * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现 + * TODO @jason:可以看看其它开源项目,针对这个场景,处理策略是怎么样的?例如说,每天主动轮询?这个状态的单子? + */ + IN_PROGRESS(10, "转账进行中"), + + SUCCESS(20, "转账成功"), + /** + * 转账关闭 (失败,或者其它情况) + */ + CLOSED(30, "转账关闭"); + + private final Integer status; + private final String name; + + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + + public static boolean isClosed(Integer status) { + return Objects.equals(status, CLOSED.getStatus()); + } + + public static boolean isInProgress(Integer status) { + return Objects.equals(status, IN_PROGRESS.getStatus()); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java new file mode 100644 index 0000000..a7580f0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.framework.pay.core.enums.transfer; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 转账类型枚举 + * + * @author jason + */ +@AllArgsConstructor +@Getter +public enum PayTransferTypeEnum implements IntArrayValuable { + + ALIPAY_BALANCE(1, "支付宝余额"), + WX_BALANCE(2, "微信余额"), + BANK_CARD(3, "银行卡"), + WALLET_BALANCE(4, "钱包余额"); + + public interface WxPay { + } + + public interface Alipay { + } + + private final Integer type; + private final String name; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayTransferTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + + public static PayTransferTypeEnum typeOf(Integer type) { + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..f2a8bf1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.pay.config.YudaoPayAutoConfiguration \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java new file mode 100644 index 0000000..9842560 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPubPayClient; +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +/** + * {@link PayClientFactoryImpl} 的集成测试 + * + * @author 芋道源码 + */ +@Disabled +public class PayClientFactoryImplIntegrationTest { + + private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do"; + + private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); + + /** + * {@link WxPubPayClient} 的 V2 版本 + */ + @Test + public void testCreatePayClient_WX_PUB_V2() { + // 创建配置 + WxPayClientConfig config = new WxPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WxPayClientConfig.API_VERSION_V2); + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); + // 创建客户端 + Long channelId = RandomUtil.randomLong(); + payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_PUB.getCode(), config); + PayClient client = payClientFactory.getPayClient(channelId); + // 发起支付 + PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); +// CommonResult result = client.unifiedOrder(reqDTO); +// System.out.println(result); + } + + /** + * {@link WxPubPayClient} 的 V3 版本 + */ + @Test + public void testCreatePayClient_WX_PUB_V3() throws FileNotFoundException { + // 创建配置 + WxPayClientConfig config = new WxPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WxPayClientConfig.API_VERSION_V3); + config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); + config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); + config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); + // 创建客户端 + Long channelId = RandomUtil.randomLong(); + payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_PUB.getCode(), config); + PayClient client = payClientFactory.getPayClient(channelId); + // 发起支付 + PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); +// CommonResult result = client.unifiedOrder(reqDTO); +// System.out.println(result); + } + + /** + * {@link AlipayQrPayClient} + */ + @Test + @SuppressWarnings("unchecked") + public void testCreatePayClient_ALIPAY_QR() { + // 创建配置 + AlipayPayClientConfig config = new AlipayPayClientConfig(); + config.setAppId("2021000118634035"); + config.setServerUrl(SERVER_URL_SANDBOX); + config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); + config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); + config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); + // 创建客户端 + Long channelId = RandomUtil.randomLong(); + payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config); + PayClient client = payClientFactory.getPayClient(channelId); + // 发起支付 + PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); + reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址 +// CommonResult result = (CommonResult) client.unifiedOrder(reqDTO); +// System.out.println(JsonUtils.toJsonString(result)); +// System.out.println(result.getData().getQrCode()); + } + + /** + * {@link AlipayWapPayClient} + */ + @Test + public void testCreatePayClient_ALIPAY_WAP() { + // 创建配置 + AlipayPayClientConfig config = new AlipayPayClientConfig(); + config.setAppId("2021000118634035"); + config.setServerUrl(SERVER_URL_SANDBOX); + config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); + config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); + config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); + // 创建客户端 + Long channelId = RandomUtil.randomLong(); + payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config); + PayClient client = payClientFactory.getPayClient(channelId); + // 发起支付 + PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); +// CommonResult result = client.unifiedOrder(reqDTO); +// System.out.println(JsonUtils.toJsonString(result)); + } + + private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { + PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); + reqDTO.setPrice(123); + reqDTO.setSubject("IPhone 13"); + reqDTO.setBody("biubiubiu"); + reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis())); + reqDTO.setUserIp("127.0.0.1"); + reqDTO.setNotifyUrl("http://127.0.0.1:8080"); + return reqDTO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java new file mode 100644 index 0000000..2d22007 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java @@ -0,0 +1,221 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import com.alipay.api.AlipayApiException; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.DefaultSigner; +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeRefundResponse; +import lombok.Setter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; + +import javax.validation.ConstraintViolationException; +import java.util.Date; + +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * 支付宝 Client 的测试基类 + * + * @author jason + */ +public abstract class AbstractAlipayClientTest extends BaseMockitoUnitTest { + + protected AlipayPayClientConfig config = randomPojo(AlipayPayClientConfig.class, o -> { + o.setServerUrl(randomURL()); + o.setPrivateKey(randomString()); + o.setMode(MODE_PUBLIC_KEY); + o.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); + o.setAppCertContent(""); + o.setAlipayPublicCertContent(""); + o.setRootCertContent(""); + }); + + @Mock + protected DefaultAlipayClient defaultAlipayClient; + + @Setter + private AbstractAlipayPayClient client; + + /** + * 子类需要实现该方法. 设置 client 的具体实现 + */ + @BeforeEach + public abstract void setUp(); + + @Test + @DisplayName("支付宝 Client 初始化") + public void testDoInit() { + // 调用 + client.doInit(); + // 断言 + DefaultAlipayClient realClient = client.getClient(); + assertNotSame(defaultAlipayClient, realClient); + assertInstanceOf(DefaultSigner.class, realClient.getSigner()); + assertEquals(config.getPrivateKey(), ((DefaultSigner) realClient.getSigner()).getPrivateKey()); + } + + @Test + @DisplayName("支付宝 Client 统一退款:成功") + public void testUnifiedRefund_success() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + Date refundTime = randomDate(); + String outRefundNo = randomString(); + String outTradeNo = randomString(); + Integer refundAmount = randomInteger(); + AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> { + o.setSubCode(""); + o.setGmtRefundPay(refundTime); + }); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel()); + AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel(); + assertEquals(outRefundNo, bizModel.getOutRequestNo()); + assertEquals(outTradeNo, bizModel.getOutTradeNo()); + assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount()); + return true; + }))).thenReturn(response); + // 准备请求参数 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { + o.setOutRefundNo(outRefundNo); + o.setOutTradeNo(outTradeNo); + o.setNotifyUrl(notifyUrl); + o.setRefundPrice(refundAmount); + }); + + // 调用 + PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO); + // 断言 + assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus()); + assertEquals(outRefundNo, resp.getOutRefundNo()); + assertNull(resp.getChannelRefundNo()); + assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝 Client 统一退款:渠道返回失败") + public void test_unified_refund_channel_failed() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + String subCode = randomString(); + String subMsg = randomString(); + AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> { + o.setSubCode(subCode); + o.setSubMsg(subMsg); + }); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel()); + return true; + }))).thenReturn(response); + // 准备请求参数 + String outRefundNo = randomString(); + String outTradeNo = randomString(); + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { + o.setOutRefundNo(outRefundNo); + o.setOutTradeNo(outTradeNo); + o.setNotifyUrl(notifyUrl); + }); + + // 调用 + PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO); + // 断言 + assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus()); + assertEquals(outRefundNo, resp.getOutRefundNo()); + assertNull(resp.getChannelRefundNo()); + assertNull(resp.getSuccessTime()); + assertSame(response, resp.getRawData()); + assertEquals(subCode, resp.getChannelErrorCode()); + assertEquals(subMsg, resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝 Client 统一退款:参数校验不通过") + public void testUnifiedRefund_paramInvalidate() { + // 准备请求参数 + String notifyUrl = randomURL(); + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { + o.setOutTradeNo(""); + o.setNotifyUrl(notifyUrl); + }); + + // 调用,并断言 + assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO)); + } + + @Test + @DisplayName("支付宝 Client 统一退款:抛出业务异常") + public void testUnifiedRefund_throwServiceException() throws AlipayApiException { + // mock 方法 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) + .thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR)); + // 准备请求参数 + String notifyUrl = randomURL(); + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl)); + + // 调用,并断言 + assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO)); + } + + @Test + @DisplayName("支付宝 Client 统一退款:抛出系统异常") + public void testUnifiedRefund_throwPayException() throws AlipayApiException { + // mock 方法 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) + .thenThrow(new RuntimeException("系统异常")); + // 准备请求参数 + String notifyUrl = randomURL(); + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl)); + + // 调用,并断言 + assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO)); + } + + @Test + @DisplayName("支付宝 Client 统一下单:参数校验不通过") + public void testUnifiedOrder_paramInvalidate() { + // 准备请求参数 + String outTradeNo = randomString(); + String notifyUrl = randomURL(); + PayOrderUnifiedReqDTO reqDTO = randomPojo(PayOrderUnifiedReqDTO.class, o -> { + o.setOutTradeNo(outTradeNo); + o.setNotifyUrl(notifyUrl); + }); + + // 调用,并断言 + assertThrows(ConstraintViolationException.class, () -> client.unifiedOrder(reqDTO)); + } + + protected PayOrderUnifiedReqDTO buildOrderUnifiedReqDTO(String notifyUrl, String outTradeNo, Integer price) { + return randomPojo(PayOrderUnifiedReqDTO.class, o -> { + o.setOutTradeNo(outTradeNo); + o.setNotifyUrl(notifyUrl); + o.setPrice(price); + o.setSubject(RandomUtil.randomString(32)); + o.setBody(RandomUtil.randomString(32)); + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java new file mode 100644 index 0000000..47f1008 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java @@ -0,0 +1,170 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePayModel; +import com.alipay.api.request.AlipayTradePayRequest; +import com.alipay.api.response.AlipayTradePayResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * {@link AlipayBarPayClient} 单元测试 + * + * @author jason + */ +public class AlipayBarPayClientTest extends AbstractAlipayClientTest { + + @InjectMocks + private AlipayBarPayClient client = new AlipayBarPayClient(randomLongId(), config); + + @Override + @BeforeEach + public void setUp() { + setClient(client); + } + + @Test + @DisplayName("支付宝条码支付:非免密码支付下单成功") + public void testUnifiedOrder_success() throws AlipayApiException { + // mock 方法 + String outTradeNo = randomString(); + String notifyUrl = randomURL(); + Integer price = randomInteger(); + String authCode = randomString(); + AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> o.setSubCode("")); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertInstanceOf(AlipayTradePayModel.class, request.getBizModel()); + assertEquals(notifyUrl, request.getNotifyUrl()); + AlipayTradePayModel model = (AlipayTradePayModel) request.getBizModel(); + assertEquals(outTradeNo, model.getOutTradeNo()); + assertEquals(String.valueOf(price / 100.0), model.getTotalAmount()); + assertEquals(authCode, model.getAuthCode()); + return true; + }))).thenReturn(response); + // 准备请求参数 + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + Map extraParam = new HashMap<>(); + extraParam.put("auth_code", authCode); + reqDTO.setChannelExtras(extraParam); + + // 调用方法 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(WAITING.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.BAR_CODE.getMode(), resp.getDisplayMode()); + assertEquals("", resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝条码支付:免密码支付下单成功") + public void testUnifiedOrder_code10000Success() throws AlipayApiException { + // mock 方法 + String outTradeNo = randomString(); + String channelNo = randomString(); + String channelUserId = randomString(); + Date payTime = randomDate(); + AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> { + o.setSubCode(""); + o.setCode("10000"); + o.setOutTradeNo(outTradeNo); + o.setTradeNo(channelNo); + o.setBuyerUserId(channelUserId); + o.setGmtPayment(payTime); + }); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) + .thenReturn(response); + // 准备请求参数 + String authCode = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); + Map extraParam = new HashMap<>(); + extraParam.put("auth_code", authCode); + reqDTO.setChannelExtras(extraParam); + + // 下单请求 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(PayOrderStatusRespEnum.SUCCESS.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertEquals(channelNo, resp.getChannelOrderNo()); + assertEquals(channelUserId, resp.getChannelUserId()); + assertEquals(LocalDateTimeUtil.of(payTime), resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.BAR_CODE.getMode(), resp.getDisplayMode()); + assertEquals("", resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝条码支付:没有传条码") + public void testUnifiedOrder_emptyAuthCode() { + // 准备参数 + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger()); + + // 调用,并断言 + assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO)); + } + + @Test + @DisplayName("支付宝条码支付:渠道返回失败") + public void test_unified_order_channel_failed() throws AlipayApiException { + // mock 方法 + String subCode = randomString(); + String subMsg = randomString(); + AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> { + o.setSubCode(subCode); + o.setSubMsg(subMsg); + }); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) + .thenReturn(response); + // 准备请求参数 + String authCode = randomString(); + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); + Map extraParam = new HashMap<>(); + extraParam.put("auth_code", authCode); + reqDTO.setChannelExtras(extraParam); + + // 调用方法 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(CLOSED.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertNull(resp.getDisplayMode()); + assertNull(resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertEquals(subCode, resp.getChannelErrorCode()); + assertEquals(subMsg, resp.getChannelErrorMsg()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java new file mode 100644 index 0000000..d78caf2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.http.Method; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.alipay.api.response.AlipayTradePagePayResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; + +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link AlipayPcPayClient} 单元测试 + * + * @author jason + */ +public class AlipayPcPayClientTest extends AbstractAlipayClientTest { + + @InjectMocks + private AlipayPcPayClient client = new AlipayPcPayClient(randomLongId(), config); + + @Override + @BeforeEach + public void setUp() { + setClient(client); + } + + @Test + @DisplayName("支付宝 PC 网站支付:URL Display Mode 下单成功") + public void testUnifiedOrder_urlSuccess() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> o.setSubCode("")); + when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), + eq(Method.GET.name()))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + Integer price = randomInteger(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + reqDTO.setDisplayMode(null); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(WAITING.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.URL.getMode(), resp.getDisplayMode()); + assertEquals(response.getBody(), resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝 PC 网站支付:Form Display Mode 下单成功") + public void testUnifiedOrder_formSuccess() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> o.setSubCode("")); + when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), + eq(Method.POST.name()))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + Integer price = randomInteger(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + reqDTO.setDisplayMode(PayOrderDisplayModeEnum.FORM.getMode()); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(WAITING.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.FORM.getMode(), resp.getDisplayMode()); + assertEquals(response.getBody(), resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝 PC 网站支付:渠道返回失败") + public void testUnifiedOrder_channelFailed() throws AlipayApiException { + // mock 方法 + String subCode = randomString(); + String subMsg = randomString(); + AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> { + o.setSubCode(subCode); + o.setSubMsg(subMsg); + }); + when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), + eq(Method.GET.name()))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); + reqDTO.setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(CLOSED.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertNull(resp.getDisplayMode()); + assertNull(resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertEquals(subCode, resp.getChannelErrorCode()); + assertEquals(subMsg, resp.getChannelErrorMsg()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java new file mode 100644 index 0000000..c7e1eb3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.request.AlipayTradePrecreateRequest; +import com.alipay.api.response.AlipayTradePrecreateResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; + +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * {@link AlipayQrPayClient} 单元测试 + * + * @author jason + */ +public class AlipayQrPayClientTest extends AbstractAlipayClientTest { + + @InjectMocks + private AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config); + + @BeforeEach + public void setUp() { + setClient(client); + } + + @Test + @DisplayName("支付宝扫描支付:下单成功") + public void testUnifiedOrder_success() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + String qrCode = randomString(); + Integer price = randomInteger(); + AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> { + o.setQrCode(qrCode); + o.setSubCode(""); + }); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertEquals(notifyUrl, request.getNotifyUrl()); + return true; + }))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(WAITING.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.QR_CODE.getMode(), resp.getDisplayMode()); + assertEquals(response.getQrCode(), resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝扫描支付:渠道返回失败") + public void testUnifiedOrder_channelFailed() throws AlipayApiException { + // mock 方法 + String notifyUrl = randomURL(); + String subCode = randomString(); + String subMsg = randomString(); + Integer price = randomInteger(); + AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> { + o.setSubCode(subCode); + o.setSubMsg(subMsg); + }); + // mock + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertEquals(notifyUrl, request.getNotifyUrl()); + return true; + }))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(CLOSED.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertNull(resp.getDisplayMode()); + assertNull(resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertEquals(subCode, resp.getChannelErrorCode()); + assertEquals(subMsg, resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝扫描支付, 抛出系统异常") + public void testUnifiedOrder_throwPayException() throws AlipayApiException { + // mock 方法 + String outTradeNo = randomString(); + String notifyUrl = randomURL(); + Integer price = randomInteger(); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertEquals(notifyUrl, request.getNotifyUrl()); + return true; + }))).thenThrow(new RuntimeException("系统异常")); + // 准备请求参数 + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo,price); + + // 调用,并断言 + assertThrows(PayException.class, () -> client.unifiedOrder(reqDTO)); + } + + @Test + @DisplayName("支付宝 Client 统一下单:抛出业务异常") + public void testUnifiedOrder_throwServiceException() throws AlipayApiException { + // mock 方法 + String outTradeNo = randomString(); + String notifyUrl = randomURL(); + Integer price = randomInteger(); + when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { + assertEquals(notifyUrl, request.getNotifyUrl()); + return true; + }))).thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR)); + // 准备请求参数 + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + + // 调用,并断言 + assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java new file mode 100644 index 0000000..af0c717 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.http.Method; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeWapPayModel; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.alipay.api.response.AlipayTradeWapPayResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; + +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; +import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link AlipayWapPayClient} 单元测试 + * + * @author jason + */ +public class AlipayWapPayClientTest extends AbstractAlipayClientTest { + + /** + * 支付宝 H5 支付 Client + */ + @InjectMocks + private AlipayWapPayClient client = new AlipayWapPayClient(randomLongId(), config); + + @BeforeEach + public void setUp() { + setClient(client); + } + + @Test + @DisplayName("支付宝 H5 支付:下单成功") + public void testUnifiedOrder_success() throws AlipayApiException { + // mock 方法 + String h5Body = randomString(); + Integer price = randomInteger(); + AlipayTradeWapPayResponse response = randomPojo(AlipayTradeWapPayResponse.class, o -> { + o.setSubCode(""); + o.setBody(h5Body); + }); + String notifyUrl = randomURL(); + when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> { + assertInstanceOf(AlipayTradeWapPayModel.class, request.getBizModel()); + AlipayTradeWapPayModel bizModel = (AlipayTradeWapPayModel) request.getBizModel(); + assertEquals(String.valueOf(price / 100.0), bizModel.getTotalAmount()); + assertEquals(notifyUrl, request.getNotifyUrl()); + return true; + }), eq(Method.GET.name()))).thenReturn(response); + // 准备请求参数 + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(WAITING.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertEquals(PayOrderDisplayModeEnum.URL.getMode(), resp.getDisplayMode()); + assertEquals(response.getBody(), resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertNull(resp.getChannelErrorCode()); + assertNull(resp.getChannelErrorMsg()); + } + + @Test + @DisplayName("支付宝 H5 支付:渠道返回失败") + public void test_unified_order_channel_failed() throws AlipayApiException { + // mock 方法 + String subCode = randomString(); + String subMsg = randomString(); + AlipayTradeWapPayResponse response = randomPojo(AlipayTradeWapPayResponse.class, o -> { + o.setSubCode(subCode); + o.setSubMsg(subMsg); + }); + when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), + eq(Method.GET.name()))).thenReturn(response); + String outTradeNo = randomString(); + PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); + + // 调用 + PayOrderRespDTO resp = client.unifiedOrder(reqDTO); + // 断言 + assertEquals(CLOSED.getStatus(), resp.getStatus()); + assertEquals(outTradeNo, resp.getOutTradeNo()); + assertNull(resp.getChannelOrderNo()); + assertNull(resp.getChannelUserId()); + assertNull(resp.getSuccessTime()); + assertNull(resp.getDisplayMode()); + assertNull(resp.getDisplayContent()); + assertSame(response, resp.getRawData()); + assertEquals(subCode, resp.getChannelErrorCode()); + assertEquals(subMsg, resp.getChannelErrorMsg()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java new file mode 100644 index 0000000..9af11ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java @@ -0,0 +1,123 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.AbstractWxPayClient.formatDateV2; + +/** + * {@link WxBarPayClient} 的集成测试,用于快速调试微信条码支付 + * + * @author 芋道源码 + */ +@Disabled +public class WxBarPayClientIntegrationTest { + + @Test + public void testPayV2() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV2(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行发起支付 + WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() + .outTradeNo(String.valueOf(System.currentTimeMillis())) + .body("测试支付-body") + .detail("测试支付-detail") + .totalFee(1) // 单位分 + .timeExpire(formatDateV2(LocalDateTimeUtils.addTime(Duration.ofMinutes(2)))) + .spbillCreateIp("127.0.0.1") + .authCode("134298744426278497") + .build(); + System.out.println("========= request =========="); + System.out.println(JsonUtils.toJsonPrettyString(request)); + WxPayMicropayResult response = client.micropay(request); + System.out.println("========= response =========="); + System.out.println(JsonUtils.toJsonPrettyString(response)); + } + + @Test + public void testParseRefundNotifyV2() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV2(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行解析 + String xml = "SUCCESS"; + WxPayRefundNotifyResult response = client.parseRefundNotifyResult(xml); + System.out.println(response.getReqInfo()); + } + + @Test + public void testRefundV2() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV2(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行发起退款 + WxPayRefundRequest request = new WxPayRefundRequest() + .setOutTradeNo("1689545667276") + .setOutRefundNo(String.valueOf(System.currentTimeMillis())) + .setRefundFee(1) + .setRefundDesc("就是想退了") + .setTotalFee(1); + System.out.println("========= request =========="); + System.out.println(JsonUtils.toJsonPrettyString(request)); + WxPayRefundResult response = client.refund(request); + System.out.println("========= response =========="); + System.out.println(JsonUtils.toJsonPrettyString(response)); + } + + @Test + public void testRefundV3() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV2(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行发起退款 + WxPayRefundV3Request request = new WxPayRefundV3Request() + .setOutTradeNo("1689506325635") + .setOutRefundNo(String.valueOf(System.currentTimeMillis())) + .setAmount(new WxPayRefundV3Request.Amount().setTotal(1).setRefund(1).setCurrency("CNY")) + .setReason("就是想退了"); + System.out.println("========= request =========="); + System.out.println(JsonUtils.toJsonPrettyString(request)); + WxPayRefundV3Result response = client.refundV3(request); + System.out.println("========= response =========="); + System.out.println(JsonUtils.toJsonPrettyString(response)); + } + + private WxPayConfig buildWxPayConfigV2() { + WxPayConfig config = new WxPayConfig(); + config.setAppId("wx62056c0d5e8db250"); + config.setMchId("1545083881"); + config.setMchKey("dS1ngeN63JLr3NRbvPH9AJy3MyUxZdim"); +// config.setSignType(WxPayConstants.SignType.MD5); + config.setKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"); + return config; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java new file mode 100644 index 0000000..5e73601 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.AbstractWxPayClient.formatDateV3; + +/** + * {@link WxNativePayClient} 的集成测试,用于快速调试微信扫码支付 + * + * @author 芋道源码 + */ +@Disabled +public class WxNativePayClientIntegrationTest { + + @Test + public void testPayV3() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV3(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行发起支付 + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request() + .setOutTradeNo(String.valueOf(System.currentTimeMillis())) + .setDescription("测试支付-body") + .setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(1)) // 单位分 + .setTimeExpire(formatDateV3(LocalDateTimeUtils.addTime(Duration.ofMinutes(2)))) + .setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp("127.0.0.1")) + .setNotifyUrl("http://127.0.0.1:48080"); + System.out.println("========= request =========="); + System.out.println(JsonUtils.toJsonPrettyString(request)); + String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); + System.out.println("========= response =========="); + System.out.println(JsonUtils.toJsonPrettyString(response)); + } + + @Test + public void testRefundV3() throws WxPayException { + // 创建 config 配置 + WxPayConfig config = buildWxPayConfigV3(); + // 创建 WxPayService 客户端 + WxPayService client = new WxPayServiceImpl(); + client.setConfig(config); + + // 执行发起退款 + WxPayRefundV3Request request = new WxPayRefundV3Request() + .setOutTradeNo("1689545729695") + .setOutRefundNo(String.valueOf(System.currentTimeMillis())) + .setAmount(new WxPayRefundV3Request.Amount().setTotal(1).setRefund(1).setCurrency("CNY")) + .setReason("就是想退了"); + System.out.println("========= request =========="); + System.out.println(JsonUtils.toJsonPrettyString(request)); + WxPayRefundV3Result response = client.refundV3(request); + System.out.println("========= response =========="); + System.out.println(JsonUtils.toJsonPrettyString(response)); + } + + private WxPayConfig buildWxPayConfigV3() { + WxPayConfig config = new WxPayConfig(); + config.setAppId("wx62056c0d5e8db250"); + config.setMchId("1545083881"); + config.setApiV3Key("459arNsYHl1mgkiO6H9ZH5KkhFXSxaA4"); +// config.setCertSerialNo(serialNo); + config.setPrivateCertPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"); + config.setPrivateKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"); + return config; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/pom.xml b/ruoyi-vue-pro-master/yudao-module-report/pom.xml new file mode 100644 index 0000000..fadb074 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/pom.xml @@ -0,0 +1,23 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + + yudao-module-report-api + yudao-module-report-biz + + yudao-module-report + pom + + ${project.artifactId} + + report 模块,主要实现数据可视化报表等功能。 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/pom.xml new file mode 100644 index 0000000..3effa43 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/pom.xml @@ -0,0 +1,26 @@ + + + + cn.iocoder.boot + yudao-module-report + ${revision} + + 4.0.0 + + yudao-module-report-api + jar + + ${project.artifactId} + + report 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/api/package-info.java new file mode 100644 index 0000000..827bef3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/api/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,避免 api 目录无文件时,git 无法提交 + */ +package cn.iocoder.yudao.module.report.api; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..2562976 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-api/src/main/java/cn/iocoder/yudao/module/report/enums/ErrorCodeConstants.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.report.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * Report 错误码枚举类 + * + * report 系统,使用 1-003-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== GoView 模块 1-003-000-000 ========== + ErrorCode GO_VIEW_PROJECT_NOT_EXISTS = new ErrorCode(1_003_000_000, "GoView 项目不存在"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/pom.xml new file mode 100644 index 0000000..b2c4d18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/pom.xml @@ -0,0 +1,79 @@ + + + + cn.iocoder.boot + yudao-module-report + ${revision} + + 4.0.0 + + yudao-module-report-biz + jar + + ${project.artifactId} + + report 模块,主要实现数据可视化报表等功能: + 1. 基于「积木报表」实现,打印设计、报表设计、图形设计、大屏设计等。 + + + + cn.iocoder.boot + yudao-module-report-api + ${revision} + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + org.jeecgframework.jimureport + jimureport-spring-boot-starter + + + + xerces + xercesImpl + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/ajreport/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/ajreport/package-info.java new file mode 100644 index 0000000..e32b8b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/ajreport/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.report.controller.admin.ajreport; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewDataController.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewDataController.java new file mode 100644 index 0000000..6b28d1f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewDataController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.data.GoViewDataGetBySqlReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.data.GoViewDataRespVO; +import cn.iocoder.yudao.module.report.service.goview.GoViewDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.util.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - GoView 数据", description = "提供 SQL、HTTP 等数据查询的能力") +@RestController +@RequestMapping("/report/go-view/data") +@Validated +public class GoViewDataController { + + @Resource + private GoViewDataService goViewDataService; + + @RequestMapping("/get-by-sql") + @Operation(summary = "使用 SQL 查询数据") + @PreAuthorize("@ss.hasPermission('report:go-view-data:get-by-sql')") + public CommonResult getDataBySQL(@Valid @RequestBody GoViewDataGetBySqlReqVO reqVO) { + return success(goViewDataService.getDataBySQL(reqVO.getSql())); + } + + @RequestMapping("/get-by-http") + @Operation(summary = "使用 HTTP 查询数据", description = "这个只是示例接口,实际应该每个查询,都要写一个接口") + @PreAuthorize("@ss.hasPermission('report:go-view-data:get-by-http')") + public CommonResult getDataByHttp( + @RequestParam(required = false) Map params, + @RequestBody(required = false) String body) { // params、body 按照需要去接收,这里仅仅是示例 + GoViewDataRespVO respVO = new GoViewDataRespVO(); + // 1. 数据维度 + respVO.setDimensions(Arrays.asList("日期", "PV", "UV")); // PV 是每天访问次数;UV 是每天访问人数 + // 2. 明细数据列表 + // 目前通过随机的方式生成。一般来说,这里你可以写逻辑来实现数据的返回 + respVO.setSource(new LinkedList<>()); + for (int i = 1; i <= 12; i++) { + String date = "2021-" + (i < 10 ? "0" + i : i); + Integer pv = RandomUtil.randomInt(1000, 10000); + Integer uv = RandomUtil.randomInt(100, 1000); + respVO.getSource().add(MapUtil.builder().put("日期", date) + .put("PV", pv).put("UV", uv).build()); + } + return success(respVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewProjectController.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewProjectController.java new file mode 100644 index 0000000..8cc5f7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/GoViewProjectController.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectCreateReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectRespVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectUpdateReqVO; +import cn.iocoder.yudao.module.report.convert.goview.GoViewProjectConvert; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; +import cn.iocoder.yudao.module.report.service.goview.GoViewProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - GoView 项目") +@RestController +@RequestMapping("/report/go-view/project") +@Validated +public class GoViewProjectController { + + @Resource + private GoViewProjectService goViewProjectService; + + @PostMapping("/create") + @Operation(summary = "创建项目") + @PreAuthorize("@ss.hasPermission('report:go-view-project:create')") + public CommonResult createProject(@Valid @RequestBody GoViewProjectCreateReqVO createReqVO) { + return success(goViewProjectService.createProject(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新项目") + @PreAuthorize("@ss.hasPermission('report:go-view-project:update')") + public CommonResult updateProject(@Valid @RequestBody GoViewProjectUpdateReqVO updateReqVO) { + goViewProjectService.updateProject(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除 GoView 项目") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('report:go-view-project:delete')") + public CommonResult deleteProject(@RequestParam("id") Long id) { + goViewProjectService.deleteProject(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得项目") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('report:go-view-project:query')") + public CommonResult getProject(@RequestParam("id") Long id) { + GoViewProjectDO project = goViewProjectService.getProject(id); + return success(GoViewProjectConvert.INSTANCE.convert(project)); + } + + @GetMapping("/my-page") + @Operation(summary = "获得我的项目分页") + @PreAuthorize("@ss.hasPermission('report:go-view-project:query')") + public CommonResult> getMyProjectPage(@Valid PageParam pageVO) { + PageResult pageResult = goViewProjectService.getMyProjectPage( + pageVO, getLoginUserId()); + return success(GoViewProjectConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataGetBySqlReqVO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataGetBySqlReqVO.java new file mode 100644 index 0000000..785a4c5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataGetBySqlReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview.vo.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - GoView 使用 SQL 查询数据 Request VO") +@Data +public class GoViewDataGetBySqlReqVO { + + @Schema(description = "SQL 语句", requiredMode = Schema.RequiredMode.REQUIRED, example = "SELECT * FROM user") + @NotEmpty(message = "SQL 语句不能为空") + private String sql; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataRespVO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataRespVO.java new file mode 100644 index 0000000..38251dd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/data/GoViewDataRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview.vo.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - GoView 数据 Response VO") +@Data +public class GoViewDataRespVO { + + @Schema(description = "数据维度", requiredMode = Schema.RequiredMode.REQUIRED, example = "['product', 'data1', 'data2']") + private List dimensions; + + @Schema(description = "数据明细列表", requiredMode = Schema.RequiredMode.REQUIRED) + private List> source; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectCreateReqVO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectCreateReqVO.java new file mode 100644 index 0000000..dce5d92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectCreateReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview.vo.project; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - GoView 项目创建 Request VO") +@Data +public class GoViewProjectCreateReqVO { + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "项目名称不能为空") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectRespVO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectRespVO.java new file mode 100644 index 0000000..3197d99 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview.vo.project; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - GoView 项目 Response VO") +@Data +public class GoViewProjectRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18993") + private Long id; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "发布状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "报表内容") // JSON 格式 + private String content; + + @Schema(description = "预览图片 URL", example = "https://www.iocoder.cn") + private String picUrl; + + @Schema(description = "项目备注", example = "你猜") + private String remark; + + @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String creator; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectUpdateReqVO.java new file mode 100644 index 0000000..f5c2004 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/admin/goview/vo/project/GoViewProjectUpdateReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.report.controller.admin.goview.vo.project; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - GoView 项目更新 Request VO") +@Data +public class GoViewProjectUpdateReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18993") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "发布状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = CommonStatusEnum.class, message = "发布状态必须是 {value}") + private Integer status; + + @Schema(description = "报表内容") // JSON 格式 + private String content; + + @Schema(description = "预览图片 URL", example = "https://www.iocoder.cn") + private String picUrl; + + @Schema(description = "项目备注", example = "你猜") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/package-info.java new file mode 100644 index 0000000..ccbf9bb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.report.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/ajreport/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/ajreport/package-info.java new file mode 100644 index 0000000..7286079 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/ajreport/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 占位,后续删除 + */ +package cn.iocoder.yudao.module.report.convert.ajreport; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/goview/GoViewProjectConvert.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/goview/GoViewProjectConvert.java new file mode 100644 index 0000000..9c993a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/convert/goview/GoViewProjectConvert.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.report.convert.goview; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectCreateReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectRespVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectUpdateReqVO; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface GoViewProjectConvert { + + GoViewProjectConvert INSTANCE = Mappers.getMapper(GoViewProjectConvert.class); + + GoViewProjectDO convert(GoViewProjectCreateReqVO bean); + + GoViewProjectDO convert(GoViewProjectUpdateReqVO bean); + + GoViewProjectRespVO convert(GoViewProjectDO bean); + + PageResult convertPage(PageResult page); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/ajreport/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/ajreport/package-info.java new file mode 100644 index 0000000..922ec6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/ajreport/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:占位,待删除 + */ +package cn.iocoder.yudao.module.report.dal.dataobject.ajreport; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/goview/GoViewProjectDO.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/goview/GoViewProjectDO.java new file mode 100644 index 0000000..38730d2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/dataobject/goview/GoViewProjectDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.report.dal.dataobject.goview; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * GoView 项目表 + * + * 每个大屏图标,对应一个项目 + * + * @author 芋道源码 + */ +@TableName(value = "report_go_view_project", autoResultMap = true) // 由于 SQL Server 的 system_user 是关键字,所以使用 system_users +@KeySequence("report_go_view_project_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GoViewProjectDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + @TableId + private Long id; + /** + * 项目名称 + */ + private String name; + /** + * 预览图片 URL + */ + private String picUrl; + /** + * 报表内容 + * + * JSON 配置,使用字符串存储 + */ + private String content; + /** + * 发布状态 + * + * 0 - 已发布 + * 1 - 未发布 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 项目备注 + */ + private String remark; +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/ajreport/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/ajreport/package-info.java new file mode 100644 index 0000000..0fb8617 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/ajreport/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:占位,待删除 + */ +package cn.iocoder.yudao.module.report.dal.mysql.ajreport; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/goview/GoViewProjectMapper.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/goview/GoViewProjectMapper.java new file mode 100644 index 0000000..af1ca63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/dal/mysql/goview/GoViewProjectMapper.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.report.dal.mysql.goview; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface GoViewProjectMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long userId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(GoViewProjectDO::getCreator, userId) + .orderByDesc(GoViewProjectDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/config/JmReportConfiguration.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/config/JmReportConfiguration.java new file mode 100644 index 0000000..1946d05 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/config/JmReportConfiguration.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.report.framework.jmreport.config; + +import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.report.framework.jmreport.core.service.JmReportTokenServiceImpl; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * 积木报表的配置类 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +@ComponentScan(basePackages = "org.jeecg.modules.jmreport") // 扫描积木报表的包 +public class JmReportConfiguration { + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public JmReportTokenServiceI jmReportTokenService(OAuth2TokenApi oAuth2TokenApi, + PermissionApi permissionApi, + SecurityProperties securityProperties) { + return new JmReportTokenServiceImpl(oAuth2TokenApi, permissionApi, securityProperties); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java new file mode 100644 index 0000000..8bd4eaa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java @@ -0,0 +1,153 @@ +package cn.iocoder.yudao.module.report.framework.jmreport.core.service; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import lombok.RequiredArgsConstructor; +import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; +import org.springframework.http.HttpHeaders; + +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; + +/** + * {@link JmReportTokenServiceI} 实现类,提供积木报表的 Token 校验、用户信息的查询等功能 + * + * @author 随心 + */ +@RequiredArgsConstructor +public class JmReportTokenServiceImpl implements JmReportTokenServiceI { + + /** + * 积木 token head 头 + */ + private static final String JM_TOKEN_HEADER = "X-Access-Token"; + /** + * auth 相关格式 + */ + private static final String AUTHORIZATION_FORMAT = SecurityFrameworkUtils.AUTHORIZATION_BEARER + " %s"; + + private final OAuth2TokenApi oauth2TokenApi; + private final PermissionApi permissionApi; + + private final SecurityProperties securityProperties; + + /** + * 自定义 API 数据集appian自定义 Header,解决 Token 传递。 + * 参考 api数据集token机制详解 文档 + * + * @return 新 head + */ + @Override + public HttpHeaders customApiHeader() { + // 读取积木标标系统的 token + HttpServletRequest request = ServletUtils.getRequest(); + String token = request.getHeader(JM_TOKEN_HEADER); + + // 设置到 yudao 系统的 token + HttpHeaders headers = new HttpHeaders(); + headers.add(securityProperties.getTokenHeader(), String.format(AUTHORIZATION_FORMAT, token)); + return headers; + } + + /** + * 校验 Token 是否有效,即验证通过 + * + * @param token JmReport 前端传递的 token + * @return 是否认证通过 + */ + @Override + public Boolean verifyToken(String token) { + Long userId = SecurityFrameworkUtils.getLoginUserId(); + if (!Objects.isNull(userId)) { + return true; + } + return buildLoginUserByToken(token) != null; + } + + /** + * 获得用户编号 + *

+ * 虽然方法名获得的是 username,实际对应到项目中是用户编号 + * + * @param token JmReport 前端传递的 token + * @return 用户编号 + */ + @Override + public String getUsername(String token) { + Long userId = SecurityFrameworkUtils.getLoginUserId(); + if (ObjectUtil.isNotNull(userId)) { + return String.valueOf(userId); + } + LoginUser user = buildLoginUserByToken(token); + return user == null ? null : String.valueOf(user.getId()); + } + + /** + * 基于 token 构建登录用户 + * + * @param token token + * @return 返回 token 对应的用户信息 + */ + private LoginUser buildLoginUserByToken(String token) { + if (StrUtil.isEmpty(token)) { + return null; + } + // TODO 如下的实现不算特别优雅,主要咱是不想搞的太复杂,所以参考对应的 Filter 先实现了 + + // ① 参考 TokenAuthenticationFilter 的认证逻辑(Security 的上下文清理,交给 Spring Security 完成) + // 目的:实现基于 JmReport 前端传递的 token,实现认证 + TenantContextHolder.setIgnore(true); // 忽略租户,保证可查询到 token 信息 + LoginUser user = null; + try { + OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token); + if (accessToken == null) { + return null; + } + user = new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) + .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()); + } catch (ServiceException ignored) { + // do nothing:如果报错,说明认证失败,则返回 false 即可 + } + if (user == null) { + return null; + } + SecurityFrameworkUtils.setLoginUser(user, WebFrameworkUtils.getRequest()); + + // ② 参考 TenantContextWebFilter 实现(Tenant 的上下文清理,交给 TenantContextWebFilter 完成) + // 目的:基于 LoginUser 获得到的租户编号,设置到 Tenant 上下文,避免查询数据库时的报错 + TenantContextHolder.setIgnore(false); + TenantContextHolder.setTenantId(user.getTenantId()); + return user; + } + + @Override + public String[] getRoles(String token) { + // 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档 + // 适配:如果是本系统的管理员,则转换成 jimu 报表的管理员 + Long userId = SecurityFrameworkUtils.getLoginUserId(); + return permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode()) + ? new String[]{"admin"} : null; + } + + @Override + public String getTenantId() { + // 补充说明:不能直接通过 TenantContext 获取,因为 jimu 报表前端请求时,没有带上 tenant-id Header + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + return null; + } + return StrUtil.toStringOrNull(loginUser.getTenantId()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/web/package-info.java new file mode 100644 index 0000000..e082e3b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/web/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位,后续会基于 Filter 实现积木报表的认证等功能,替代 {@link cn.iocoder.yudao.module.report.framework.jmreport.core.service.JmReportTokenServiceImpl} + */ +package cn.iocoder.yudao.module.report.framework.jmreport.core.web; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/package-info.java new file mode 100644 index 0000000..c2163d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 report 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.report.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/config/SecurityConfiguration.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/config/SecurityConfiguration.java new file mode 100644 index 0000000..0de31d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.report.framework.security.config; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; + +import javax.annotation.Resource; + +/** + * Report 模块的 Security 配置 + */ +@Configuration("reportSecurityConfiguration") +public class SecurityConfiguration { + + @Resource + private OAuth2TokenApi oauth2TokenApi; + + @Bean("reportAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) { + registry.antMatchers("/jmreport/**").permitAll(); // 积木报表 + } + + }; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/core/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/core/package-info.java new file mode 100644 index 0000000..6108326 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.report.framework.security.core; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/package-info.java new file mode 100644 index 0000000..3306c0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/package-info.java @@ -0,0 +1,9 @@ +/** + * report 模块,主要实现数据可视化报表等功能: + * 1. 基于「积木报表」实现,打印设计、报表设计、图形设计、大屏设计等。URL 前缀是 /jmreport,表名前缀是 jimu_ + * + * 由于「积木报表」的大屏设计器需要收费,后续会自研,对应的是: + * 1. Controller URL:以 /report/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 report_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.report; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/ajreport/package-info.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/ajreport/package-info.java new file mode 100644 index 0000000..2512e50 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/ajreport/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:占位,待删除 + */ +package cn.iocoder.yudao.module.report.service.ajreport; diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataService.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataService.java new file mode 100644 index 0000000..b912373 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataService.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.data.GoViewDataRespVO; + +/** + * GoView 数据 Service 接口 + * + * @author 芋道源码 + */ +public interface GoViewDataService { + + /** + * 使用 SQL 查询数据 + * + * @param sql SQL 语句 + * @return 数据 + */ + GoViewDataRespVO getDataBySQL(String sql); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImpl.java new file mode 100644 index 0000000..8938d3e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImpl.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.data.GoViewDataRespVO; +import com.google.common.collect.Maps; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.jdbc.support.rowset.SqlRowSetMetaData; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Map; + +/** + * GoView 数据 Service 实现类 + * + * 补充说明: + * 1. 目前默认使用 jdbcTemplate 查询项目配置的数据源。如果你想查询其它数据源,可以新建对应数据源的 jdbcTemplate 来实现。 + * 2. 默认数据源是 MySQL 关系数据源,可能数据量比较大的情况下,会比较慢,可以考虑后续使用 Click House 等等。 + * + * @author 芋道源码 + */ +@Service +@Validated +public class GoViewDataServiceImpl implements GoViewDataService { + + @Resource + private JdbcTemplate jdbcTemplate; + + @Override + public GoViewDataRespVO getDataBySQL(String sql) { + // 1. 执行查询 + SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql); + + // 2. 构建返回结果 + GoViewDataRespVO respVO = new GoViewDataRespVO(); + // 2.1 解析元数据 + SqlRowSetMetaData metaData = sqlRowSet.getMetaData(); + String[] columnNames = metaData.getColumnNames(); + respVO.setDimensions(Arrays.asList(columnNames)); + // 2.2 解析数据明细 + respVO.setSource(new LinkedList<>()); // 由于数据量不确认,使用 LinkedList 虽然内存占用大一点,但是不存在扩容复制的问题 + while (sqlRowSet.next()) { + Map data = Maps.newHashMapWithExpectedSize(columnNames.length); + for (String columnName : columnNames) { + data.put(columnName, sqlRowSet.getObject(columnName)); + } + respVO.getSource().add(data); + } + return respVO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectService.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectService.java new file mode 100644 index 0000000..b171c59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectService.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectCreateReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectUpdateReqVO; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; + +import javax.validation.Valid; + +/** + * GoView 项目 Service 接口 + * + * @author 芋道源码 + */ +public interface GoViewProjectService { + + /** + * 创建项目 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProject(@Valid GoViewProjectCreateReqVO createReqVO); + + /** + * 更新项目 + * + * @param updateReqVO 更新信息 + */ + void updateProject(@Valid GoViewProjectUpdateReqVO updateReqVO); + + /** + * 删除项目 + * + * @param id 编号 + */ + void deleteProject(Long id); + + /** + * 获得项目 + * + * @param id 编号 + * @return 项目 + */ + GoViewProjectDO getProject(Long id); + + /** + * 获得我的项目分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return GoView 项目分页 + */ + PageResult getMyProjectPage(PageParam pageReqVO, Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImpl.java new file mode 100644 index 0000000..2b05052 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImpl.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectCreateReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectUpdateReqVO; +import cn.iocoder.yudao.module.report.convert.goview.GoViewProjectConvert; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; +import cn.iocoder.yudao.module.report.dal.mysql.goview.GoViewProjectMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.report.enums.ErrorCodeConstants.GO_VIEW_PROJECT_NOT_EXISTS; + +/** + * GoView 项目 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class GoViewProjectServiceImpl implements GoViewProjectService { + + @Resource + private GoViewProjectMapper goViewProjectMapper; + + @Override + public Long createProject(GoViewProjectCreateReqVO createReqVO) { + // 插入 + GoViewProjectDO goViewProject = GoViewProjectConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.DISABLE.getStatus()); + goViewProjectMapper.insert(goViewProject); + // 返回 + return goViewProject.getId(); + } + + @Override + public void updateProject(GoViewProjectUpdateReqVO updateReqVO) { + // 校验存在 + validateProjectExists(updateReqVO.getId()); + // 更新 + GoViewProjectDO updateObj = GoViewProjectConvert.INSTANCE.convert(updateReqVO); + goViewProjectMapper.updateById(updateObj); + } + + @Override + public void deleteProject(Long id) { + // 校验存在 + validateProjectExists(id); + // 删除 + goViewProjectMapper.deleteById(id); + } + + private void validateProjectExists(Long id) { + if (goViewProjectMapper.selectById(id) == null) { + throw exception(GO_VIEW_PROJECT_NOT_EXISTS); + } + } + + @Override + public GoViewProjectDO getProject(Long id) { + return goViewProjectMapper.selectById(id); + } + + @Override + public PageResult getMyProjectPage(PageParam pageReqVO, Long userId) { + return goViewProjectMapper.selectPage(pageReqVO, userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImplTest.java new file mode 100644 index 0000000..87b78b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewDataServiceImplTest.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.data.GoViewDataRespVO; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.jdbc.support.rowset.SqlRowSetMetaData; + +import javax.annotation.Resource; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@Import(GoViewDataServiceImpl.class) +public class GoViewDataServiceImplTest extends BaseDbUnitTest { + + @Resource + private GoViewDataServiceImpl goViewDataService; + + @MockBean + private JdbcTemplate jdbcTemplate; + + @Test + public void testGetDataBySQL() { + // 准备参数 + String sql = "SELECT id, name FROM system_users"; + // mock 方法 + SqlRowSet sqlRowSet = mock(SqlRowSet.class); + when(jdbcTemplate.queryForRowSet(eq(sql))).thenReturn(sqlRowSet); + // mock 元数据 + SqlRowSetMetaData metaData = mock(SqlRowSetMetaData.class); + when(sqlRowSet.getMetaData()).thenReturn(metaData); + when(metaData.getColumnNames()).thenReturn(new String[]{"id", "name"}); + // mock 数据明细 + when(sqlRowSet.next()).thenReturn(true).thenReturn(true).thenReturn(false); + when(sqlRowSet.getObject("id")).thenReturn(1L).thenReturn(2L); + when(sqlRowSet.getObject("name")).thenReturn("芋道源码").thenReturn("芋道"); + + // 调用 + GoViewDataRespVO dataBySQL = goViewDataService.getDataBySQL(sql); + // 断言 + assertEquals(Arrays.asList("id", "name"), dataBySQL.getDimensions()); + assertEquals(2, dataBySQL.getDimensions().size()); + assertEquals(2, dataBySQL.getSource().get(0).size()); + assertEquals(1L, dataBySQL.getSource().get(0).get("id")); + assertEquals("芋道源码", dataBySQL.getSource().get(0).get("name")); + assertEquals(2, dataBySQL.getSource().get(1).size()); + assertEquals(2L, dataBySQL.getSource().get(1).get("id")); + assertEquals("芋道", dataBySQL.getSource().get(1).get("name")); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImplTest.java new file mode 100644 index 0000000..2f6bfae --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/java/cn/iocoder/yudao/module/report/service/goview/GoViewProjectServiceImplTest.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.report.service.goview; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectCreateReqVO; +import cn.iocoder.yudao.module.report.controller.admin.goview.vo.project.GoViewProjectUpdateReqVO; +import cn.iocoder.yudao.module.report.dal.dataobject.goview.GoViewProjectDO; +import cn.iocoder.yudao.module.report.dal.mysql.goview.GoViewProjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.report.enums.ErrorCodeConstants.GO_VIEW_PROJECT_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link GoViewProjectServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(GoViewProjectServiceImpl.class) +public class GoViewProjectServiceImplTest extends BaseDbUnitTest { + + @Resource + private GoViewProjectServiceImpl goViewProjectService; + + @Resource + private GoViewProjectMapper goViewProjectMapper; + + @Test + public void testCreateProject_success() { + // 准备参数 + GoViewProjectCreateReqVO reqVO = randomPojo(GoViewProjectCreateReqVO.class); + + // 调用 + Long goViewProjectId = goViewProjectService.createProject(reqVO); + // 断言 + assertNotNull(goViewProjectId); + // 校验记录的属性是否正确 + GoViewProjectDO goViewProject = goViewProjectMapper.selectById(goViewProjectId); + assertPojoEquals(reqVO, goViewProject); + } + + @Test + public void testUpdateProject_success() { + // mock 数据 + GoViewProjectDO dbGoViewProject = randomPojo(GoViewProjectDO.class); + goViewProjectMapper.insert(dbGoViewProject);// @Sql: 先插入出一条存在的数据 + // 准备参数 + GoViewProjectUpdateReqVO reqVO = randomPojo(GoViewProjectUpdateReqVO.class, o -> { + o.setId(dbGoViewProject.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用 + goViewProjectService.updateProject(reqVO); + // 校验是否更新正确 + GoViewProjectDO goViewProject = goViewProjectMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, goViewProject); + } + + @Test + public void testUpdateProject_notExists() { + // 准备参数 + GoViewProjectUpdateReqVO reqVO = randomPojo(GoViewProjectUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> goViewProjectService.updateProject(reqVO), GO_VIEW_PROJECT_NOT_EXISTS); + } + + @Test + public void testDeleteProject_success() { + // mock 数据 + GoViewProjectDO dbGoViewProject = randomPojo(GoViewProjectDO.class); + goViewProjectMapper.insert(dbGoViewProject);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbGoViewProject.getId(); + + // 调用 + goViewProjectService.deleteProject(id); + // 校验数据不存在了 + assertNull(goViewProjectMapper.selectById(id)); + } + + @Test + public void testDeleteProject_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> goViewProjectService.deleteProject(id), GO_VIEW_PROJECT_NOT_EXISTS); + } + + @Test + public void testGetProject() { + // mock 数据 + GoViewProjectDO dbGoViewProject = randomPojo(GoViewProjectDO.class); + goViewProjectMapper.insert(dbGoViewProject);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbGoViewProject.getId(); + + // 调用 + GoViewProjectDO goViewProject = goViewProjectService.getProject(id); + // 断言 + assertPojoEquals(dbGoViewProject, goViewProject); + } + + @Test + public void testGetMyGoViewProjectPage() { + // mock 数据 + GoViewProjectDO dbGoViewProject = randomPojo(GoViewProjectDO.class, o -> { // 等会查询到 + o.setCreator("1"); + }); + goViewProjectMapper.insert(dbGoViewProject); + // 测试 userId 不匹配 + goViewProjectMapper.insert(cloneIgnoreId(dbGoViewProject, o -> o.setCreator("2"))); + // 准备参数 + PageParam reqVO = new PageParam(); + Long userId = 1L; + + // 调用 + PageResult pageResult = goViewProjectService.getMyProjectPage(reqVO, userId); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbGoViewProject, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..eb823d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,53 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module + captcha: + timeout: 5m + width: 160 + height: 60 + enable: true diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..1529151 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/clean.sql @@ -0,0 +1 @@ +DELETE FROM "report_go_view_project"; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..a77397f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-report/yudao-module-report-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS "report_go_view_project" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "pic_url" varchar, + "content" varchar, + "status" varchar NOT NULL, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT 'GoView 项目表'; diff --git a/ruoyi-vue-pro-master/yudao-module-system/pom.xml b/ruoyi-vue-pro-master/yudao-module-system/pom.xml new file mode 100644 index 0000000..c2cc5a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/pom.xml @@ -0,0 +1,24 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + + yudao-module-system-api + yudao-module-system-biz + + yudao-module-system + pom + + ${project.artifactId} + + system 模块下,我们放通用业务,支撑上层的核心业务。 + 例如说:用户、部门、权限、数据字典等等 + + + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/pom.xml b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/pom.xml new file mode 100644 index 0000000..c98baf3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.boot + yudao-module-system + ${revision} + + 4.0.0 + yudao-module-system-api + jar + + ${project.artifactId} + + system 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java new file mode 100644 index 0000000..bdc3ba5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.system.api.dept; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 部门 API 接口 + * + * @author 芋道源码 + */ +public interface DeptApi { + + /** + * 获得部门信息 + * + * @param id 部门编号 + * @return 部门信息 + */ + DeptRespDTO getDept(Long id); + + /** + * 获得部门信息数组 + * + * @param ids 部门编号数组 + * @return 部门信息数组 + */ + List getDeptList(Collection ids); + + /** + * 校验部门们是否有效。如下情况,视为无效: + * 1. 部门编号不存在 + * 2. 部门被禁用 + * + * @param ids 角色编号数组 + */ + void validateDeptList(Collection ids); + + /** + * 获得指定编号的部门 Map + * + * @param ids 部门编号数组 + * @return 部门 Map + */ + default Map getDeptMap(Collection ids) { + List list = getDeptList(ids); + return CollectionUtils.convertMap(list, DeptRespDTO::getId); + } + + /** + * 获得指定部门的所有子部门 + * + * @param id 部门编号 + * @return 子部门列表 + */ + List getChildDeptList(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApi.java new file mode 100644 index 0000000..c38f4cd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApi.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.api.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 岗位 API 接口 + * + * @author 芋道源码 + */ +public interface PostApi { + + /** + * 校验岗位们是否有效。如下情况,视为无效: + * 1. 岗位编号不存在 + * 2. 岗位被禁用 + * + * @param ids 岗位编号数组 + */ + void validPostList(Collection ids); + + List getPostList(Collection ids); + + default Map getPostMap(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return MapUtil.empty(); + } + + List list = getPostList(ids); + return CollectionUtils.convertMap(list, PostRespDTO::getId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java new file mode 100644 index 0000000..d3e66fd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.dept.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +/** + * 部门 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DeptRespDTO { + + /** + * 部门编号 + */ + private Long id; + /** + * 部门名称 + */ + private String name; + /** + * 父部门编号 + */ + private Long parentId; + /** + * 负责人的用户编号 + */ + private Long leaderUserId; + /** + * 部门状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/PostRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/PostRespDTO.java new file mode 100644 index 0000000..cf2cc25 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/PostRespDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.dept.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +/** + * 岗位 Response DTO + * + * @author 芋道源码 + */ +@Data +public class PostRespDTO { + + /** + * 岗位序号 + */ + private Long id; + /** + * 岗位名称 + */ + private String name; + /** + * 岗位编码 + */ + private String code; + /** + * 岗位排序 + */ + private Integer sort; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java new file mode 100644 index 0000000..b75684d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.system.api.dict; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 字典数据 API 接口 + * + * @author 芋道源码 + */ +public interface DictDataApi { + + /** + * 校验字典数据们是否有效。如下情况,视为无效: + * 1. 字典数据不存在 + * 2. 字典数据被禁用 + * + * @param dictType 字典类型 + * @param values 字典数据值的数组 + */ + void validateDictDataList(String dictType, Collection values); + + /** + * 获得指定的字典数据,从缓存中 + * + * @param type 字典类型 + * @param value 字典数据值 + * @return 字典数据 + */ + DictDataRespDTO getDictData(String type, String value); + + /** + * 获得指定的字典标签,从缓存中 + * + * @param type 字典类型 + * @param value 字典数据值 + * @return 字典标签 + */ + default String getDictDataLabel(String type, Integer value) { + DictDataRespDTO dictData = getDictData(type, String.valueOf(value)); + if (ObjUtil.isNull(dictData)) { + return StrUtil.EMPTY; + } + return dictData.getLabel(); + } + + /** + * 解析获得指定的字典数据,从缓存中 + * + * @param type 字典类型 + * @param label 字典数据标签 + * @return 字典数据 + */ + DictDataRespDTO parseDictData(String type, String label); + + /** + * 获得指定字典类型的字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + List getDictDataList(String dictType); + + /** + * 获得字典数据标签列表 + * + * @param dictType 字典类型 + * @return 字典数据标签列表 + */ + default List getDictDataLabelList(String dictType) { + List list = getDictDataList(dictType); + return convertList(list, DictDataRespDTO::getLabel); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/dto/DictDataRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/dto/DictDataRespDTO.java new file mode 100644 index 0000000..fe5ab6a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/dto/DictDataRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.api.dict.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +/** + * 字典数据 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DictDataRespDTO { + + /** + * 字典标签 + */ + private String label; + /** + * 字典值 + */ + private String value; + /** + * 字典类型 + */ + private String dictType; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApi.java new file mode 100644 index 0000000..4ff596c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApi.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.api.logger; + +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; + +import javax.validation.Valid; + +/** + * 登录日志的 API 接口 + * + * @author 芋道源码 + */ +public interface LoginLogApi { + + /** + * 创建登录日志 + * + * @param reqDTO 日志信息 + */ + void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java new file mode 100644 index 0000000..86962ad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.api.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogRespDTO; + +import javax.validation.Valid; + +/** + * 操作日志 API 接口 + * + * @author 芋道源码 + */ +public interface OperateLogApi { + + /** + * 创建操作日志 + * + * @param createReqDTO 请求 + */ + void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO); + + /** + * 获取指定模块的指定数据的操作日志分页 + * + * @param pageReqVO 请求 + * @return 操作日志分页 + */ + PageResult getOperateLogPage(OperateLogPageReqDTO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java new file mode 100644 index 0000000..5131056 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.system.api.logger.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 登录日志创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class LoginLogCreateReqDTO { + + /** + * 日志类型 + */ + @NotNull(message = "日志类型不能为空") + private Integer logType; + /** + * 链路追踪编号 + */ + private String traceId; + + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + */ + @NotNull(message = "用户类型不能为空") + private Integer userType; + /** + * 用户账号 + * + * 不再强制校验 username 非空,因为 Member 社交登录时,此时暂时没有 username(mobile)! + */ + private String username; + + /** + * 登录结果 + */ + @NotNull(message = "登录结果不能为空") + private Integer result; + + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + /** + * 浏览器 UserAgent + * + * 允许空,原因:Job 过期登出时,是无法传递 UserAgent 的 + */ + private String userAgent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogCreateReqDTO.java new file mode 100644 index 0000000..e7a3db7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogCreateReqDTO.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.system.api.logger.dto; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 系统操作日志 Create Request DTO + * + * @author HUIHUI + */ +@Data +public class OperateLogCreateReqDTO { + + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + * + * 关联 {@link UserTypeEnum} + */ + @NotNull(message = "用户类型不能为空") + private Integer userType; + /** + * 操作模块类型 + */ + @NotEmpty(message = "操作模块类型不能为空") + private String type; + /** + * 操作名 + */ + @NotEmpty(message = "操作名不能为空") + private String subType; + /** + * 操作模块业务编号 + */ + @NotNull(message = "操作模块业务编号不能为空") + private Long bizId; + /** + * 操作内容,记录整个操作的明细 + * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + */ + @NotEmpty(message = "操作内容不能为空") + private String action; + /** + * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ) + * 例如说,记录订单编号,{ orderId: "1"} + */ + private String extra; + + /** + * 请求方法名 + */ + @NotEmpty(message = "请求方法名不能为空") + private String requestMethod; + /** + * 请求地址 + */ + @NotEmpty(message = "请求地址不能为空") + private String requestUrl; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + /** + * 浏览器 UA + */ + @NotEmpty(message = "浏览器 UA 不能为空") + private String userAgent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogPageReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogPageReqDTO.java new file mode 100644 index 0000000..80e52cd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogPageReqDTO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.api.logger.dto; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import lombok.Data; + +/** + * 操作日志分页 Request DTO + * + * @author HUIHUI + */ +@Data +public class OperateLogPageReqDTO extends PageParam { + + /** + * 模块类型 + */ + private String type; + /** + * 模块数据编号 + */ + private Long bizId; + + /** + * 用户编号 + */ + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogRespDTO.java new file mode 100644 index 0000000..34a7526 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogRespDTO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.system.api.logger.dto; + +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 系统操作日志 Resp DTO + * + * @author HUIHUI + */ +@Data +public class OperateLogRespDTO implements VO { + + /** + * 日志编号 + */ + private Long id; + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + @Trans(type = TransType.RPC, targetClassName = "cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO", + fields = "nickname", ref = "userName") + private Long userId; + /** + * 用户名称 + */ + private String userName; + /** + * 用户类型 + */ + private Integer userType; + /** + * 操作模块类型 + */ + private String type; + /** + * 操作名 + */ + private String subType; + /** + * 操作模块业务编号 + */ + private Long bizId; + /** + * 操作内容 + */ + private String action; + /** + * 拓展字段 + */ + private String extra; + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 请求地址 + */ + private String requestUrl; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java new file mode 100644 index 0000000..5427277 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApi.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.mail; + +import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleToUserReqDTO; + +import javax.validation.Valid; + +/** + * 邮箱发送 API 接口 + * + * @author 芋道源码 + */ +public interface MailSendApi { + + /** + * 发送单条邮箱给 Admin 用户 + * + * 在 mail 为空时,使用 userId 加载对应 Admin 的邮箱 + * + * @param reqDTO 发送请求 + * @return 发送日志编号 + */ + Long sendSingleMailToAdmin(@Valid MailSendSingleToUserReqDTO reqDTO); + + /** + * 发送单条邮箱给 Member 用户 + * + * 在 mail 为空时,使用 userId 加载对应 Member 的邮箱 + * + * @param reqDTO 发送请求 + * @return 发送日志编号 + */ + Long sendSingleMailToMember(@Valid MailSendSingleToUserReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java new file mode 100644 index 0000000..c8c5cba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.mail.dto; + +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * 邮件发送 Request DTO + * + * @author wangjingqi + */ +@Data +public class MailSendSingleToUserReqDTO { + + /** + * 用户编号 + */ + private Long userId; + /** + * 邮箱 + */ + @Email + private String mail; + + /** + * 邮件模板编号 + */ + @NotNull(message = "邮件模板编号不能为空") + private String templateCode; + /** + * 邮件模板参数 + */ + private Map templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java new file mode 100644 index 0000000..facedfa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.api.notify; + +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; + +import javax.validation.Valid; + +/** + * 站内信发送 API 接口 + * + * @author xrcoder + */ +public interface NotifyMessageSendApi { + + /** + * 发送单条站内信给 Admin 用户 + * + * @param reqDTO 发送请求 + * @return 发送消息 ID + */ + Long sendSingleMessageToAdmin(@Valid NotifySendSingleToUserReqDTO reqDTO); + + /** + * 发送单条站内信给 Member 用户 + * + * @param reqDTO 发送请求 + * @return 发送消息 ID + */ + Long sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java new file mode 100644 index 0000000..502d3eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifySendSingleToUserReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.api.notify.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * 站内信发送给 Admin 或者 Member 用户 + * + * @author xrcoder + */ +@Data +public class NotifySendSingleToUserReqDTO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + + /** + * 站内信模板编号 + */ + @NotEmpty(message = "站内信模板编号不能为空") + private String templateCode; + + /** + * 站内信模板参数 + */ + private Map templateParams; +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java new file mode 100644 index 0000000..09d5b6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.notify.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Data +public class NotifyTemplateReqDTO { + + @NotEmpty(message = "模版名称不能为空") + private String name; + + @NotNull(message = "模版编码不能为空") + private String code; + + @NotNull(message = "模版类型不能为空") + private Integer type; + + @NotEmpty(message = "发送人名称不能为空") + private String nickname; + + @NotEmpty(message = "模版内容不能为空") + private String content; + + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApi.java new file mode 100644 index 0000000..79393cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApi.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.api.oauth2; + +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; + +import javax.validation.Valid; + +/** + * OAuth2.0 Token API 接口 + * + * @author 芋道源码 + */ +public interface OAuth2TokenApi { + + /** + * 创建访问令牌 + * + * @param reqDTO 访问令牌的创建信息 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO); + + /** + * 校验访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken); + + /** + * 移除访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenRespDTO removeAccessToken(String accessToken); + + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java new file mode 100644 index 0000000..9332104 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCheckRespDTO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.api.oauth2.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * OAuth2.0 访问令牌的校验 Response DTO + * + * @author 芋道源码 + */ +@Data +public class OAuth2AccessTokenCheckRespDTO implements Serializable { + + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 用户信息 + */ + private Map userInfo; + /** + * 租户编号 + */ + private Long tenantId; + /** + * 授权范围的数组 + */ + private List scopes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java new file mode 100644 index 0000000..9257cc9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenCreateReqDTO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.api.oauth2.dto; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** + * OAuth2.0 访问令牌创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class OAuth2AccessTokenCreateReqDTO implements Serializable { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @NotNull(message = "用户类型不能为空") + @InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}") + private Integer userType; + /** + * 客户端编号 + */ + @NotNull(message = "客户端编号不能为空") + private String clientId; + /** + * 授权范围 + */ + private List scopes; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenRespDTO.java new file mode 100644 index 0000000..4c82632 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/dto/OAuth2AccessTokenRespDTO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.api.oauth2.dto; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * OAuth2.0 访问令牌的信息 Response DTO + * + * @author 芋道源码 + */ +@Data +@Accessors(chain = true) +public class OAuth2AccessTokenRespDTO implements Serializable { + + /** + * 访问令牌 + */ + private String accessToken; + /** + * 刷新令牌 + */ + private String refreshToken; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + */ + private Integer userType; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/package-info.java new file mode 100644 index 0000000..25bfc44 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/package-info.java @@ -0,0 +1,4 @@ +/** + * System API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.system.api; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApi.java new file mode 100644 index 0000000..ea16fe4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApi.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.api.permission; + +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; + +import java.util.Collection; +import java.util.Set; + +/** + * 权限 API 接口 + * + * @author 芋道源码 + */ +public interface PermissionApi { + + /** + * 获得拥有多个角色的用户编号集合 + * + * @param roleIds 角色编号集合 + * @return 用户编号集合 + */ + Set getUserRoleIdListByRoleIds(Collection roleIds); + + /** + * 判断是否有权限,任一一个即可 + * + * @param userId 用户编号 + * @param permissions 权限 + * @return 是否 + */ + boolean hasAnyPermissions(Long userId, String... permissions); + + /** + * 判断是否有角色,任一一个即可 + * + * @param userId 用户编号 + * @param roles 角色数组 + * @return 是否 + */ + boolean hasAnyRoles(Long userId, String... roles); + + /** + * 获得登陆用户的部门数据权限 + * + * @param userId 用户编号 + * @return 部门数据权限 + */ + DeptDataPermissionRespDTO getDeptDataPermission(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java new file mode 100644 index 0000000..309c9ef --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.api.permission; + +import java.util.Collection; + +/** + * 角色 API 接口 + * + * @author 芋道源码 + */ +public interface RoleApi { + + /** + * 校验角色们是否有效。如下情况,视为无效: + * 1. 角色编号不存在 + * 2. 角色被禁用 + * + * @param ids 角色编号数组 + */ + void validRoleList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/DeptDataPermissionRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/DeptDataPermissionRespDTO.java new file mode 100644 index 0000000..5650e89 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/DeptDataPermissionRespDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.api.permission.dto; + +import lombok.Data; + +import java.util.HashSet; +import java.util.Set; + +/** + * 部门的数据权限 Response DTO + * + * @author 芋道源码 + */ +@Data +public class DeptDataPermissionRespDTO { + + /** + * 是否可查看全部数据 + */ + private Boolean all; + /** + * 是否可查看自己的数据 + */ + private Boolean self; + /** + * 可查看的部门编号数组 + */ + private Set deptIds; + + public DeptDataPermissionRespDTO() { + this.all = false; + this.self = false; + this.deptIds = new HashSet<>(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java new file mode 100644 index 0000000..98d4cde --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.api.sms; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; + +import javax.validation.Valid; + +/** + * 短信验证码 API 接口 + * + * @author 芋道源码 + */ +public interface SmsCodeApi { + + /** + * 创建短信验证码,并进行发送 + * + * @param reqDTO 发送请求 + */ + void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO); + + /** + * 验证短信验证码,并进行使用 + * 如果正确,则将验证码标记成已使用 + * 如果错误,则抛出 {@link ServiceException} 异常 + * + * @param reqDTO 使用请求 + */ + void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO); + + /** + * 检查验证码是否有效 + * + * @param reqDTO 校验请求 + */ + void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApi.java new file mode 100644 index 0000000..c86bbf5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApi.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.sms; + +import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; + +import javax.validation.Valid; + +/** + * 短信发送 API 接口 + * + * @author 芋道源码 + */ +public interface SmsSendApi { + + /** + * 发送单条短信给 Admin 用户 + * + * 在 mobile 为空时,使用 userId 加载对应 Admin 的手机号 + * + * @param reqDTO 发送请求 + * @return 发送日志编号 + */ + Long sendSingleSmsToAdmin(@Valid SmsSendSingleToUserReqDTO reqDTO); + + /** + * 发送单条短信给 Member 用户 + * + * 在 mobile 为空时,使用 userId 加载对应 Member 的手机号 + * + * @param reqDTO 发送请求 + * @return 发送日志编号 + */ + Long sendSingleSmsToMember(@Valid SmsSendSingleToUserReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeSendReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeSendReqDTO.java new file mode 100644 index 0000000..5d6579b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeSendReqDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.sms.dto.code; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信验证码的发送 Request DTO + * + * @author 芋道源码 + */ +@Data +public class SmsCodeSendReqDTO { + + /** + * 手机号 + */ + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + /** + * 发送场景 + */ + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + /** + * 发送 IP + */ + @NotEmpty(message = "发送 IP 不能为空") + private String createIp; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeUseReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeUseReqDTO.java new file mode 100644 index 0000000..3043adf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeUseReqDTO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.api.sms.dto.code; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信验证码的使用 Request DTO + * + * @author 芋道源码 + */ +@Data +public class SmsCodeUseReqDTO { + + /** + * 手机号 + */ + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + /** + * 发送场景 + */ + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + /** + * 验证码 + */ + @NotEmpty(message = "验证码") + private String code; + /** + * 使用 IP + */ + @NotEmpty(message = "使用 IP 不能为空") + private String usedIp; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeValidateReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeValidateReqDTO.java new file mode 100644 index 0000000..e780835 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/code/SmsCodeValidateReqDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.sms.dto.code; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信验证码的校验 Request DTO + * + * @author 芋道源码 + */ +@Data +public class SmsCodeValidateReqDTO { + + /** + * 手机号 + */ + @Mobile + @NotEmpty(message = "手机号不能为空") + private String mobile; + /** + * 发送场景 + */ + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + /** + * 验证码 + */ + @NotEmpty(message = "验证码") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java new file mode 100644 index 0000000..ef77780 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.api.sms.dto.send; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Map; + +/** + * 短信发送给 Admin 或者 Member 用户 + * + * @author 芋道源码 + */ +@Data +public class SmsSendSingleToUserReqDTO { + + /** + * 用户编号 + */ + private Long userId; + /** + * 手机号 + */ + @Mobile + private String mobile; + /** + * 短信模板编号 + */ + @NotEmpty(message = "短信模板编号不能为空") + private String templateCode; + /** + * 短信模板参数 + */ + private Map templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java new file mode 100644 index 0000000..7fdb35a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.api.social; + +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; + +/** + * 社交应用的 API 接口 + * + * @author 芋道源码 + */ +public interface SocialClientApi { + + /** + * 获得社交平台的授权 URL + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param redirectUri 重定向 URL + * @return 社交平台的授权 URL + */ + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri); + + /** + * 创建微信公众号 JS SDK 初始化所需的签名 + * + * @param userType 用户类型 + * @param url 访问的 URL 地址 + * @return 签名 + */ + SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url); + + /** + * 获得微信小程序的手机信息 + * + * @param userType 用户类型 + * @param phoneCode 手机授权码 + * @return 手机信息 + */ + SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java new file mode 100644 index 0000000..05c6acb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.api.social; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; + +import javax.validation.Valid; + +/** + * 社交用户的 API 接口 + * + * @author 芋道源码 + */ +public interface SocialUserApi { + + /** + * 绑定社交用户 + * + * @param reqDTO 绑定信息 + * @return 社交用户 openid + */ + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); + + /** + * 取消绑定社交用户 + * + * @param reqDTO 解绑 + */ + void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); + + /** + * 获得社交用户,基于 userId + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param socialType 社交平台的类型 + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType); + + /** + * 获得社交用户 + * + * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 + * + * @param userType 用户类型 + * @param socialType 社交平台的类型 + * @param code 授权码 + * @param state state + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java new file mode 100644 index 0000000..f8f7154 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 取消绑定社交用户 Request DTO + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserBindReqDTO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + /** + * 社交平台的类型 + */ + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer socialType; + /** + * 授权码 + */ + @NotEmpty(message = "授权码不能为空") + private String code; + /** + * state + */ + @NotNull(message = "state 不能为空") + private String state; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java new file mode 100644 index 0000000..29fef01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 社交用户 Response DTO + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserRespDTO { + + /** + * 社交用户的 openid + */ + private String openid; + /** + * 社交用户的昵称 + */ + private String nickname; + /** + * 社交用户的头像 + */ + private String avatar; + + /** + * 关联的用户编号 + */ + private Long userId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserUnbindReqDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserUnbindReqDTO.java new file mode 100644 index 0000000..3c6be32 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserUnbindReqDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 社交绑定 Request DTO,使用 code 授权码 + * + * @author 芋道源码 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SocialUserUnbindReqDTO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + /** + * 社交平台的类型 + */ + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer socialType; + + /** + * 社交平台的 openid + */ + @NotEmpty(message = "社交平台的 openid 不能为空") + private String openid; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxJsapiSignatureRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxJsapiSignatureRespDTO.java new file mode 100644 index 0000000..7d332e9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxJsapiSignatureRespDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import lombok.Data; + +/** + * 微信公众号 JSAPI 签名 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SocialWxJsapiSignatureRespDTO { + + /** + * 微信公众号的 appId + */ + private String appId; + /** + * 匿名串 + */ + private String nonceStr; + /** + * 时间戳 + */ + private Long timestamp; + /** + * URL + */ + private String url; + /** + * 签名 + */ + private String signature; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java new file mode 100644 index 0000000..9d404b3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxPhoneNumberInfoRespDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import lombok.Data; + +/** + * 微信小程序的手机信息 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SocialWxPhoneNumberInfoRespDTO { + + /** + * 用户绑定的手机号(国外手机号会有区号) + */ + private String phoneNumber; + + /** + * 没有区号的手机号 + */ + private String purePhoneNumber; + /** + * 区号 + */ + private String countryCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java new file mode 100644 index 0000000..1fad83e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApi.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.api.tenant; + +import java.util.List; + +/** + * 多租户的 API 接口 + * + * @author 芋道源码 + */ +public interface TenantApi { + + /** + * 获得所有租户 + * + * @return 租户编号数组 + */ + List getTenantIdList(); + + /** + * 校验租户是否合法 + * + * @param id 租户编号 + */ + void validateTenant(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java new file mode 100644 index 0000000..507fb4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.system.api.user; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Admin 用户 API 接口 + * + * @author 芋道源码 + */ +public interface AdminUserApi { + + /** + * 通过用户 ID 查询用户 + * + * @param id 用户ID + * @return 用户对象信息 + */ + AdminUserRespDTO getUser(Long id); + + /** + * 通过用户 ID 查询用户下属 + * + * @param id 用户编号 + * @return 用户下属用户列表 + */ + List getUserListBySubordinate(Long id); + + /** + * 通过用户 ID 查询用户们 + * + * @param ids 用户 ID 们 + * @return 用户对象信息 + */ + List getUserList(Collection ids); + + /** + * 获得指定部门的用户数组 + * + * @param deptIds 部门数组 + * @return 用户数组 + */ + List getUserListByDeptIds(Collection deptIds); + + /** + * 获得指定岗位的用户数组 + * + * @param postIds 岗位数组 + * @return 用户数组 + */ + List getUserListByPostIds(Collection postIds); + + /** + * 获得用户 Map + * + * @param ids 用户编号数组 + * @return 用户 Map + */ + default Map getUserMap(Collection ids) { + List users = getUserList(ids); + return CollectionUtils.convertMap(users, AdminUserRespDTO::getId); + } + + /** + * 校验用户是否有效。如下情况,视为无效: + * 1. 用户编号不存在 + * 2. 用户被禁用 + * + * @param id 用户编号 + */ + default void validateUser(Long id) { + validateUserList(Collections.singleton(id)); + } + + /** + * 校验用户们是否有效。如下情况,视为无效: + * 1. 用户编号不存在 + * 2. 用户被禁用 + * + * @param ids 用户编号数组 + */ + void validateUserList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/AdminUserRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/AdminUserRespDTO.java new file mode 100644 index 0000000..ac13c3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/AdminUserRespDTO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.system.api.user.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +import java.util.Set; + +/** + * Admin 用户 Response DTO + * + * @author 芋道源码 + */ +@Data +public class AdminUserRespDTO { + + /** + * 用户ID + */ + private Long id; + /** + * 用户昵称 + */ + private String nickname; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 部门ID + */ + private Long deptId; + /** + * 岗位编号数组 + */ + private Set postIds; + /** + * 手机号码 + */ + private String mobile; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java new file mode 100644 index 0000000..d7967fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.enums; + +/** + * System 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String USER_TYPE = "user_type"; // 用户类型 + String COMMON_STATUS = "common_status"; // 系统状态 + + // ========== SYSTEM 模块 ========== + + String USER_SEX = "system_user_sex"; // 用户性别 + + String LOGIN_TYPE = "system_login_type"; // 登录日志的类型 + String LOGIN_RESULT = "system_login_result"; // 登录结果 + + String ERROR_CODE_TYPE = "system_error_code_type"; // 错误码的类型枚举 + + String SMS_CHANNEL_CODE = "system_sms_channel_code"; // 短信渠道编码 + String SMS_TEMPLATE_TYPE = "system_sms_template_type"; // 短信模板类型 + String SMS_SEND_STATUS = "system_sms_send_status"; // 短信发送状态 + String SMS_RECEIVE_STATUS = "system_sms_receive_status"; // 短信接收状态 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java new file mode 100644 index 0000000..1b4c313 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -0,0 +1,166 @@ +package cn.iocoder.yudao.module.system.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * System 错误码枚举类 + * + * system 系统,使用 1-002-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== AUTH 模块 1-002-000-000 ========== + ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_002_000_000, "登录失败,账号密码不正确"); + ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "登录失败,账号被禁用"); + ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "验证码不正确,原因:{}"); + ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定"); + ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1_002_000_006, "Token 已经过期"); + ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在"); + + // ========== 菜单模块 1-002-001-000 ========== + ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单"); + ErrorCode MENU_PARENT_NOT_EXISTS = new ErrorCode(1_002_001_001, "父菜单不存在"); + ErrorCode MENU_PARENT_ERROR = new ErrorCode(1_002_001_002, "不能设置自己为父菜单"); + ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "菜单不存在"); + ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除"); + ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单"); + + // ========== 角色模块 1-002-002-000 ========== + ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在"); + ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1_002_002_001, "已经存在名为【{}】的角色"); + ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在编码为【{}】的角色"); + ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色"); + ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用"); + ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用"); + + // ========== 用户模块 1-002-003-000 ========== + ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在"); + ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "手机号已经存在"); + ErrorCode USER_EMAIL_EXISTS = new ErrorCode(1_002_003_002, "邮箱已经存在"); + ErrorCode USER_NOT_EXISTS = new ErrorCode(1_002_003_003, "用户不存在"); + ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_003_004, "导入用户数据不能为空!"); + ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1_002_003_005, "用户密码校验失败"); + ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "名字为【{}】的用户已被禁用"); + ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})!"); + + // ========== 部门模块 1-002-004-000 ========== + ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门"); + ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001,"父级部门不存在"); + ErrorCode DEPT_NOT_FOUND = new ErrorCode(1_002_004_002, "当前部门不存在"); + ErrorCode DEPT_EXITS_CHILDREN = new ErrorCode(1_002_004_003, "存在子部门,无法删除"); + ErrorCode DEPT_PARENT_ERROR = new ErrorCode(1_002_004_004, "不能设置自己为父部门"); + ErrorCode DEPT_EXISTS_USER = new ErrorCode(1_002_004_005, "部门中存在员工,无法删除"); + ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "部门({})不处于开启状态,不允许选择"); + ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "不能设置自己的子部门为父部门"); + + // ========== 岗位模块 1-002-005-000 ========== + ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "当前岗位不存在"); + ErrorCode POST_NOT_ENABLE = new ErrorCode(1_002_005_001, "岗位({}) 不处于开启状态,不允许选择"); + ErrorCode POST_NAME_DUPLICATE = new ErrorCode(1_002_005_002, "已经存在该名字的岗位"); + ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1_002_005_003, "已经存在该标识的岗位"); + + // ========== 字典类型 1-002-006-000 ========== + ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1_002_006_001, "当前字典类型不存在"); + ErrorCode DICT_TYPE_NOT_ENABLE = new ErrorCode(1_002_006_002, "字典类型不处于开启状态,不允许选择"); + ErrorCode DICT_TYPE_NAME_DUPLICATE = new ErrorCode(1_002_006_003, "已经存在该名字的字典类型"); + ErrorCode DICT_TYPE_TYPE_DUPLICATE = new ErrorCode(1_002_006_004, "已经存在该类型的字典类型"); + ErrorCode DICT_TYPE_HAS_CHILDREN = new ErrorCode(1_002_006_005, "无法删除,该字典类型还有字典数据"); + + // ========== 字典数据 1-002-007-000 ========== + ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1_002_007_001, "当前字典数据不存在"); + ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1_002_007_002, "字典数据({})不处于开启状态,不允许选择"); + ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1_002_007_003, "已经存在该值的字典数据"); + + // ========== 通知公告 1-002-008-000 ========== + ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在"); + + // ========== 短信渠道 1-002-011-000 ========== + ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在"); + ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择"); + ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板"); + + // ========== 短信模板 1-002-012-000 ========== + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在"); + ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板"); + ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "短信 API 模板调用失败,原因是:{}"); + ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "短信 API 模版无法使用,原因:审批中"); + ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "短信 API 模版无法使用,原因:审批不通过,{}"); + ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "短信 API 模版无法使用,原因:模版不存在"); + + // ========== 短信发送 1-002-013-000 ========== + ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在"); + ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "模板参数({})缺失"); + ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "短信模板不存在"); + + // ========== 短信验证码 1-002-014-000 ========== + ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在"); + ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1_002_014_001, "验证码已过期"); + ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用"); + ErrorCode SMS_CODE_NOT_CORRECT = new ErrorCode(1_002_014_003, "验证码不正确"); + ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量"); + ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁"); + ErrorCode SMS_CODE_IS_EXISTS = new ErrorCode(1_002_014_006, "手机号已被使用"); + ErrorCode SMS_CODE_IS_UNUSED = new ErrorCode(1_002_014_007, "验证码未被使用"); + + // ========== 租户信息 1-002-015-000 ========== + ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1_002_015_000, "租户不存在"); + ErrorCode TENANT_DISABLE = new ErrorCode(1_002_015_001, "名字为【{}】的租户已被禁用"); + ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的租户已过期"); + ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!"); + ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在"); + ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在"); + + // ========== 租户套餐 1-002-016-000 ========== + ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在"); + ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除"); + ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用"); + + // ========== 社交用户 1-002-018-000 ========== + ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); + ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); + + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); + ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_201, "社交客户端不存在"); + ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_202, "社交客户端已存在配置"); + + // ========== OAuth2 客户端 1-002-020-000 ========= + ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在"); + ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在"); + ErrorCode OAUTH2_CLIENT_DISABLE = new ErrorCode(1_002_020_002, "OAuth2 客户端已禁用"); + ErrorCode OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS = new ErrorCode(1_002_020_003, "不支持该授权类型"); + ErrorCode OAUTH2_CLIENT_SCOPE_OVER = new ErrorCode(1_002_020_004, "授权范围过大"); + ErrorCode OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH = new ErrorCode(1_002_020_005, "无效 redirect_uri: {}"); + ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1_002_020_006, "无效 client_secret: {}"); + + // ========== OAuth2 授权 1-002-021-000 ========= + ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1_002_021_000, "client_id 不匹配"); + ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1_002_021_001, "redirect_uri 不匹配"); + ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1_002_021_002, "state 不匹配"); + ErrorCode OAUTH2_GRANT_CODE_NOT_EXISTS = new ErrorCode(1_002_021_003, "code 不存在"); + + // ========== OAuth2 授权 1-002-022-000 ========= + ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1_002_022_000, "code 不存在"); + ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1_002_022_001, "code 已过期"); + + // ========== 邮箱账号 1-002-023-000 ========== + ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_023_000, "邮箱账号不存在"); + ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1_002_023_001, "无法删除,该邮箱账号还有邮件模板"); + + // ========== 邮件模版 1-002-024-000 ========== + ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_024_000, "邮件模版不存在"); + ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1_002_024_001, "邮件模版 code({}) 已存在"); + + // ========== 邮件发送 1-002-025-000 ========== + ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_025_000, "模板参数({})缺失"); + ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1_002_025_001, "邮箱不存在"); + + // ========== 站内信模版 1-002-026-000 ========== + ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_026_000, "站内信模版不存在"); + ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_026_001, "已经存在编码为【{}】的站内信模板"); + + // ========== 站内信模版 1-002-027-000 ========== + + // ========== 站内信发送 1-002-028-000 ========== + ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失"); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/LogRecordConstants.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/LogRecordConstants.java new file mode 100644 index 0000000..4ee3840 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/LogRecordConstants.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.enums; + +/** + * System 操作日志枚举 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串 + * + * @author 芋道源码 + */ +public interface LogRecordConstants { + + // ======================= SYSTEM_USER 用户 ======================= + + String SYSTEM_USER_TYPE = "SYSTEM 用户"; + String SYSTEM_USER_CREATE_SUB_TYPE = "创建用户"; + String SYSTEM_USER_CREATE_SUCCESS = "创建了用户【{{#user.nickname}}】"; + String SYSTEM_USER_UPDATE_SUB_TYPE = "更新用户"; + String SYSTEM_USER_UPDATE_SUCCESS = "更新了用户【{{#user.nickname}}】: {_DIFF{#updateReqVO}}"; + String SYSTEM_USER_DELETE_SUB_TYPE = "删除用户"; + String SYSTEM_USER_DELETE_SUCCESS = "删除了用户【{{#user.nickname}}】"; + String SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE = "重置用户密码"; + String SYSTEM_USER_UPDATE_PASSWORD_SUCCESS = "将用户【{{#user.nickname}}】的密码从【{{#user.password}}】重置为【{{#newPassword}}】"; + + // ======================= SYSTEM_ROLE 角色 ======================= + + String SYSTEM_ROLE_TYPE = "SYSTEM 角色"; + String SYSTEM_ROLE_CREATE_SUB_TYPE = "创建角色"; + String SYSTEM_ROLE_CREATE_SUCCESS = "创建了角色【{{#role.name}}】"; + String SYSTEM_ROLE_UPDATE_SUB_TYPE = "更新角色"; + String SYSTEM_ROLE_UPDATE_SUCCESS = "更新了角色【{{#role.name}}】: {_DIFF{#updateReqVO}}"; + String SYSTEM_ROLE_DELETE_SUB_TYPE = "删除角色"; + String SYSTEM_ROLE_DELETE_SUCCESS = "删除了角色【{{#role.name}}】"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/common/SexEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/common/SexEnum.java new file mode 100644 index 0000000..c1e222b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/common/SexEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.enums.common; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 性别的枚举值 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SexEnum { + + /** 男 */ + MALE(1), + /** 女 */ + FEMALE(2), + /* 未知 */ + UNKNOWN(0); + + /** + * 性别 + */ + private final Integer sex; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java new file mode 100644 index 0000000..4c51f91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginLogTypeEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录日志的类型枚举 + */ +@Getter +@AllArgsConstructor +public enum LoginLogTypeEnum { + + LOGIN_USERNAME(100), // 使用账号登录 + LOGIN_SOCIAL(101), // 使用社交登录 + LOGIN_MOBILE(103), // 使用手机登陆 + LOGIN_SMS(104), // 使用短信登陆 + + LOGOUT_SELF(200), // 自己主动登出 + LOGOUT_DELETE(202), // 强制退出 + ; + + /** + * 日志类型 + */ + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginResultEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginResultEnum.java new file mode 100644 index 0000000..afb92e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/logger/LoginResultEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.enums.logger; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录结果的枚举类 + */ +@Getter +@AllArgsConstructor +public enum LoginResultEnum { + + SUCCESS(0), // 成功 + BAD_CREDENTIALS(10), // 账号或密码不正确 + USER_DISABLED(20), // 用户被禁用 + CAPTCHA_NOT_FOUND(30), // 图片验证码不存在 + CAPTCHA_CODE_ERROR(31), // 图片验证码不正确 + + ; + + /** + * 结果 + */ + private final Integer result; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java new file mode 100644 index 0000000..7cb16ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/mail/MailSendStatusEnum.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.enums.mail; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邮件的发送状态枚举 + * + * @author wangjingyi + * @since 2022/4/10 13:39 + */ +@Getter +@AllArgsConstructor +public enum MailSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 + ; + + private final int status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notice/NoticeTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notice/NoticeTypeEnum.java new file mode 100644 index 0000000..9a2a3c4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notice/NoticeTypeEnum.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.enums.notice; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum NoticeTypeEnum { + + NOTICE(1), + ANNOUNCEMENT(2); + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java new file mode 100644 index 0000000..dccfb19 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.enums.notify; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知模板类型枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum NotifyTemplateTypeEnum { + + /** + * 系统消息 + */ + SYSTEM_MESSAGE(2), + /** + * 通知消息 + */ + NOTIFICATION_MESSAGE(1); + + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java new file mode 100644 index 0000000..a123d57 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.system.enums.oauth2; + +/** + * OAuth2.0 客户端的通用枚举 + * + * @author 芋道源码 + */ +public interface OAuth2ClientConstants { + + String CLIENT_ID_DEFAULT = "default"; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java new file mode 100644 index 0000000..0b09fe5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.enums.oauth2; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * OAuth2 授权类型(模式)的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum OAuth2GrantTypeEnum { + + PASSWORD("password"), // 密码模式 + AUTHORIZATION_CODE("authorization_code"), // 授权码模式 + IMPLICIT("implicit"), // 简化模式 + CLIENT_CREDENTIALS("client_credentials"), // 客户端模式 + REFRESH_TOKEN("refresh_token"), // 刷新模式 + ; + + private final String grantType; + + public static OAuth2GrantTypeEnum getByGrantType(String grantType) { + return ArrayUtil.firstMatch(o -> o.getGrantType().equals(grantType), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/DataScopeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/DataScopeEnum.java new file mode 100644 index 0000000..6b06b06 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/DataScopeEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.enums.permission; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 数据范围枚举类 + * + * 用于实现数据级别的权限 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum implements IntArrayValuable { + + ALL(1), // 全部数据权限 + + DEPT_CUSTOM(2), // 指定部门数据权限 + DEPT_ONLY(3), // 部门数据权限 + DEPT_AND_CHILD(4), // 部门及以下数据权限 + + SELF(5); // 仅本人数据权限 + + /** + * 范围 + */ + private final Integer scope; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DataScopeEnum::getScope).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/MenuTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/MenuTypeEnum.java new file mode 100644 index 0000000..575a33c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/MenuTypeEnum.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.enums.permission; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 菜单类型枚举类 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MenuTypeEnum { + + DIR(1), // 目录 + MENU(2), // 菜单 + BUTTON(3) // 按钮 + ; + + /** + * 类型 + */ + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java new file mode 100644 index 0000000..cdf9a00 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.enums.permission; + +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 角色标识枚举 + */ +@Getter +@AllArgsConstructor +public enum RoleCodeEnum { + + SUPER_ADMIN("super_admin", "超级管理员"), + TENANT_ADMIN("tenant_admin", "租户管理员"), + CRM_ADMIN("crm_admin", "CRM 管理员"); // CRM 系统专用 + ; + + /** + * 角色编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static boolean isSuperAdmin(String code) { + return ObjectUtils.equalsAny(code, SUPER_ADMIN.getCode()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleTypeEnum.java new file mode 100644 index 0000000..1607b20 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleTypeEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.enums.permission; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum RoleTypeEnum { + + /** + * 内置角色 + */ + SYSTEM(1), + /** + * 自定义角色 + */ + CUSTOM(2); + + private final Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsReceiveStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsReceiveStatusEnum.java new file mode 100644 index 0000000..581ee6f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsReceiveStatusEnum.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的接收状态枚举 + * + * @author 芋道源码 + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SmsReceiveStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 接收成功 + FAILURE(20), // 接收失败 + ; + + private final int status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java new file mode 100644 index 0000000..225685d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.system.enums.sms; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 用户短信验证码发送场景的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SmsSceneEnum implements IntArrayValuable { + + MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"), + MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"), + MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"), + MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"), + + ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SmsSceneEnum::getScene).toArray(); + + /** + * 验证场景的编号 + */ + private final Integer scene; + /** + * 模版编码 + */ + private final String templateCode; + /** + * 描述 + */ + private final String description; + + @Override + public int[] array() { + return ARRAYS; + } + + public static SmsSceneEnum getCodeByScene(Integer scene) { + return ArrayUtil.firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene), + values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSendStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSendStatusEnum.java new file mode 100644 index 0000000..307c9f6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSendStatusEnum.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的发送状态枚举 + * + * @author zzf + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SmsSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 + ; + + private final int status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsTemplateTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsTemplateTypeEnum.java new file mode 100644 index 0000000..d24b07a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsTemplateTypeEnum.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的模板类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SmsTemplateTypeEnum { + + VERIFICATION_CODE(1), // 验证码 + NOTICE(2), // 通知 + PROMOTION(3), // 营销 + ; + + /** + * 类型 + */ + private final int type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java new file mode 100644 index 0000000..602eb1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.system.enums.social; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 社交平台的类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SocialTypeEnum implements IntArrayValuable { + + /** + * Gitee + * + * @see 接入文档 + */ + GITEE(10, "GITEE"), + /** + * 钉钉 + * + * @see 接入文档 + */ + DINGTALK(20, "DINGTALK"), + + /** + * 企业微信 + * + * @see 接入文档 + */ + WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), + /** + * 微信公众平台 - 移动端 H5 + * + * @see 接入文档 + */ + WECHAT_MP(31, "WECHAT_MP"), + /** + * 微信开放平台 - 网站应用 PC 端扫码授权登录 + * + * @see 接入文档 + */ + WECHAT_OPEN(32, "WECHAT_OPEN"), + /** + * 微信小程序 + * + * @see 接入文档 + */ + WECHAT_MINI_APP(34, "WECHAT_MINI_APP"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SocialTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 类型的标识 + */ + private final String source; + + @Override + public int[] array() { + return ARRAYS; + } + + public static SocialTypeEnum valueOfType(Integer type) { + return ArrayUtil.firstMatch(o -> o.getType().equals(type), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/pom.xml b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/pom.xml new file mode 100644 index 0000000..6de1a58 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/pom.xml @@ -0,0 +1,132 @@ + + + + cn.iocoder.boot + yudao-module-system + ${revision} + + 4.0.0 + yudao-module-system-biz + jar + + ${project.artifactId} + + system 模块下,我们放通用业务,支撑上层的核心业务。 + 例如说:用户、部门、权限、数据字典等等 + + + + + cn.iocoder.boot + yudao-module-system-api + ${revision} + + + cn.iocoder.boot + yudao-module-infra-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-data-permission + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-validation + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-job + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + + + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + + + org.springframework.boot + spring-boot-starter-mail + + + + + com.xingyuv + spring-boot-starter-justauth + + + + com.github.binarywang + wx-java-mp-spring-boot-starter + + + com.github.binarywang + wx-java-miniapp-spring-boot-starter + + + + com.aliyun + aliyun-java-sdk-core + + + com.aliyun + aliyun-java-sdk-dysmsapi + + + com.tencentcloudapi + tencentcloud-sdk-java-sms + + + + com.xingyuv + spring-boot-starter-captcha-plus + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java new file mode 100644 index 0000000..b040a75 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.api.dept; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 部门 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class DeptApiImpl implements DeptApi { + + @Resource + private DeptService deptService; + + @Override + public DeptRespDTO getDept(Long id) { + DeptDO dept = deptService.getDept(id); + return BeanUtils.toBean(dept, DeptRespDTO.class); + } + + @Override + public List getDeptList(Collection ids) { + List depts = deptService.getDeptList(ids); + return BeanUtils.toBean(depts, DeptRespDTO.class); + } + + @Override + public void validateDeptList(Collection ids) { + deptService.validateDeptList(ids); + } + + @Override + public List getChildDeptList(Long id) { + List childDeptList = deptService.getChildDeptList(id); + return BeanUtils.toBean(childDeptList, DeptRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApiImpl.java new file mode 100644 index 0000000..e61b19e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApiImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.api.dept; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 岗位 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class PostApiImpl implements PostApi { + + @Resource + private PostService postService; + + @Override + public void validPostList(Collection ids) { + postService.validatePostList(ids); + } + + @Override + public List getPostList(Collection ids) { + List list = postService.getPostList(ids); + return BeanUtils.toBean(list, PostRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java new file mode 100644 index 0000000..aecaf80 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.api.dict; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import cn.iocoder.yudao.module.system.service.dict.DictDataService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; + +/** + * 字典数据 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class DictDataApiImpl implements DictDataApi { + + @Resource + private DictDataService dictDataService; + + @Override + public void validateDictDataList(String dictType, Collection values) { + dictDataService.validateDictDataList(dictType, values); + } + + @Override + public DictDataRespDTO getDictData(String dictType, String value) { + DictDataDO dictData = dictDataService.getDictData(dictType, value); + return BeanUtils.toBean(dictData, DictDataRespDTO.class); + } + + @Override + public DictDataRespDTO parseDictData(String dictType, String label) { + DictDataDO dictData = dictDataService.parseDictData(dictType, label); + return BeanUtils.toBean(dictData, DictDataRespDTO.class); + } + + @Override + public List getDictDataList(String dictType) { + List list = dictDataService.getDictDataListByDictType(dictType); + return BeanUtils.toBean(list, DictDataRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApiImpl.java new file mode 100644 index 0000000..b5f40e0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/LoginLogApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.api.logger; + +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.service.logger.LoginLogService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 登录日志的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class LoginLogApiImpl implements LoginLogApi { + + @Resource + private LoginLogService loginLogService; + + @Override + public void createLoginLog(LoginLogCreateReqDTO reqDTO) { + loginLogService.createLoginLog(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java new file mode 100644 index 0000000..fafded8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.api.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; +import cn.iocoder.yudao.module.system.service.logger.OperateLogService; +import com.fhs.core.trans.anno.TransMethodResult; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 操作日志 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class OperateLogApiImpl implements OperateLogApi { + + @Resource + private OperateLogService operateLogService; + + @Override + @Async + public void createOperateLog(OperateLogCreateReqDTO createReqDTO) { + operateLogService.createOperateLog(createReqDTO); + } + + @Override + @TransMethodResult + public PageResult getOperateLogPage(OperateLogPageReqDTO pageReqVO) { + PageResult operateLogPage = operateLogService.getOperateLogPage(pageReqVO); + return BeanUtils.toBean(operateLogPage, OperateLogRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java new file mode 100644 index 0000000..72d03af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.mail; + +import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleToUserReqDTO; +import cn.iocoder.yudao.module.system.service.mail.MailSendService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 邮件发送 API 实现类 + * + * @author wangjingyi + */ +@Service +@Validated +public class MailSendApiImpl implements MailSendApi { + + @Resource + private MailSendService mailSendService; + + @Override + public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) { + return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + + @Override + public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) { + return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java new file mode 100644 index 0000000..f1b0ae7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.api.notify; + +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; +import cn.iocoder.yudao.module.system.service.notify.NotifySendService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 站内信发送 API 实现类 + * + * @author xrcoder + */ +@Service +public class NotifyMessageSendApiImpl implements NotifyMessageSendApi { + + @Resource + private NotifySendService notifySendService; + + @Override + public Long sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) { + return notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + + @Override + public Long sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) { + return notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApiImpl.java new file mode 100644 index 0000000..be7eba3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/oauth2/OAuth2TokenApiImpl.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.api.oauth2; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO; +import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * OAuth2.0 Token API 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2TokenApiImpl implements OAuth2TokenApi { + + @Resource + private OAuth2TokenService oauth2TokenService; + + @Override + public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken( + reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes()); + return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class); + } + + @Override + public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken); + return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class); + } + + @Override + public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken); + return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class); + } + + @Override + public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId); + return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApiImpl.java new file mode 100644 index 0000000..2539343 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApiImpl.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.api.permission; + +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Set; + +/** + * 权限 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class PermissionApiImpl implements PermissionApi { + + @Resource + private PermissionService permissionService; + + @Override + public Set getUserRoleIdListByRoleIds(Collection roleIds) { + return permissionService.getUserRoleIdListByRoleId(roleIds); + } + + @Override + public boolean hasAnyPermissions(Long userId, String... permissions) { + return permissionService.hasAnyPermissions(userId, permissions); + } + + @Override + public boolean hasAnyRoles(Long userId, String... roles) { + return permissionService.hasAnyRoles(userId, roles); + } + + @Override + public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { + return permissionService.getDeptDataPermission(userId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java new file mode 100644 index 0000000..d8622a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.api.permission; + +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * 角色 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class RoleApiImpl implements RoleApi { + + @Resource + private RoleService roleService; + + @Override + public void validRoleList(Collection ids) { + roleService.validateRoleList(ids); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApiImpl.java new file mode 100644 index 0000000..23c5e4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApiImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.api.sms; + +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.service.sms.SmsCodeService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 短信验证码 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SmsCodeApiImpl implements SmsCodeApi { + + @Resource + private SmsCodeService smsCodeService; + + @Override + public void sendSmsCode(SmsCodeSendReqDTO reqDTO) { + smsCodeService.sendSmsCode(reqDTO); + } + + @Override + public void useSmsCode(SmsCodeUseReqDTO reqDTO) { + smsCodeService.useSmsCode(reqDTO); + } + + @Override + public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) { + smsCodeService.validateSmsCode(reqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApiImpl.java new file mode 100644 index 0000000..ee5812d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsSendApiImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.sms; + +import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import cn.iocoder.yudao.module.system.service.sms.SmsSendService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 短信发送 API 接口 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SmsSendApiImpl implements SmsSendApi { + + @Resource + private SmsSendService smsSendService; + + @Override + public Long sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) { + return smsSendService.sendSingleSmsToAdmin(reqDTO.getMobile(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + + @Override + public Long sendSingleSmsToMember(SmsSendSingleToUserReqDTO reqDTO) { + return smsSendService.sendSingleSmsToMember(reqDTO.getMobile(), reqDTO.getUserId(), + reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java new file mode 100644 index 0000000..e05251f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.system.api.social; + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; +import cn.iocoder.yudao.module.system.service.social.SocialClientService; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 社交应用的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SocialClientApiImpl implements SocialClientApi { + + @Resource + private SocialClientService socialClientService; + + @Override + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { + return socialClientService.getAuthorizeUrl(socialType, userType, redirectUri); + } + + @Override + public SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url) { + WxJsapiSignature signature = socialClientService.createWxMpJsapiSignature(userType, url); + return BeanUtils.toBean(signature, SocialWxJsapiSignatureRespDTO.class); + } + + @Override + public SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { + WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode); + return BeanUtils.toBean(info, SocialWxPhoneNumberInfoRespDTO.class); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java new file mode 100644 index 0000000..1892dbc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.api.social; + +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 社交用户的 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SocialUserApiImpl implements SocialUserApi { + + @Resource + private SocialUserService socialUserService; + + @Override + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { + return socialUserService.bindSocialUser(reqDTO); + } + + @Override + public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) { + socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(), + reqDTO.getSocialType(), reqDTO.getOpenid()); + } + + @Override + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { + return socialUserService.getSocialUserByUserId(userType, userId, socialType); + } + + @Override + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { + return socialUserService.getSocialUserByCode(userType, socialType, code, state); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java new file mode 100644 index 0000000..25ea260 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/tenant/TenantApiImpl.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.api.tenant; + +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 多租户的 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class TenantApiImpl implements TenantApi { + + @Resource + private TenantService tenantService; + + @Override + public List getTenantIdList() { + return tenantService.getTenantIdList(); + } + + @Override + public void validateTenant(Long id) { + tenantService.validTenant(id); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java new file mode 100644 index 0000000..373e088 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.system.api.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * Admin 用户 API 实现类 + * + * @author 芋道源码 + */ +@Service +public class AdminUserApiImpl implements AdminUserApi { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + + @Override + public AdminUserRespDTO getUser(Long id) { + AdminUserDO user = userService.getUser(id); + return BeanUtils.toBean(user, AdminUserRespDTO.class); + } + + @Override + public List getUserListBySubordinate(Long id) { + // 1.1 获取用户负责的部门 + AdminUserDO user = userService.getUser(id); + if (user == null) { + return Collections.emptyList(); + } + ArrayList deptIds = new ArrayList<>(); + DeptDO dept = deptService.getDept(user.getDeptId()); + if (dept == null) { + return Collections.emptyList(); + } + if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人 + return Collections.emptyList(); + } + deptIds.add(dept.getId()); + // 1.2 获取所有子部门 + List childDeptList = deptService.getChildDeptList(dept.getId()); + if (CollUtil.isNotEmpty(childDeptList)) { + deptIds.addAll(convertSet(childDeptList, DeptDO::getId)); + } + + // 2. 获取部门对应的用户信息 + List users = userService.getUserListByDeptIds(deptIds); + users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己 + return BeanUtils.toBean(users, AdminUserRespDTO.class); + } + + @Override + public List getUserList(Collection ids) { + List users = userService.getUserList(ids); + return BeanUtils.toBean(users, AdminUserRespDTO.class); + } + + @Override + public List getUserListByDeptIds(Collection deptIds) { + List users = userService.getUserListByDeptIds(deptIds); + return BeanUtils.toBean(users, AdminUserRespDTO.class); + } + + @Override + public List getUserListByPostIds(Collection postIds) { + List users = userService.getUserListByPostIds(postIds); + return BeanUtils.toBean(users, AdminUserRespDTO.class); + } + + @Override + public void validateUserList(Collection ids) { + userService.validateUserList(ids); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http new file mode 100644 index 0000000..00ae2ba --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http @@ -0,0 +1,33 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/system/auth/login +Content-Type: application/json +tenant-id: {{adminTenentId}} +tag: Yunai.local + +{ + "username": "admin", + "password": "admin123", + "uuid": "3acd87a09a4f48fb9118333780e94883", + "code": "1024" +} + +### 请求 /login 接口 => 成功(无验证码) +POST {{baseUrl}}/system/auth/login +Content-Type: application/json +tenant-id: {{adminTenentId}} + +{ + "username": "admin", + "password": "admin123" +} + +### 请求 /get-permission-info 接口 => 成功 +GET {{baseUrl}}/system/auth/get-permission-info +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /list-menus 接口 => 成功 +GET {{baseUrl}}/system/list-menus +Authorization: Bearer {{token}} +#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java new file mode 100644 index 0000000..2128ebe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -0,0 +1,157 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; +import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import cn.iocoder.yudao.module.system.service.permission.MenuService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import cn.iocoder.yudao.module.system.service.social.SocialClientService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 认证") +@RestController +@RequestMapping("/system/auth") +@Validated +@Slf4j +public class AuthController { + + @Resource + private AdminAuthService authService; + @Resource + private AdminUserService userService; + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private PermissionService permissionService; + @Resource + private SocialClientService socialClientService; + + @Resource + private SecurityProperties securityProperties; + + @PostMapping("/login") + @PermitAll + @Operation(summary = "使用账号密码登录") + public CommonResult login(@RequestBody @Valid AuthLoginReqVO reqVO) { + return success(authService.login(reqVO)); + } + + @PostMapping("/logout") + @PermitAll + @Operation(summary = "登出系统") + public CommonResult logout(HttpServletRequest request) { + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); + if (StrUtil.isNotBlank(token)) { + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); + } + return success(true); + } + + @PostMapping("/refresh-token") + @PermitAll + @Operation(summary = "刷新令牌") + @Parameter(name = "refreshToken", description = "刷新令牌", required = true) + public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { + return success(authService.refreshToken(refreshToken)); + } + + @GetMapping("/get-permission-info") + @Operation(summary = "获取登录用户的权限信息") + public CommonResult getPermissionInfo() { + // 1.1 获得用户信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + if (user == null) { + return success(null); + } + + // 1.2 获得角色列表 + Set roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + if (CollUtil.isEmpty(roleIds)) { + return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); + } + List roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + + // 1.3 获得菜单列表 + Set menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); + List menuList = menuService.getMenuList(menuIds); + menuList = menuService.filterDisableMenus(menuList); + + // 2. 拼接结果返回 + return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); + } + + // ========== 短信登录相关 ========== + + @PostMapping("/sms-login") + @PermitAll + @Operation(summary = "使用短信验证码登录") + public CommonResult smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) { + return success(authService.smsLogin(reqVO)); + } + + @PostMapping("/send-sms-code") + @PermitAll + @Operation(summary = "发送手机验证码") + public CommonResult sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) { + authService.sendSmsCode(reqVO); + return success(true); + } + + // ========== 社交登录相关 ========== + + @GetMapping("/social-auth-redirect") + @PermitAll + @Operation(summary = "社交授权的跳转") + @Parameters({ + @Parameter(name = "type", description = "社交类型", required = true), + @Parameter(name = "redirectUri", description = "回调路径") + }) + public CommonResult socialLogin(@RequestParam("type") Integer type, + @RequestParam("redirectUri") String redirectUri) { + return success(socialClientService.getAuthorizeUrl( + type, UserTypeEnum.ADMIN.getValue(), redirectUri)); + } + + @PostMapping("/social-login") + @PermitAll + @Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户") + public CommonResult socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { + return success(authService.socialLogin(reqVO)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java new file mode 100644 index 0000000..2009a9e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Schema(description = "管理后台 - 账号密码登录 Request VO,如果登录并绑定社交用户,需要传递 social 开头的参数") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginReqVO { + + @Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "登录账号不能为空") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + // ========== 图片验证码相关 ========== + + @Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED, + example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==") + @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) + private String captchaVerification; + + // ========== 绑定社交登录时,需要传递如下参数 ========== + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String socialCode; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + private String socialState; + + /** + * 开启验证码的 Group + */ + public interface CodeEnableGroup {} + + @AssertTrue(message = "授权码不能为空") + public boolean isSocialCodeValid() { + return socialType == null || StrUtil.isNotEmpty(socialCode); + } + + @AssertTrue(message = "授权 state 不能为空") + public boolean isSocialState() { + return socialType == null || StrUtil.isNotEmpty(socialState); + } + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java new file mode 100644 index 0000000..1720d07 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 登录 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthLoginRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + private String refreshToken; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java new file mode 100644 index 0000000..d310bde --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthMenuRespVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthMenuRespVO { + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private Long id; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + private String path; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + /** + * 子路由 + */ + private List children; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java new file mode 100644 index 0000000..c26acb8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Set; + +@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthPermissionInfoRespVO { + + @Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED) + private UserVO user; + + @Schema(description = "角色标识数组", requiredMode = Schema.RequiredMode.REQUIRED) + private Set roles; + + @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED) + private Set permissions; + + @Schema(description = "菜单树", requiredMode = Schema.RequiredMode.REQUIRED) + private List menus; + + @Schema(description = "用户信息 VO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class UserVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String nickname; + + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg") + private String avatar; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private Long deptId; + + } + + @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO") + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class MenuVO { + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private Long id; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + private String path; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + /** + * 子路由 + */ + private List children; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java new file mode 100644 index 0000000..51aba67 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 短信验证码的登录 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsLoginReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "短信验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "验证码不能为空") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java new file mode 100644 index 0000000..18bdc81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsSendReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 发送手机验证码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSmsSendReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma") + @NotEmpty(message = "手机号不能为空") + @Mobile + private String mobile; + + @Schema(description = "短信场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java new file mode 100644 index 0000000..1bbb67e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 社交绑定登录 Request VO,使用 code 授权码 + 账号密码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthSocialLoginReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java new file mode 100644 index 0000000..f2c7141 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.captcha; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; + +@Tag(name = "管理后台 - 验证码") +@RestController("adminCaptchaController") +@RequestMapping("/system/captcha") +public class CaptchaController { + + @Resource + private CaptchaService captchaService; + + @PostMapping({"/get"}) + @Operation(summary = "获得验证码") + @PermitAll + public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) { + assert request.getRemoteHost() != null; + data.setBrowserInfo(getRemoteId(request)); + return captchaService.get(data); + } + + @PostMapping("/check") + @Operation(summary = "校验验证码") + @PermitAll + public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) { + data.setBrowserInfo(getRemoteId(request)); + return captchaService.check(data); + } + + public static String getRemoteId(HttpServletRequest request) { + String ip = ServletUtils.getClientIP(request); + String ua = request.getHeader("user-agent"); + if (StrUtil.isNotBlank(ip)) { + return ip + ua; + } + return request.getRemoteAddr() + ua; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java new file mode 100644 index 0000000..86cdeed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 部门") +@RestController +@RequestMapping("/system/dept") +@Validated +public class DeptController { + + @Resource + private DeptService deptService; + + @PostMapping("create") + @Operation(summary = "创建部门") + @PreAuthorize("@ss.hasPermission('system:dept:create')") + public CommonResult createDept(@Valid @RequestBody DeptSaveReqVO createReqVO) { + Long deptId = deptService.createDept(createReqVO); + return success(deptId); + } + + @PutMapping("update") + @Operation(summary = "更新部门") + @PreAuthorize("@ss.hasPermission('system:dept:update')") + public CommonResult updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) { + deptService.updateDept(updateReqVO); + return success(true); + } + + @DeleteMapping("delete") + @Operation(summary = "删除部门") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dept:delete')") + public CommonResult deleteDept(@RequestParam("id") Long id) { + deptService.deleteDept(id); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获取部门列表") + @PreAuthorize("@ss.hasPermission('system:dept:query')") + public CommonResult> getDeptList(DeptListReqVO reqVO) { + List list = deptService.getDeptList(reqVO); + return success(BeanUtils.toBean(list, DeptRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项") + public CommonResult> getSimpleDeptList() { + List list = deptService.getDeptList( + new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + return success(BeanUtils.toBean(list, DeptSimpleRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得部门信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dept:query')") + public CommonResult getDept(@RequestParam("id") Long id) { + DeptDO dept = deptService.getDept(id); + return success(BeanUtils.toBean(dept, DeptRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java new file mode 100644 index 0000000..6c4a3a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 岗位") +@RestController +@RequestMapping("/system/post") +@Validated +public class PostController { + + @Resource + private PostService postService; + + @PostMapping("/create") + @Operation(summary = "创建岗位") + @PreAuthorize("@ss.hasPermission('system:post:create')") + public CommonResult createPost(@Valid @RequestBody PostSaveReqVO createReqVO) { + Long postId = postService.createPost(createReqVO); + return success(postId); + } + + @PutMapping("/update") + @Operation(summary = "修改岗位") + @PreAuthorize("@ss.hasPermission('system:post:update')") + public CommonResult updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) { + postService.updatePost(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除岗位") + @PreAuthorize("@ss.hasPermission('system:post:delete')") + public CommonResult deletePost(@RequestParam("id") Long id) { + postService.deletePost(id); + return success(true); + } + + @GetMapping(value = "/get") + @Operation(summary = "获得岗位信息") + @Parameter(name = "id", description = "岗位编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:post:query')") + public CommonResult getPost(@RequestParam("id") Long id) { + PostDO post = postService.getPost(id); + return success(BeanUtils.toBean(post, PostRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项") + public CommonResult> getSimplePostList() { + // 获得岗位列表,只要开启状态的 + List list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus())); + // 排序后,返回给前端 + list.sort(Comparator.comparing(PostDO::getSort)); + return success(BeanUtils.toBean(list, PostSimpleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得岗位分页列表") + @PreAuthorize("@ss.hasPermission('system:post:query')") + public CommonResult> getPostPage(@Validated PostPageReqVO pageReqVO) { + PageResult pageResult = postService.getPostPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, PostRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "岗位管理") + @PreAuthorize("@ss.hasPermission('system:post:export')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = postService.getPostPage(reqVO).getList(); + // 输出 + ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class, + BeanUtils.toBean(list, PostRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java new file mode 100644 index 0000000..131686f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 部门列表 Request VO") +@Data +public class DeptListReqVO { + + @Schema(description = "部门名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java new file mode 100644 index 0000000..83e6ed0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 部门信息 Response VO") +@Data +public class DeptRespVO { + + @Schema(description = "部门编号", example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父部门 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer sort; + + @Schema(description = "负责人的用户编号", example = "2048") + private Long leaderUserId; + + @Schema(description = "联系电话", example = "15601691000") + private String phone; + + @Schema(description = "邮箱", example = "yudao@iocoder.cn") + private String email; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java new file mode 100644 index 0000000..0d6276f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 部门创建/修改 Request VO") +@Data +public class DeptSaveReqVO { + + @Schema(description = "部门编号", example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "部门名称不能为空") + @Size(max = 30, message = "部门名称长度不能超过 30 个字符") + private String name; + + @Schema(description = "父部门 ID", example = "1024") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "负责人的用户编号", example = "2048") + private Long leaderUserId; + + @Schema(description = "联系电话", example = "15601691000") + @Size(max = 11, message = "联系电话长度不能超过11个字符") + private String phone; + + @Schema(description = "邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java new file mode 100644 index 0000000..31c15d5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 部门精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeptSimpleRespVO { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostPageReqVO.java new file mode 100644 index 0000000..78f306e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostPageReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 岗位分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class PostPageReqVO extends PageParam { + + @Schema(description = "岗位编码,模糊匹配", example = "yudao") + private String code; + + @Schema(description = "岗位名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostRespVO.java new file mode 100644 index 0000000..dde6f95 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 岗位信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class PostRespVO { + + @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位序号") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @ExcelProperty("岗位名称") + private String name; + + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("岗位编码") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位排序") + private Integer sort; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSaveReqVO.java new file mode 100644 index 0000000..daafe9e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 岗位创建/修改 Request VO") +@Data +public class PostSaveReqVO { + + @Schema(description = "岗位编号", example = "1024") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @NotBlank(message = "岗位名称不能为空") + @Size(max = 50, message = "岗位名称长度不能超过 50 个字符") + private String name; + + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotBlank(message = "岗位编码不能为空") + @Size(max = 64, message = "岗位编码长度不能超过64个字符") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + +} \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSimpleRespVO.java new file mode 100644 index 0000000..72852a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 岗位信息的精简 Response VO") +@Data +public class PostSimpleRespVO { + + @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("岗位序号") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆") + @ExcelProperty("岗位名称") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.http new file mode 100644 index 0000000..f524315 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.http @@ -0,0 +1,4 @@ +### 请求 /menu/list 接口 => 成功 +GET {{baseUrl}}/system/dict-data/list-all-simple +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java new file mode 100644 index 0000000..d7402a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import cn.iocoder.yudao.module.system.service.dict.DictDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 字典数据") +@RestController +@RequestMapping("/system/dict-data") +@Validated +public class DictDataController { + + @Resource + private DictDataService dictDataService; + + @PostMapping("/create") + @Operation(summary = "新增字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:create')") + public CommonResult createDictData(@Valid @RequestBody DictDataSaveReqVO createReqVO) { + Long dictDataId = dictDataService.createDictData(createReqVO); + return success(dictDataId); + } + + @PutMapping("/update") + @Operation(summary = "修改字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:update')") + public CommonResult updateDictData(@Valid @RequestBody DictDataSaveReqVO updateReqVO) { + dictDataService.updateDictData(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除字典数据") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:delete')") + public CommonResult deleteDictData(Long id) { + dictDataService.deleteDictData(id); + return success(true); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地") + // 无需添加权限认证,因为前端全局都需要 + public CommonResult> getSimpleDictDataList() { + List list = dictDataService.getDictDataList( + CommonStatusEnum.ENABLE.getStatus(), null); + return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "/获得字典类型的分页列表") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult> getDictTypePage(@Valid DictDataPageReqVO pageReqVO) { + PageResult pageResult = dictDataService.getDictDataPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DictDataRespVO.class)); + } + + @GetMapping(value = "/get") + @Operation(summary = "/查询字典数据详细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult getDictData(@RequestParam("id") Long id) { + DictDataDO dictData = dictDataService.getDictData(id); + return success(BeanUtils.toBean(dictData, DictDataRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "导出字典数据") + @PreAuthorize("@ss.hasPermission('system:dict:export')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Valid DictDataPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = dictDataService.getDictDataPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "字典数据.xls", "数据", DictDataRespVO.class, + BeanUtils.toBean(list, DictDataRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java new file mode 100644 index 0000000..65f8e7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import cn.iocoder.yudao.module.system.service.dict.DictTypeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 字典类型") +@RestController +@RequestMapping("/system/dict-type") +@Validated +public class DictTypeController { + + @Resource + private DictTypeService dictTypeService; + + @PostMapping("/create") + @Operation(summary = "创建字典类型") + @PreAuthorize("@ss.hasPermission('system:dict:create')") + public CommonResult createDictType(@Valid @RequestBody DictTypeSaveReqVO createReqVO) { + Long dictTypeId = dictTypeService.createDictType(createReqVO); + return success(dictTypeId); + } + + @PutMapping("/update") + @Operation(summary = "修改字典类型") + @PreAuthorize("@ss.hasPermission('system:dict:update')") + public CommonResult updateDictType(@Valid @RequestBody DictTypeSaveReqVO updateReqVO) { + dictTypeService.updateDictType(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除字典类型") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:dict:delete')") + public CommonResult deleteDictType(Long id) { + dictTypeService.deleteDictType(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得字典类型的分页列表") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult> pageDictTypes(@Valid DictTypePageReqVO pageReqVO) { + PageResult pageResult = dictTypeService.getDictTypePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DictTypeRespVO.class)); + } + + @Operation(summary = "/查询字典类型详细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @GetMapping(value = "/get") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + public CommonResult getDictType(@RequestParam("id") Long id) { + DictTypeDO dictType = dictTypeService.getDictType(id); + return success(BeanUtils.toBean(dictType, DictTypeRespVO.class)); + } + + @GetMapping(value = {"/list-all-simple", "simple-list"}) + @Operation(summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项") + // 无需添加权限认证,因为前端全局都需要 + public CommonResult> getSimpleDictTypeList() { + List list = dictTypeService.getDictTypeList(); + return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class)); + } + + @Operation(summary = "导出数据类型") + @GetMapping("/export") + @PreAuthorize("@ss.hasPermission('system:dict:query')") + @ApiAccessLog(operateType = EXPORT) + public void export(HttpServletResponse response, @Valid DictTypePageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = dictTypeService.getDictTypePage(exportReqVO).getList(); + // 导出 + ExcelUtils.write(response, "字典类型.xls", "数据", DictTypeRespVO.class, + BeanUtils.toBean(list, DictTypeRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataPageReqVO.java new file mode 100644 index 0000000..d9bd14a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataPageReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 字典类型分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class DictDataPageReqVO extends PageParam { + + @Schema(description = "字典标签", example = "芋道") + @Size(max = 100, message = "字典标签长度不能超过100个字符") + private String label; + + @Schema(description = "字典类型,模糊匹配", example = "sys_common_sex") + @Size(max = 100, message = "字典类型类型长度不能超过100个字符") + private String dictType; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataRespVO.java new file mode 100644 index 0000000..8857a70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataRespVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 字典数据信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DictDataRespVO { + + @Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典编码") + private Long id; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典排序") + private Integer sort; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @ExcelProperty("字典标签") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + @ExcelProperty("字典键值") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @ExcelProperty("字典类型") + private String dictType; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java new file mode 100644 index 0000000..480475f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSaveReqVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 字典数据创建/修改 Request VO") +@Data +public class DictDataSaveReqVO { + + @Schema(description = "字典数据编号", example = "1024") + private Long id; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "字典标签不能为空") + @Size(max = 100, message = "字典标签长度不能超过100个字符") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + @NotBlank(message = "字典键值不能为空") + @Size(max = 100, message = "字典键值长度不能超过100个字符") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @NotBlank(message = "字典类型不能为空") + @Size(max = 100, message = "字典类型长度不能超过100个字符") + private String dictType; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java new file mode 100644 index 0000000..d1497c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/data/DictDataSimpleRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 数据字典精简 Response VO") +@Data +public class DictDataSimpleRespVO { + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "gender") + private String dictType; + + @Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String value; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "男") + private String label; + + @Schema(description = "颜色类型,default、primary、success、info、warning、danger", example = "default") + private String colorType; + + @Schema(description = "css 样式", example = "btn-visible") + private String cssClass; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java new file mode 100644 index 0000000..80fde2e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 字典类型分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class DictTypePageReqVO extends PageParam { + + @Schema(description = "字典类型名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "字典类型,模糊匹配", example = "sys_common_sex") + @Size(max = 100, message = "字典类型类型长度不能超过100个字符") + private String type; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeRespVO.java new file mode 100644 index 0000000..6ddd47b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeRespVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 字典类型信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DictTypeRespVO { + + @Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("字典主键") + private Long id; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别") + @ExcelProperty("字典名称") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @ExcelProperty("字典类型") + private String type; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java new file mode 100644 index 0000000..c506c08 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 字典类型创建/修改 Request VO") +@Data +public class DictTypeSaveReqVO { + + @Schema(description = "字典类型编号", example = "1024") + private Long id; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "性别") + @NotBlank(message = "字典名称不能为空") + @Size(max = 100, message = "字典类型名称长度不能超过100个字符") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + @NotNull(message = "字典类型不能为空") + @Size(max = 100, message = "字典类型类型长度不能超过 100 个字符") + private String type; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "快乐的备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java new file mode 100644 index 0000000..f3e717d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.dict.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 字典类型精简信息 Response VO") +@Data +public class DictTypeSimpleRespVO { + + @Schema(description = "字典类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "字典类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + private String type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http new file mode 100644 index 0000000..f1b893d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http @@ -0,0 +1,5 @@ +### 获得地区树 +GET {{baseUrl}}/system/area/tree +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java new file mode 100644 index 0000000..b2f95d6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.controller.admin.ip; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.framework.ip.core.utils.IPUtils; +import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 地区") +@RestController +@RequestMapping("/system/area") +@Validated +public class AreaController { + + @GetMapping("/tree") + @Operation(summary = "获得地区树") + public CommonResult> getAreaTree() { + Area area = AreaUtils.getArea(Area.ID_CHINA); + Assert.notNull(area, "获取不到中国"); + return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class)); + } + + @GetMapping("/get-by-ip") + @Operation(summary = "获得 IP 对应的地区名") + @Parameter(name = "ip", description = "IP", required = true) + public CommonResult getAreaByIp(@RequestParam("ip") String ip) { + // 获得城市 + Area area = IPUtils.getArea(ip); + if (area == null) { + return success("未知"); + } + // 格式化返回 + return success(AreaUtils.format(area.getId())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java new file mode 100644 index 0000000..1360ec6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.ip.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 地区节点 Response VO") +@Data +public class AreaNodeRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京") + private String name; + + /** + * 子节点 + */ + private List children; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java new file mode 100644 index 0000000..9fa4dc1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; +import cn.iocoder.yudao.module.system.service.logger.LoginLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 登录日志") +@RestController +@RequestMapping("/system/login-log") +@Validated +public class LoginLogController { + + @Resource + private LoginLogService loginLogService; + + @GetMapping("/page") + @Operation(summary = "获得登录日志分页列表") + @PreAuthorize("@ss.hasPermission('system:login-log:query')") + public CommonResult> getLoginLogPage(@Valid LoginLogPageReqVO pageReqVO) { + PageResult pageResult = loginLogService.getLoginLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, LoginLogRespVO.class)); + } + + @GetMapping("/export") + @Operation(summary = "导出登录日志 Excel") + @PreAuthorize("@ss.hasPermission('system:login-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportLoginLog(HttpServletResponse response, @Valid LoginLogPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = loginLogService.getLoginLogPage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "登录日志.xls", "数据列表", LoginLogRespVO.class, + BeanUtils.toBean(list, LoginLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.http new file mode 100644 index 0000000..4853581 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.http @@ -0,0 +1,4 @@ +### 请求 /system/operate-log/page 接口 => 成功 +GET {{baseUrl}}/system/operate-log/page +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java new file mode 100644 index 0000000..e926f0b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.translate.core.TranslateUtils; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; +import cn.iocoder.yudao.module.system.service.logger.OperateLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 操作日志") +@RestController +@RequestMapping("/system/operate-log") +@Validated +public class OperateLogController { + + @Resource + private OperateLogService operateLogService; + + @GetMapping("/page") + @Operation(summary = "查看操作日志分页列表") + @PreAuthorize("@ss.hasPermission('system:operate-log:query')") + public CommonResult> pageOperateLog(@Valid OperateLogPageReqVO pageReqVO) { + PageResult pageResult = operateLogService.getOperateLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, OperateLogRespVO.class)); + } + + @Operation(summary = "导出操作日志") + @GetMapping("/export") + @PreAuthorize("@ss.hasPermission('system:operate-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = operateLogService.getOperateLogPage(exportReqVO).getList(); + ExcelUtils.write(response, "操作日志.xls", "数据列表", OperateLogRespVO.class, + TranslateUtils.translate(BeanUtils.toBean(list, OperateLogRespVO.class))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java new file mode 100644 index 0000000..40e12a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 登录日志分页列表 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class LoginLogPageReqVO extends PageParam { + + @Schema(description = "用户 IP,模拟匹配", example = "127.0.0.1") + private String userIp; + + @Schema(description = "用户账号,模拟匹配", example = "芋道") + private String username; + + @Schema(description = "操作状态", example = "true") + private Boolean status; + + @Schema(description = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java new file mode 100644 index 0000000..7b9cd16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 登录日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class LoginLogRespVO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志主键") + private Long id; + + @Schema(description = "日志类型,参见 LoginLogTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "日志类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.LOGIN_TYPE) + private Integer logType; + + @Schema(description = "用户编号", example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("用户账号") + private String username; + + @Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "登录结果", converter = DictConvert.class) + @DictFormat(DictTypeConstants.LOGIN_RESULT) + private Integer result; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + @ExcelProperty("登录 IP") + private String userIp; + + @Schema(description = "浏览器 UserAgent", example = "Mozilla/5.0") + @ExcelProperty("浏览器 UA") + private String userAgent; + + @Schema(description = "登录时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("登录时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java new file mode 100644 index 0000000..1061f6d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 操作日志分页列表 Request VO") +@Data +public class OperateLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "芋道") + private Long userId; + + @Schema(description = "操作模块业务编号", example = "1") + private Long bizId; + + @Schema(description = "操作模块,模拟匹配", example = "订单") + private String type; + + @Schema(description = "操作名,模拟匹配", example = "创建订单") + private String subType; + + @Schema(description = "操作明细,模拟匹配", example = "修改编号为 1 的用户信息") + private String action; + + @Schema(description = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java new file mode 100644 index 0000000..d8839b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogRespVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog; + +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 操作日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class OperateLogRespVO implements VO { + + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("日志编号") + private Long id; + + @Schema(description = "链路追踪编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "89aca178-a370-411c-ae02-3f0d672be4ab") + private String traceId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Trans(type = TransType.SIMPLE, target = AdminUserDO.class, fields = "nickname", ref = "userName") + private Long userId; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("操作人") + private String userName; + + @Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单") + @ExcelProperty("操作模块类型") + private String type; + + @Schema(description = "操作名", requiredMode = Schema.RequiredMode.REQUIRED, example = "创建订单") + @ExcelProperty("操作名") + private String subType; + + @Schema(description = "操作模块业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("操作模块业务编号") + private Long bizId; + + @Schema(description = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。") + private String action; + + @Schema(description = "拓展字段", example = "{'orderId': 1}") + private String extra; + + @Schema(description = "请求方法名", requiredMode = Schema.RequiredMode.REQUIRED, example = "GET") + @NotEmpty(message = "请求方法名不能为空") + private String requestMethod; + + @Schema(description = "请求地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "/xxx/yyy") + private String requestUrl; + + @Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1") + private String userIp; + + @Schema(description = "浏览器 UserAgent", requiredMode = Schema.RequiredMode.REQUIRED, example = "Mozilla/5.0") + private String userAgent; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java new file mode 100644 index 0000000..2e3a732 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail; + + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountRespVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.service.mail.MailAccountService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 邮箱账号") +@RestController +@RequestMapping("/system/mail-account") +public class MailAccountController { + + @Resource + private MailAccountService mailAccountService; + + @PostMapping("/create") + @Operation(summary = "创建邮箱账号") + @PreAuthorize("@ss.hasPermission('system:mail-account:create')") + public CommonResult createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) { + return success(mailAccountService.createMailAccount(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改邮箱账号") + @PreAuthorize("@ss.hasPermission('system:mail-account:update')") + public CommonResult updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) { + mailAccountService.updateMailAccount(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除邮箱账号") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:mail-account:delete')") + public CommonResult deleteMailAccount(@RequestParam Long id) { + mailAccountService.deleteMailAccount(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得邮箱账号") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-account:query')") + public CommonResult getMailAccount(@RequestParam("id") Long id) { + MailAccountDO account = mailAccountService.getMailAccount(id); + return success(BeanUtils.toBean(account, MailAccountRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得邮箱账号分页") + @PreAuthorize("@ss.hasPermission('system:mail-account:query')") + public CommonResult> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) { + PageResult pageResult = mailAccountService.getMailAccountPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获得邮箱账号精简列表") + public CommonResult> getSimpleMailAccountList() { + List list = mailAccountService.getMailAccountList(); + return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailLogController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailLogController.java new file mode 100644 index 0000000..c2669ec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailLogController.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.service.mail.MailLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 邮件日志") +@RestController +@RequestMapping("/system/mail-log") +public class MailLogController { + + @Resource + private MailLogService mailLogService; + + @GetMapping("/page") + @Operation(summary = "获得邮箱日志分页") + @PreAuthorize("@ss.hasPermission('system:mail-log:query')") + public CommonResult> getMailLogPage(@Valid MailLogPageReqVO pageVO) { + PageResult pageResult = mailLogService.getMailLogPage(pageVO); + return success(BeanUtils.toBean(pageResult, MailLogRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得邮箱日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-log:query')") + public CommonResult getMailTemplate(@RequestParam("id") Long id) { + MailLogDO log = mailLogService.getMailLog(id); + return success(BeanUtils.toBean(log, MailLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.http new file mode 100644 index 0000000..f3c47f5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.http @@ -0,0 +1,14 @@ +### 请求 /system/mail-template/send-mail 接口 => 成功 +POST {{baseUrl}}/system/mail-template/send-mail +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenentId}} + +{ + "templateCode": "test_01", + "mail": "7685413@qq.com", + "templateParams": { + "key01": "value01", + "key02": "value02" + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java new file mode 100644 index 0000000..00ab378 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.*; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.service.mail.MailSendService; +import cn.iocoder.yudao.module.system.service.mail.MailTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 邮件模版") +@RestController +@RequestMapping("/system/mail-template") +public class MailTemplateController { + + @Resource + private MailTemplateService mailTempleService; + @Resource + private MailSendService mailSendService; + + @PostMapping("/create") + @Operation(summary = "创建邮件模版") + @PreAuthorize("@ss.hasPermission('system:mail-template:create')") + public CommonResult createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){ + return success(mailTempleService.createMailTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改邮件模版") + @PreAuthorize("@ss.hasPermission('system:mail-template:update')") + public CommonResult updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){ + mailTempleService.updateMailTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除邮件模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-template:delete')") + public CommonResult deleteMailTemplate(@RequestParam("id") Long id) { + mailTempleService.deleteMailTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得邮件模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:mail-template:query')") + public CommonResult getMailTemplate(@RequestParam("id") Long id) { + MailTemplateDO template = mailTempleService.getMailTemplate(id); + return success(BeanUtils.toBean(template, MailTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得邮件模版分页") + @PreAuthorize("@ss.hasPermission('system:mail-template:query')") + public CommonResult> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) { + PageResult pageResult = mailTempleService.getMailTemplatePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获得邮件模版精简列表") + public CommonResult> getSimpleTemplateList() { + List list = mailTempleService.getMailTemplateList(); + return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class)); + } + + @PostMapping("/send-mail") + @Operation(summary = "发送短信") + @PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')") + public CommonResult sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) { + return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), getLoginUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java new file mode 100644 index 0000000..9de195d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 邮箱账号分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailAccountPageReqVO extends PageParam { + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + private String mail; + + @Schema(description = "用户名" , requiredMode = Schema.RequiredMode.REQUIRED , example = "yudao") + private String username; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java new file mode 100644 index 0000000..15232b2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 邮箱账号 Response VO") +@Data +public class MailAccountRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + private String mail; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String password; + + @Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn") + private String host; + + @Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + private Integer port; + + @Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean sslEnable; + + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean starttlsEnable; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java new file mode 100644 index 0000000..2cc232a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 邮箱账号创建/修改 Request VO") +@Data +public class MailAccountSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma@123.com") + @NotNull(message = "邮箱不能为空") + @Email(message = "必须是 Email 格式") + private String mail; + + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "用户名不能为空") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "密码必填") + private String password; + + @Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn") + @NotNull(message = "SMTP 服务器域名不能为空") + private String host; + + @Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + @NotNull(message = "SMTP 服务器端口不能为空") + private Integer port; + + @Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启 ssl 必填") + private Boolean sslEnable; + + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启 starttls 必填") + private Boolean starttlsEnable; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java new file mode 100644 index 0000000..0600633 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.account; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 邮箱账号的精简 Response VO") +@Data +public class MailAccountSimpleRespVO { + + @Schema(description = "邮箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "768541388@qq.com") + private String mail; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java new file mode 100644 index 0000000..5b3ad72 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.log; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 邮箱日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "30883") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2") + private Integer userType; + + @Schema(description = "接收邮箱地址,模糊匹配", example = "76854@qq.com") + private String toMail; + + @Schema(description = "邮箱账号编号", example = "18107") + private Long accountId; + + @Schema(description = "模板编号", example = "5678") + private Long templateId; + + @Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", example = "1") + private Integer sendStatus; + + @Schema(description = "发送时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] sendTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java new file mode 100644 index 0000000..49edfff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogRespVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.log; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 邮件日志 Response VO") +@Data +public class MailLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31020") + private Long id; + + @Schema(description = "用户编号", example = "30883") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2") + private Byte userType; + + @Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "76854@qq.com") + private String toMail; + + @Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107") + private Long accountId; + + @Schema(description = "发送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "85757@qq.com") + private String fromMail; + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5678") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + private String templateCode; + + @Schema(description = "模版发送人名称", example = "李四") + private String templateNickname; + + @Schema(description = "邮件标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试标题") + private String templateTitle; + + @Schema(description = "邮件内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容") + private String templateContent; + + @Schema(description = "邮件参数", requiredMode = Schema.RequiredMode.REQUIRED) + private Map templateParams; + + @Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte sendStatus; + + @Schema(description = "发送时间") + private LocalDateTime sendTime; + + @Schema(description = "发送返回的消息 ID", example = "28568") + private String sendMessageId; + + @Schema(description = "发送异常") + private String sendException; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java new file mode 100644 index 0000000..2a9afd7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplatePageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 邮件模版分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MailTemplatePageReqVO extends PageParam { + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1") + private Integer status; + + @Schema(description = "标识,模糊匹配", example = "code_1024") + private String code; + + @Schema(description = "名称,模糊匹配", example = "芋头") + private String name; + + @Schema(description = "账号编号", example = "2048") + private Long accountId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java new file mode 100644 index 0000000..8485f25 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 邮件末班 Response VO") +@Data +public class MailTemplateRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字") + private String name; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + private String code; + + @Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long accountId; + + @Schema(description = "发送人名称", example = "芋头") + private String nickname; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功") + private String title; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "奥特曼") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java new file mode 100644 index 0000000..de31697 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 邮件模版创建/修改 Request VO") +@Data +public class MailTemplateSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字") + @NotNull(message = "名称不能为空") + private String name; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @NotNull(message = "模版编号不能为空") + private String code; + + @Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送的邮箱账号编号不能为空") + private Long accountId; + + @Schema(description = "发送人名称", example = "芋头") + private String nickname; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功") + @NotEmpty(message = "标题不能为空") + private String title; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦") + @NotEmpty(message = "内容不能为空") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "奥特曼") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java new file mode 100644 index 0000000..8dd0887 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 邮件发送 Req VO") +@Data +public class MailTemplateSendReqVO { + + @Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "7685413@qq.com") + @NotEmpty(message = "接收邮箱不能为空") + private String mail; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java new file mode 100644 index 0000000..29833ff --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 邮件模版的精简 Response VO") +@Data +public class MailTemplateSimpleRespVO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "哒哒哒") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/NoticeController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/NoticeController.java new file mode 100644 index 0000000..138f2d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/NoticeController.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.system.controller.admin.notice; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeRespVO; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; +import cn.iocoder.yudao.module.system.service.notice.NoticeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 通知公告") +@RestController +@RequestMapping("/system/notice") +@Validated +public class NoticeController { + + @Resource + private NoticeService noticeService; + + @Resource + private WebSocketSenderApi webSocketSenderApi; + + @PostMapping("/create") + @Operation(summary = "创建通知公告") + @PreAuthorize("@ss.hasPermission('system:notice:create')") + public CommonResult createNotice(@Valid @RequestBody NoticeSaveReqVO createReqVO) { + Long noticeId = noticeService.createNotice(createReqVO); + return success(noticeId); + } + + @PutMapping("/update") + @Operation(summary = "修改通知公告") + @PreAuthorize("@ss.hasPermission('system:notice:update')") + public CommonResult updateNotice(@Valid @RequestBody NoticeSaveReqVO updateReqVO) { + noticeService.updateNotice(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除通知公告") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:delete')") + public CommonResult deleteNotice(@RequestParam("id") Long id) { + noticeService.deleteNotice(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获取通知公告列表") + @PreAuthorize("@ss.hasPermission('system:notice:query')") + public CommonResult> getNoticePage(@Validated NoticePageReqVO pageReqVO) { + PageResult pageResult = noticeService.getNoticePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得通知公告") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:query')") + public CommonResult getNotice(@RequestParam("id") Long id) { + NoticeDO notice = noticeService.getNotice(id); + return success(BeanUtils.toBean(notice, NoticeRespVO.class)); + } + + @PostMapping("/push") + @Operation(summary = "推送通知公告", description = "只发送给 websocket 连接在线的用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notice:update')") + public CommonResult push(@RequestParam("id") Long id) { + NoticeDO notice = noticeService.getNotice(id); + Assert.notNull(notice, "公告不能为空"); + // 通过 websocket 推送给在线的用户 + webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), "notice-push", notice); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticePageReqVO.java new file mode 100644 index 0000000..e398042 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticePageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.notice.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 通知公告分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class NoticePageReqVO extends PageParam { + + @Schema(description = "通知公告名称,模糊匹配", example = "芋道") + private String title; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeRespVO.java new file mode 100644 index 0000000..543f588 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.notice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 通知公告信息 Response VO") +@Data +public class NoticeRespVO { + + @Schema(description = "通知公告序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + private String title; + + @Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + private Integer type; + + @Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java new file mode 100644 index 0000000..200aadd --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notice/vo/NoticeSaveReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.notice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 通知公告创建/修改 Request VO") +@Data +public class NoticeSaveReqVO { + + @Schema(description = "岗位公告编号", example = "1024") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + @NotBlank(message = "公告标题不能为空") + @Size(max = 50, message = "公告标题不能超过50个字符") + private String title; + + @Schema(description = "公告类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主") + @NotNull(message = "公告类型不能为空") + private Integer type; + + @Schema(description = "公告内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "半生编码") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java new file mode 100644 index 0000000..53212fa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; +import cn.iocoder.yudao.module.system.service.notify.NotifyMessageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 我的站内信") +@RestController +@RequestMapping("/system/notify-message") +@Validated +public class NotifyMessageController { + + @Resource + private NotifyMessageService notifyMessageService; + + // ========== 管理所有的站内信 ========== + + @GetMapping("/get") + @Operation(summary = "获得站内信") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notify-message:query')") + public CommonResult getNotifyMessage(@RequestParam("id") Long id) { + NotifyMessageDO message = notifyMessageService.getNotifyMessage(id); + return success(BeanUtils.toBean(message, NotifyMessageRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得站内信分页") + @PreAuthorize("@ss.hasPermission('system:notify-message:query')") + public CommonResult> getNotifyMessagePage(@Valid NotifyMessagePageReqVO pageVO) { + PageResult pageResult = notifyMessageService.getNotifyMessagePage(pageVO); + return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class)); + } + + // ========== 查看自己的站内信 ========== + + @GetMapping("/my-page") + @Operation(summary = "获得我的站内信分页") + public CommonResult> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) { + PageResult pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO, + getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class)); + } + + @PutMapping("/update-read") + @Operation(summary = "标记站内信为已读") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + public CommonResult updateNotifyMessageRead(@RequestParam("ids") List ids) { + notifyMessageService.updateNotifyMessageRead(ids, getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(Boolean.TRUE); + } + + @PutMapping("/update-all-read") + @Operation(summary = "标记所有站内信为已读") + public CommonResult updateAllNotifyMessageRead() { + notifyMessageService.updateAllNotifyMessageRead(getLoginUserId(), UserTypeEnum.ADMIN.getValue()); + return success(Boolean.TRUE); + } + + @GetMapping("/get-unread-list") + @Operation(summary = "获取当前用户的最新站内信列表,默认 10 条") + @Parameter(name = "size", description = "10") + public CommonResult> getUnreadNotifyMessageList( + @RequestParam(name = "size", defaultValue = "10") Integer size) { + List list = notifyMessageService.getUnreadNotifyMessageList( + getLoginUserId(), UserTypeEnum.ADMIN.getValue(), size); + return success(BeanUtils.toBean(list, NotifyMessageRespVO.class)); + } + + @GetMapping("/get-unread-count") + @Operation(summary = "获得当前用户的未读站内信数量") + @ApiAccessLog(enable = false) // 由于前端会不断轮询该接口,记录日志没有意义 + public CommonResult getUnreadNotifyMessageCount() { + return success(notifyMessageService.getUnreadNotifyMessageCount( + getLoginUserId(), UserTypeEnum.ADMIN.getValue())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java new file mode 100644 index 0000000..81c5d3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.*; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import cn.iocoder.yudao.module.system.service.notify.NotifySendService; +import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 站内信模版") +@RestController +@RequestMapping("/system/notify-template") +@Validated +public class NotifyTemplateController { + + @Resource + private NotifyTemplateService notifyTemplateService; + + @Resource + private NotifySendService notifySendService; + + @PostMapping("/create") + @Operation(summary = "创建站内信模版") + @PreAuthorize("@ss.hasPermission('system:notify-template:create')") + public CommonResult createNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO createReqVO) { + return success(notifyTemplateService.createNotifyTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新站内信模版") + @PreAuthorize("@ss.hasPermission('system:notify-template:update')") + public CommonResult updateNotifyTemplate(@Valid @RequestBody NotifyTemplateSaveReqVO updateReqVO) { + notifyTemplateService.updateNotifyTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除站内信模版") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:notify-template:delete')") + public CommonResult deleteNotifyTemplate(@RequestParam("id") Long id) { + notifyTemplateService.deleteNotifyTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得站内信模版") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:notify-template:query')") + public CommonResult getNotifyTemplate(@RequestParam("id") Long id) { + NotifyTemplateDO template = notifyTemplateService.getNotifyTemplate(id); + return success(BeanUtils.toBean(template, NotifyTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得站内信模版分页") + @PreAuthorize("@ss.hasPermission('system:notify-template:query')") + public CommonResult> getNotifyTemplatePage(@Valid NotifyTemplatePageReqVO pageVO) { + PageResult pageResult = notifyTemplateService.getNotifyTemplatePage(pageVO); + return success(BeanUtils.toBean(pageResult, NotifyTemplateRespVO.class)); + } + + @PostMapping("/send-notify") + @Operation(summary = "发送站内信") + @PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')") + public CommonResult sendNotify(@Valid @RequestBody NotifyTemplateSendReqVO sendReqVO) { + if (UserTypeEnum.MEMBER.getValue().equals(sendReqVO.getUserType())) { + return success(notifySendService.sendSingleNotifyToMember(sendReqVO.getUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } else { + return success(notifySendService.sendSingleNotifyToAdmin(sendReqVO.getUserId(), + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java new file mode 100644 index 0000000..213d6e1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageMyPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyMessageMyPageReqVO extends PageParam { + + @Schema(description = "是否已读", example = "true") + private Boolean readStatus; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java new file mode 100644 index 0000000..4e3aea5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyMessagePageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "25025") + private Long userId; + + @Schema(description = "用户类型", example = "1") + private Integer userType; + + @Schema(description = "模板编码", example = "test_01") + private String templateCode; + + @Schema(description = "模版类型", example = "2") + private Integer templateType; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java new file mode 100644 index 0000000..774ed2a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.message; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 站内信 Response VO") +@Data +public class NotifyMessageRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25025") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Byte userType; + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13013") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + private String templateCode; + + @Schema(description = "模版发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String templateNickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容") + private String templateContent; + + @Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer templateType; + + @Schema(description = "模版参数", requiredMode = Schema.RequiredMode.REQUIRED) + private Map templateParams; + + @Schema(description = "是否已读", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean readStatus; + + @Schema(description = "阅读时间") + private LocalDateTime readTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java new file mode 100644 index 0000000..0557297 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplatePageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 站内信模版分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class NotifyTemplatePageReqVO extends PageParam { + + @Schema(description = "模版编码", example = "test_01") + private String code; + + @Schema(description = "模版名称", example = "我是名称") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java new file mode 100644 index 0000000..8d362b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 站内信模版 Response VO") +@Data +public class NotifyTemplateRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版") + private String name; + + @Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST") + private String code; + + @Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String nickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java new file mode 100644 index 0000000..ca75018 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 站内信模版创建/修改 Request VO") +@Data +public class NotifyTemplateSaveReqVO { + + @Schema(description = "ID", example = "1024") + private Long id; + + @Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版") + @NotEmpty(message = "模版名称不能为空") + private String name; + + @Schema(description = "模版编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "SEND_TEST") + @NotNull(message = "模版编码不能为空") + private String code; + + @Schema(description = "模版类型,对应 system_notify_template_type 字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "模版类型不能为空") + private Integer type; + + @Schema(description = "发送人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotEmpty(message = "发送人名称不能为空") + private String nickname; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是模版内容") + @NotEmpty(message = "模版内容不能为空") + private String content; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java new file mode 100644 index 0000000..43b5691 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 站内信模板的发送 Request VO") +@Data +public class NotifyTemplateSendReqVO { + + @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") + @NotNull(message = "用户id不能为空") + private Long userId; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") + @NotEmpty(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http new file mode 100644 index 0000000..dcf60a6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.http @@ -0,0 +1,23 @@ +### 请求 /login 接口 => 成功 +POST {{baseUrl}}/system/oauth2-client/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "id": "1", + "secret": "admin123", + "name": "芋道源码", + "logo": "https://www.iocoder.cn/images/favicon.ico", + "description": "我是描述", + "status": 0, + "accessTokenValiditySeconds": 180, + "refreshTokenValiditySeconds": 8640, + "redirectUris": ["https://www.iocoder.cn"], + "autoApprove": true, + "authorizedGrantTypes": ["password"], + "scopes": ["user_info"], + "authorities": ["system:user:query"], + "resource_ids": ["1024"], + "additionalInformation": "{}" +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java new file mode 100644 index 0000000..7aa9bb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2ClientController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - OAuth2 客户端") +@RestController +@RequestMapping("/system/oauth2-client") +@Validated +public class OAuth2ClientController { + + @Resource + private OAuth2ClientService oAuth2ClientService; + + @PostMapping("/create") + @Operation(summary = "创建 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:create')") + public CommonResult createOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO createReqVO) { + return success(oAuth2ClientService.createOAuth2Client(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新 OAuth2 客户端") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:update')") + public CommonResult updateOAuth2Client(@Valid @RequestBody OAuth2ClientSaveReqVO updateReqVO) { + oAuth2ClientService.updateOAuth2Client(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除 OAuth2 客户端") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:oauth2-client:delete')") + public CommonResult deleteOAuth2Client(@RequestParam("id") Long id) { + oAuth2ClientService.deleteOAuth2Client(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得 OAuth2 客户端") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult getOAuth2Client(@RequestParam("id") Long id) { + OAuth2ClientDO client = oAuth2ClientService.getOAuth2Client(id); + return success(BeanUtils.toBean(client, OAuth2ClientRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得 OAuth2 客户端分页") + @PreAuthorize("@ss.hasPermission('system:oauth2-client:query')") + public CommonResult> getOAuth2ClientPage(@Valid OAuth2ClientPageReqVO pageVO) { + PageResult pageResult = oAuth2ClientService.getOAuth2ClientPage(pageVO); + return success(BeanUtils.toBean(pageResult, OAuth2ClientRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http new file mode 100644 index 0000000..725a5d4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http @@ -0,0 +1,54 @@ +### 请求 /system/oauth2/authorize 接口 => 成功 +GET {{baseUrl}}/system/oauth2/authorize?clientId=default +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 请求 /system/oauth2/authorize + token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +response_type=token&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true + +### 请求 /system/oauth2/authorize + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=false + +### 请求 /system/oauth2/token + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a + +### 请求 /system/oauth2/token + password 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=password&username=admin&password=admin123&scope=user.read + +### 请求 /system/oauth2/token + refresh_token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 + +### 请求 /system/oauth2/token + DELETE 接口 => 成功 +DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +### 请求 /system/oauth2/check-token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java new file mode 100644 index 0000000..0b6675c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -0,0 +1,297 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * 提供给外部应用调用为主 + * + * 一般来说,管理后台的 /system-api/* 是不直接提供给外部应用使用,主要是外部应用能够访问的数据与接口是有限的,而管理后台的 RBAC 无法很好的控制。 + * 参考大量的开放平台,都是独立的一套 OpenAPI,对应到【本系统】就是在 Controller 下新建 open 包,实现 /open-api/* 接口,然后通过 scope 进行控制。 + * 另外,一个公司如果有多个管理后台,它们 client_id 产生的 access token 相互之间是无法互通的,即无法访问它们系统的 API 接口,直到两个 client_id 产生信任授权。 + * + * 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。 + * scope 的使用示例,可见 {@link OAuth2UserController} 类 + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - OAuth2.0 授权") +@RestController +@RequestMapping("/system/oauth2") +@Validated +@Slf4j +public class OAuth2OpenController { + + @Resource + private OAuth2GrantService oauth2GrantService; + @Resource + private OAuth2ClientService oauth2ClientService; + @Resource + private OAuth2ApproveService oauth2ApproveService; + @Resource + private OAuth2TokenService oauth2TokenService; + + /** + * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 + * + * 授权码 authorization_code 模式时:code + redirectUri + state 参数 + * 密码 password 模式时:username + password + scope 参数 + * 刷新 refresh_token 模式时:refreshToken 参数 + * 客户端 client_credentials 模式:scope 参数 + * 简化 implicit 模式时:不支持 + * + * 注意,默认需要传递 client_id + client_secret 参数 + */ + @PostMapping("/token") + @PermitAll + @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") + @Parameters({ + @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), + @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), + @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.iocoder.cn"), + @Parameter(name = "state", description = "状态", example = "1"), + @Parameter(name = "username", example = "tudou"), + @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 + @Parameter(name = "scope", example = "user_info"), + @Parameter(name = "refresh_token", example = "123424233"), + }) + public CommonResult postAccessToken(HttpServletRequest request, + @RequestParam("grant_type") String grantType, + @RequestParam(value = "code", required = false) String code, // 授权码模式 + @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 + @RequestParam(value = "state", required = false) String state, // 授权码模式 + @RequestParam(value = "username", required = false) String username, // 密码模式 + @RequestParam(value = "password", required = false) String password, // 密码模式 + @RequestParam(value = "scope", required = false) String scope, // 密码模式 + @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 + List scopes = OAuth2Utils.buildScopes(scope); + // 1.1 校验授权类型 + OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); + if (grantTypeEnum == null) { + throw exception0(BAD_REQUEST.getCode(), StrUtil.format("未知授权类型({})", grantType)); + } + if (grantTypeEnum == OAuth2GrantTypeEnum.IMPLICIT) { + throw exception0(BAD_REQUEST.getCode(), "Token 接口不支持 implicit 授权模式"); + } + + // 1.2 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + grantType, scopes, redirectUri); + + // 2. 根据授权模式,获取访问令牌 + OAuth2AccessTokenDO accessTokenDO; + switch (grantTypeEnum) { + case AUTHORIZATION_CODE: + accessTokenDO = oauth2GrantService.grantAuthorizationCodeForAccessToken(client.getClientId(), code, redirectUri, state); + break; + case PASSWORD: + accessTokenDO = oauth2GrantService.grantPassword(username, password, client.getClientId(), scopes); + break; + case CLIENT_CREDENTIALS: + accessTokenDO = oauth2GrantService.grantClientCredentials(client.getClientId(), scopes); + break; + case REFRESH_TOKEN: + accessTokenDO = oauth2GrantService.grantRefreshToken(refreshToken, client.getClientId()); + break; + default: + throw new IllegalArgumentException("未知授权类型:" + grantType); + } + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + return success(OAuth2OpenConvert.INSTANCE.convert(accessTokenDO)); + } + + @DeleteMapping("/token") + @PermitAll + @Operation(summary = "删除访问令牌") + @Parameter(name = "token", required = true, description = "访问令牌", example = "biu") + public CommonResult revokeToken(HttpServletRequest request, + @RequestParam("token") String token) { + // 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + null, null, null); + + // 删除访问令牌 + return success(oauth2GrantService.revokeToken(client.getClientId(), token)); + } + + /** + * 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法 + */ + @PostMapping("/check-token") + @PermitAll + @Operation(summary = "校验访问令牌") + @Parameter(name = "token", required = true, description = "访问令牌", example = "biu") + public CommonResult checkToken(HttpServletRequest request, + @RequestParam("token") String token) { + // 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + null, null, null); + + // 校验令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token); + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO)); + } + + /** + * 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 authorize 方法 + */ + @GetMapping("/authorize") + @Operation(summary = "获得授权信息", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") + @Parameter(name = "clientId", required = true, description = "客户端编号", example = "tudou") + public CommonResult authorize(@RequestParam("clientId") String clientId) { + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1. 获得 Client 客户端的信息 + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId); + // 2. 获得用户已经授权的信息 + List approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId); + // 拼接返回 + return success(OAuth2OpenConvert.INSTANCE.convert(client, approves)); + } + + /** + * 对应 Spring Security OAuth 的 AuthorizationEndpoint 类的 approveOrDeny 方法 + * + * 场景一:【自动授权 autoApprove = true】 + * 刚进入 sso.vue 界面,调用该接口,用户历史已经给该应用做过对应的授权,或者 OAuth2Client 支持该 scope 的自动授权 + * 场景二:【手动授权 autoApprove = false】 + * 在 sso.vue 界面,用户选择好 scope 授权范围,调用该接口,进行授权。此时,approved 为 true 或者 false + * + * 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理 + */ + @PostMapping("/authorize") + @Operation(summary = "申请授权", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【提交】调用") + @Parameters({ + @Parameter(name = "response_type", required = true, description = "响应类型", example = "code"), + @Parameter(name = "client_id", required = true, description = "客户端编号", example = "tudou"), + @Parameter(name = "scope", description = "授权范围", example = "userinfo.read"), // 使用 Map 格式,Spring MVC 暂时不支持这么接收参数 + @Parameter(name = "redirect_uri", required = true, description = "重定向 URI", example = "https://www.iocoder.cn"), + @Parameter(name = "auto_approve", required = true, description = "用户是否接受", example = "true"), + @Parameter(name = "state", example = "1") + }) + public CommonResult approveOrDeny(@RequestParam("response_type") String responseType, + @RequestParam("client_id") String clientId, + @RequestParam(value = "scope", required = false) String scope, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "auto_approve") Boolean autoApprove, + @RequestParam(value = "state", required = false) String state) { + @SuppressWarnings("unchecked") + Map scopes = JsonUtils.parseObject(scope, Map.class); + scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1.1 校验 responseType 是否满足 code 或者 token 值 + OAuth2GrantTypeEnum grantTypeEnum = getGrantTypeEnum(responseType); + // 1.2 校验 redirectUri 重定向域名是否合法 + 校验 scope 是否在 Client 授权范围内 + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null, + grantTypeEnum.getGrantType(), scopes.keySet(), redirectUri); + + // 2.1 假设 approved 为 null,说明是场景一 + if (Boolean.TRUE.equals(autoApprove)) { + // 如果无法自动授权通过,则返回空 url,前端不进行跳转 + if (!oauth2ApproveService.checkForPreApproval(getLoginUserId(), getUserType(), clientId, scopes.keySet())) { + return success(null); + } + } else { // 2.2 假设 approved 非 null,说明是场景二 + // 如果计算后不通过,则跳转一个错误链接 + if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) { + return success(OAuth2Utils.buildUnsuccessfulRedirect(redirectUri, responseType, state, + "access_denied", "User denied access")); + } + } + + // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 + List approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue); + if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { + return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state)); + } + // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 + return success(getImplicitGrantRedirect(getLoginUserId(), client, approveScopes, redirectUri, state)); + } + + private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) { + if (StrUtil.equals(responseType, "code")) { + return OAuth2GrantTypeEnum.AUTHORIZATION_CODE; + } + if (StrUtil.equalsAny(responseType, "token")) { + return OAuth2GrantTypeEnum.IMPLICIT; + } + throw exception0(BAD_REQUEST.getCode(), "response_type 参数值只允许 code 和 token"); + } + + private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client, + List scopes, String redirectUri, String state) { + // 1. 创建 access token 访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes); + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + // 2. 拼接重定向的 URL + // noinspection unchecked + return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(), + scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class)); + } + + private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client, + List scopes, String redirectUri, String state) { + // 1. 创建 code 授权码 + String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId, getUserType(), client.getClientId(), scopes, + redirectUri, state); + // 2. 拼接重定向的 URL + return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state); + } + + private Integer getUserType() { + return UserTypeEnum.ADMIN.getValue(); + } + + private String[] obtainBasicAuthorization(HttpServletRequest request) { + String[] clientIdAndSecret = HttpUtils.obtainBasicAuthorization(request); + if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) { + throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递"); + } + return clientIdAndSecret; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java new file mode 100644 index 0000000..62827b1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2TokenController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - OAuth2.0 令牌") +@RestController +@RequestMapping("/system/oauth2-token") +public class OAuth2TokenController { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private AdminAuthService authService; + + @GetMapping("/page") + @Operation(summary = "获得访问令牌分页", description = "只返回有效期内的") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:page')") + public CommonResult> getAccessTokenPage(@Valid OAuth2AccessTokenPageReqVO reqVO) { + PageResult pageResult = oauth2TokenService.getAccessTokenPage(reqVO); + return success(BeanUtils.toBean(pageResult, OAuth2AccessTokenRespVO.class)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除访问令牌") + @Parameter(name = "accessToken", description = "访问令牌", required = true, example = "tudou") + @PreAuthorize("@ss.hasPermission('system:oauth2-token:delete')") + public CommonResult deleteAccessToken(@RequestParam("accessToken") String accessToken) { + authService.logout(accessToken, LoginLogTypeEnum.LOGOUT_DELETE.getType()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.http new file mode 100644 index 0000000..13c8545 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.http @@ -0,0 +1,14 @@ +### 请求 /system/oauth2/user/get 接口 => 成功 +GET {{baseUrl}}/system/oauth2/user/get +Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d +tenant-id: {{adminTenentId}} + +### 请求 /system/oauth2/user/update 接口 => 成功 +PUT {{baseUrl}}/system/oauth2/user/update +Content-Type: application/json +Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d +tenant-id: {{adminTenentId}} + +{ + "nickname": "芋道源码" +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.java new file mode 100644 index 0000000..7236299 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * 提供给外部应用调用为主 + * + * 1. 在 getUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.read')") 注解,声明需要满足 scope = user.read + * 2. 在 updateUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.write')") 注解,声明需要满足 scope = user.write + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - OAuth2.0 用户") +@RestController +@RequestMapping("/system/oauth2/user") +@Validated +@Slf4j +public class OAuth2UserController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + @Resource + private PostService postService; + + @GetMapping("/get") + @Operation(summary = "获得用户基本信息") + @PreAuthorize("@ss.hasScope('user.read')") // + public CommonResult getUserInfo() { + // 获得用户基本信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + OAuth2UserInfoRespVO resp = BeanUtils.toBean(user, OAuth2UserInfoRespVO.class); + // 获得部门信息 + if (user.getDeptId() != null) { + DeptDO dept = deptService.getDept(user.getDeptId()); + resp.setDept(BeanUtils.toBean(dept, OAuth2UserInfoRespVO.Dept.class)); + } + // 获得岗位信息 + if (CollUtil.isNotEmpty(user.getPostIds())) { + List posts = postService.getPostList(user.getPostIds()); + resp.setPosts(BeanUtils.toBean(posts, OAuth2UserInfoRespVO.Post.class)); + } + return success(resp); + } + + @PutMapping("/update") + @Operation(summary = "更新用户基本信息") + @PreAuthorize("@ss.hasScope('user.write')") + public CommonResult updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) { + // 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。 + // 主要是,AdminUserService 没有自己的 BO 对象,所以复用只能这么做 + userService.updateUserProfile(getLoginUserId(), BeanUtils.toBean(reqVO, UserProfileUpdateReqVO.class)); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java new file mode 100644 index 0000000..f10f15a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientPageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +@Schema(description = "管理后台 - OAuth2 客户端分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OAuth2ClientPageReqVO extends PageParam { + + @Schema(description = "应用名,模糊匹配", example = "土豆") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java new file mode 100644 index 0000000..acd26c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientRespVO.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 客户端 Response VO") +@Data +public class OAuth2ClientRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan") + private String secret; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String logo; + + @Schema(description = "应用描述", example = "我是一个应用") + private String description; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640") + private Integer accessTokenValiditySeconds; + + @Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000") + private Integer refreshTokenValiditySeconds; + + @Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + private List redirectUris; + + @Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") + private List authorizedGrantTypes; + + @Schema(description = "授权范围", example = "user_info") + private List scopes; + + @Schema(description = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + + @Schema(description = "权限", example = "system:user:query") + private List authorities; + + @Schema(description = "资源", example = "1024") + private List resourceIds; + + @Schema(description = "附加信息", example = "{yunai: true}") + private String additionalInformation; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java new file mode 100644 index 0000000..b9199b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/client/OAuth2ClientSaveReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 客户端创建/修改 Request VO") +@Data +public class OAuth2ClientSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan") + @NotNull(message = "客户端密钥不能为空") + private String secret; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + @NotNull(message = "应用名不能为空") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + @NotNull(message = "应用图标不能为空") + @URL(message = "应用图标的地址不正确") + private String logo; + + @Schema(description = "应用描述", example = "我是一个应用") + private String description; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "访问令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640") + @NotNull(message = "访问令牌的有效期不能为空") + private Integer accessTokenValiditySeconds; + + @Schema(description = "刷新令牌的有效期", requiredMode = Schema.RequiredMode.REQUIRED, example = "8640000") + @NotNull(message = "刷新令牌的有效期不能为空") + private Integer refreshTokenValiditySeconds; + + @Schema(description = "可重定向的 URI 地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") + @NotNull(message = "可重定向的 URI 地址不能为空") + private List<@NotEmpty(message = "重定向的 URI 不能为空") @URL(message = "重定向的 URI 格式不正确") String> redirectUris; + + @Schema(description = "授权类型,参见 OAuth2GrantTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") + @NotNull(message = "授权类型不能为空") + private List authorizedGrantTypes; + + @Schema(description = "授权范围", example = "user_info") + private List scopes; + + @Schema(description = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + + @Schema(description = "权限", example = "system:user:query") + private List authorities; + + @Schema(description = "资源", example = "1024") + private List resourceIds; + + @Schema(description = "附加信息", example = "{yunai: true}") + private String additionalInformation; + + @AssertTrue(message = "附加信息必须是 JSON 格式") + public boolean isAdditionalInformationJson() { + return StrUtil.isEmpty(additionalInformation) || JsonUtils.isJson(additionalInformation); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java new file mode 100644 index 0000000..1cdc6cb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 【开放接口】访问令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenAccessTokenRespVO { + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @JsonProperty("access_token") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + @JsonProperty("refresh_token") + private String refreshToken; + + @Schema(description = "令牌类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bearer") + @JsonProperty("token_type") + private String tokenType; + + @Schema(description = "过期时间,单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "42430") + @JsonProperty("expires_in") + private Long expiresIn; + + @Schema(description = "授权范围,如果多个授权范围,使用空格分隔", example = "user_info") + private String scope; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java new file mode 100644 index 0000000..2aa3d77 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAuthorizeInfoRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 授权页的信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenAuthorizeInfoRespVO { + + /** + * 客户端 + */ + private Client client; + + @Schema(description = "scope 的选中信息,使用 List 保证有序性,Key 是 scope,Value 为是否选中", requiredMode = Schema.RequiredMode.REQUIRED) + private List> scopes; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Client { + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆") + private String name; + + @Schema(description = "应用图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png") + private String logo; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java new file mode 100644 index 0000000..cbee613 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - 【开放接口】校验令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenCheckTokenRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + @JsonProperty("user_id") + private Long userId; + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @JsonProperty("user_type") + private Integer userType; + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @JsonProperty("tenant_id") + private Long tenantId; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "car") + @JsonProperty("client_id") + private String clientId; + @Schema(description = "授权范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_info") + private List scopes; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + @JsonProperty("access_token") + private String accessToken; + + @Schema(description = "过期时间,时间戳 / 1000,即单位:秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1593092157") + private Long exp; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java new file mode 100644 index 0000000..0f932ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenPageReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 访问令牌分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2AccessTokenPageReqVO extends PageParam { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String clientId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java new file mode 100644 index 0000000..362a460 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/token/OAuth2AccessTokenRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 访问令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2AccessTokenRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") + private String accessToken; + + @Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice") + private String refreshToken; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private Long userId; + + @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String clientId; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java new file mode 100644 index 0000000..69a905d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "管理后台 - OAuth2 获得用户基本信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2UserInfoRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + private String email; + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + /** + * 所在部门 + */ + private Dept dept; + + /** + * 所属岗位数组 + */ + private List posts; + + @Schema(description = "部门") + @Data + public static class Dept { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String name; + + } + + @Schema(description = "岗位") + @Data + public static class Post { + + @Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "开发") + private String name; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java new file mode 100644 index 0000000..bb2ff4b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserUpdateReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - OAuth2 更新用户基本信息 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2UserUpdateReqVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过 30 个字符") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Length(min = 11, max = 11, message = "手机号长度必须 11 位") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.http new file mode 100644 index 0000000..a90d8b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.http @@ -0,0 +1,4 @@ +### 请求 /menu/list 接口 => 成功 +GET {{baseUrl}}/system/menu/list +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java new file mode 100644 index 0000000..3ee384e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuRespVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.service.permission.MenuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 菜单") +@RestController +@RequestMapping("/system/menu") +@Validated +public class MenuController { + + @Resource + private MenuService menuService; + + @PostMapping("/create") + @Operation(summary = "创建菜单") + @PreAuthorize("@ss.hasPermission('system:menu:create')") + public CommonResult createMenu(@Valid @RequestBody MenuSaveVO createReqVO) { + Long menuId = menuService.createMenu(createReqVO); + return success(menuId); + } + + @PutMapping("/update") + @Operation(summary = "修改菜单") + @PreAuthorize("@ss.hasPermission('system:menu:update')") + public CommonResult updateMenu(@Valid @RequestBody MenuSaveVO updateReqVO) { + menuService.updateMenu(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除菜单") + @Parameter(name = "id", description = "菜单编号", required= true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:menu:delete')") + public CommonResult deleteMenu(@RequestParam("id") Long id) { + menuService.deleteMenu(id); + return success(true); + } + + @GetMapping("/list") + @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") + @PreAuthorize("@ss.hasPermission('system:menu:query')") + public CommonResult> getMenuList(MenuListReqVO reqVO) { + List list = menuService.getMenuList(reqVO); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuRespVO.class)); + } + + @GetMapping({"/list-all-simple", "simple-list"}) + @Operation(summary = "获取菜单精简信息列表", description = "只包含被开启的菜单,用于【角色分配菜单】功能的选项。" + + "在多租户的场景下,会只返回租户所在套餐有的菜单") + public CommonResult> getSimpleMenuList() { + List list = menuService.getMenuListByTenant( + new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus())); + list = menuService.filterDisableMenus(list); + list.sort(Comparator.comparing(MenuDO::getSort)); + return success(BeanUtils.toBean(list, MenuSimpleRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获取菜单信息") + @PreAuthorize("@ss.hasPermission('system:menu:query')") + public CommonResult getMenu(Long id) { + MenuDO menu = menuService.getMenu(id); + return success(BeanUtils.toBean(menu, MenuRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java new file mode 100644 index 0000000..91f5d42 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +/** + * 权限 Controller,提供赋予用户、角色的权限的 API 接口 + * + * @author 芋道源码 + */ +@Tag(name = "管理后台 - 权限") +@RestController +@RequestMapping("/system/permission") +public class PermissionController { + + @Resource + private PermissionService permissionService; + @Resource + private TenantService tenantService; + + @Operation(summary = "获得角色拥有的菜单编号") + @Parameter(name = "roleId", description = "角色编号", required = true) + @GetMapping("/list-role-menus") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult> getRoleMenuList(Long roleId) { + return success(permissionService.getRoleMenuListByRoleId(roleId)); + } + + @PostMapping("/assign-role-menu") + @Operation(summary = "赋予角色菜单") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") + public CommonResult assignRoleMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> reqVO.getMenuIds().removeIf(menuId -> !CollUtil.contains(menuIds, menuId))); + + // 执行菜单的分配 + permissionService.assignRoleMenu(reqVO.getRoleId(), reqVO.getMenuIds()); + return success(true); + } + + @PostMapping("/assign-role-data-scope") + @Operation(summary = "赋予角色数据权限") + @PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')") + public CommonResult assignRoleDataScope(@Valid @RequestBody PermissionAssignRoleDataScopeReqVO reqVO) { + permissionService.assignRoleDataScope(reqVO.getRoleId(), reqVO.getDataScope(), reqVO.getDataScopeDeptIds()); + return success(true); + } + + @Operation(summary = "获得管理员拥有的角色编号列表") + @Parameter(name = "userId", description = "用户编号", required = true) + @GetMapping("/list-user-roles") + @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')") + public CommonResult> listAdminRoles(@RequestParam("userId") Long userId) { + return success(permissionService.getUserRoleIdListByUserId(userId)); + } + + @Operation(summary = "赋予用户角色") + @PostMapping("/assign-user-role") + @PreAuthorize("@ss.hasPermission('system:permission:assign-user-role')") + public CommonResult assignUserRole(@Validated @RequestBody PermissionAssignUserRoleReqVO reqVO) { + permissionService.assignUserRole(reqVO.getUserId(), reqVO.getRoleIds()); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.http new file mode 100644 index 0000000..c68b86b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.http @@ -0,0 +1,42 @@ +### /role/create 成功 +POST {{baseUrl}}/system/role/create +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenentId}} + +{ + "name": "测试角色", + "code": "test", + "sort": 0 +} + +### /role/update 成功 +POST {{baseUrl}}/system/role/update +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenentId}} + +{ + "id": 100, + "name": "测试角色", + "code": "test", + "sort": 10 +} +### /resource/delete 成功 +POST {{baseUrl}}/system/role/delete +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +roleId=14 + +### /role/get 成功 +GET {{baseUrl}}/system/role/get?id=100 +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### /role/page 成功 +GET {{baseUrl}}/system/role/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java new file mode 100644 index 0000000..c667a7e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.*; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static java.util.Collections.singleton; + +@Tag(name = "管理后台 - 角色") +@RestController +@RequestMapping("/system/role") +@Validated +public class RoleController { + + @Resource + private RoleService roleService; + + @PostMapping("/create") + @Operation(summary = "创建角色") + @PreAuthorize("@ss.hasPermission('system:role:create')") + public CommonResult createRole(@Valid @RequestBody RoleSaveReqVO createReqVO) { + return success(roleService.createRole(createReqVO, null)); + } + + @PutMapping("/update") + @Operation(summary = "修改角色") + @PreAuthorize("@ss.hasPermission('system:role:update')") + public CommonResult updateRole(@Valid @RequestBody RoleSaveReqVO updateReqVO) { + roleService.updateRole(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除角色") + @Parameter(name = "id", description = "角色编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:role:delete')") + public CommonResult deleteRole(@RequestParam("id") Long id) { + roleService.deleteRole(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得角色信息") + @PreAuthorize("@ss.hasPermission('system:role:query')") + public CommonResult getRole(@RequestParam("id") Long id) { + RoleDO role = roleService.getRole(id); + return success(BeanUtils.toBean(role, RoleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得角色分页") + @PreAuthorize("@ss.hasPermission('system:role:query')") + public CommonResult> getRolePage(RolePageReqVO pageReqVO) { + PageResult pageResult = roleService.getRolePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RoleRespVO.class)); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项") + public CommonResult> getSimpleRoleList() { + List list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus())); + list.sort(Comparator.comparing(RoleDO::getSort)); + return success(BeanUtils.toBean(list, RoleRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出角色 Excel") + @ApiAccessLog(operateType = EXPORT) + @PreAuthorize("@ss.hasPermission('system:role:export')") + public void export(HttpServletResponse response, @Validated RolePageReqVO exportReqVO) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = roleService.getRolePage(exportReqVO).getList(); + // 输出 + ExcelUtils.write(response, "角色数据.xls", "数据", RoleRespVO.class, + BeanUtils.toBean(list, RoleRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuListReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuListReqVO.java new file mode 100644 index 0000000..b3b7f2d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuListReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 菜单列表 Request VO") +@Data +public class MenuListReqVO { + + @Schema(description = "菜单名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuRespVO.java new file mode 100644 index 0000000..09871ec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuRespVO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 菜单信息 Response VO") +@Data +public class MenuRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java new file mode 100644 index 0000000..e172793 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSaveVO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 菜单创建/修改 Request VO") +@Data +public class MenuSaveVO { + + @Schema(description = "菜单编号", example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotBlank(message = "菜单名称不能为空") + @Size(max = 50, message = "菜单名称长度不能超过50个字符") + private String name; + + @Schema(description = "权限标识,仅菜单类型为按钮时,才需要传递", example = "sys:menu:add") + @Size(max = 100) + private String permission; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "菜单类型不能为空") + private Integer type; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "父菜单 ID 不能为空") + private Long parentId; + + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post") + @Size(max = 200, message = "路由地址不能超过200个字符") + private String path; + + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list") + private String icon; + + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index") + @Size(max = 200, message = "组件路径不能超过255个字符") + private String component; + + @Schema(description = "组件名", example = "SystemUser") + private String componentName; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + + @Schema(description = "是否可见", example = "false") + private Boolean visible; + + @Schema(description = "是否缓存", example = "false") + private Boolean keepAlive; + + @Schema(description = "是否总是显示", example = "false") + private Boolean alwaysShow; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java new file mode 100644 index 0000000..20f110e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/menu/MenuSimpleRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 菜单精简信息 Response VO") +@Data +public class MenuSimpleRespVO { + + @Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long parentId; + + @Schema(description = "类型,参见 MenuTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java new file mode 100644 index 0000000..f70426d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予角色数据权限 Request VO") +@Data +public class PermissionAssignRoleDataScopeReqVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "角色编号不能为空") + private Long roleId; + + @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据范围不能为空") + @InEnum(value = DataScopeEnum.class, message = "数据范围必须是 {value}") + private Integer dataScope; + + @Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5") + private Set dataScopeDeptIds = Collections.emptySet(); // 兜底 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java new file mode 100644 index 0000000..28ae7e4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleMenuReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予角色菜单 Request VO") +@Data +public class PermissionAssignRoleMenuReqVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "角色编号不能为空") + private Long roleId; + + @Schema(description = "菜单编号列表", example = "1,3,5") + private Set menuIds = Collections.emptySet(); // 兜底 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java new file mode 100644 index 0000000..9ca43f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignUserRoleReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.permission; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.Set; + +@Schema(description = "管理后台 - 赋予用户角色 Request VO") +@Data +public class PermissionAssignUserRoleReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "角色编号列表", example = "1,3,5") + private Set roleIds = Collections.emptySet(); // 兜底 + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java new file mode 100644 index 0000000..c871274 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 角色分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class RolePageReqVO extends PageParam { + + @Schema(description = "角色名称,模糊匹配", example = "芋道") + private String name; + + @Schema(description = "角色标识,模糊匹配", example = "yudao") + private String code; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleRespVO.java new file mode 100644 index 0000000..12b3ba9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleRespVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 角色信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class RoleRespVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("角色序号") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员") + @ExcelProperty("角色名称") + private String name; + + @Schema(description = "角色标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin") + @NotBlank(message = "角色标志不能为空") + @ExcelProperty("角色标志") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("角色排序") + private Integer sort; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "角色状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "角色类型,参见 RoleTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "备注", example = "我是一个角色") + private String remark; + + @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("数据范围") + private Integer dataScope; + + @Schema(description = "数据范围(指定部门数组)", example = "1") + private Set dataScopeDeptIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java new file mode 100644 index 0000000..6830e01 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; + +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Schema(description = "管理后台 - 角色创建/更新 Request VO") +@Data +public class RoleSaveReqVO { + + @Schema(description = "角色编号", example = "1") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员") + @NotBlank(message = "角色名称不能为空") + @Size(max = 30, message = "角色名称长度不能超过 30 个字符") + @DiffLogField(name = "角色名称") + private String name; + + @NotBlank(message = "角色标志不能为空") + @Size(max = 100, message = "角色标志长度不能超过 100 个字符") + @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN") + @DiffLogField(name = "角色标志") + private String code; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "显示顺序不能为空") + @DiffLogField(name = "显示顺序") + private Integer sort; + + @Schema(description = "备注", example = "我是一个角色") + @DiffLogField(name = "备注") + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java new file mode 100644 index 0000000..1e9a9df --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSimpleRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 角色精简信息 Response VO") +@Data +public class RoleSimpleRespVO { + + @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java new file mode 100644 index 0000000..895decf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.yudao.module.system.service.sms.SmsSendService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletRequest; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信回调") +@RestController +@RequestMapping("/system/sms/callback") +public class SmsCallbackController { + + @Resource + private SmsSendService smsSendService; + + @PostMapping("/aliyun") + @PermitAll + @Operation(summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/zh/sms/developer-reference/configure-delivery-receipts-1 文档") + public CommonResult receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable { + String text = ServletUtils.getBody(request); + smsSendService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text); + return success(true); + } + + @PostMapping("/tencent") + @PermitAll + @Operation(summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/59178 文档") + public CommonResult receiveTencentSmsStatus(HttpServletRequest request) throws Throwable { + String text = ServletUtils.getBody(request); + smsSendService.receiveSmsStatus(SmsChannelEnum.TENCENT.getCode(), text); + return success(true); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsChannelController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsChannelController.java new file mode 100644 index 0000000..79ff7b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsChannelController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelRespVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.service.sms.SmsChannelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信渠道") +@RestController +@RequestMapping("system/sms-channel") +public class SmsChannelController { + + @Resource + private SmsChannelService smsChannelService; + + @PostMapping("/create") + @Operation(summary = "创建短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:create')") + public CommonResult createSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO createReqVO) { + return success(smsChannelService.createSmsChannel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:update')") + public CommonResult updateSmsChannel(@Valid @RequestBody SmsChannelSaveReqVO updateReqVO) { + smsChannelService.updateSmsChannel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除短信渠道") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-channel:delete')") + public CommonResult deleteSmsChannel(@RequestParam("id") Long id) { + smsChannelService.deleteSmsChannel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得短信渠道") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult getSmsChannel(@RequestParam("id") Long id) { + SmsChannelDO channel = smsChannelService.getSmsChannel(id); + return success(BeanUtils.toBean(channel, SmsChannelRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得短信渠道分页") + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult> getSmsChannelPage(@Valid SmsChannelPageReqVO pageVO) { + PageResult pageResult = smsChannelService.getSmsChannelPage(pageVO); + return success(BeanUtils.toBean(pageResult, SmsChannelRespVO.class)); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获得短信渠道精简列表", description = "包含被禁用的短信渠道") + public CommonResult> getSimpleSmsChannelList() { + List list = smsChannelService.getSmsChannelList(); + list.sort(Comparator.comparing(SmsChannelDO::getId)); + return success(BeanUtils.toBean(list, SmsChannelSimpleRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java new file mode 100644 index 0000000..10594a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; +import cn.iocoder.yudao.module.system.service.sms.SmsLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信日志") +@RestController +@RequestMapping("/system/sms-log") +@Validated +public class SmsLogController { + + @Resource + private SmsLogService smsLogService; + + @GetMapping("/page") + @Operation(summary = "获得短信日志分页") + @PreAuthorize("@ss.hasPermission('system:sms-log:query')") + public CommonResult> getSmsLogPage(@Valid SmsLogPageReqVO pageReqVO) { + PageResult pageResult = smsLogService.getSmsLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出短信日志 Excel") + @PreAuthorize("@ss.hasPermission('system:sms-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSmsLogExcel(@Valid SmsLogPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = smsLogService.getSmsLogPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "短信日志.xls", "数据", SmsLogRespVO.class, + BeanUtils.toBean(list, SmsLogRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.http new file mode 100644 index 0000000..ee24e92 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.http @@ -0,0 +1,14 @@ +### 请求 /system/sms-template/send-sms 接口 => 成功 +POST {{baseUrl}}/system/sms-template/send-sms +Authorization: Bearer {{token}} +Content-Type: application/json +tenant-id: {{adminTenentId}} + +{ + "templateCode": "test_01", + "mobile": "15601691390", + "templateParams": { + "operation": "value01", + "code": "value02" + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java new file mode 100644 index 0000000..dc587ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.*; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.service.sms.SmsTemplateService; +import cn.iocoder.yudao.module.system.service.sms.SmsSendService; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 短信模板") +@RestController +@RequestMapping("/system/sms-template") +public class SmsTemplateController { + + @Resource + private SmsTemplateService smsTemplateService; + @Resource + private SmsSendService smsSendService; + + @PostMapping("/create") + @Operation(summary = "创建短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:create')") + public CommonResult createSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO createReqVO) { + return success(smsTemplateService.createSmsTemplate(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:update')") + public CommonResult updateSmsTemplate(@Valid @RequestBody SmsTemplateSaveReqVO updateReqVO) { + smsTemplateService.updateSmsTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除短信模板") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-template:delete')") + public CommonResult deleteSmsTemplate(@RequestParam("id") Long id) { + smsTemplateService.deleteSmsTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得短信模板") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult getSmsTemplate(@RequestParam("id") Long id) { + SmsTemplateDO template = smsTemplateService.getSmsTemplate(id); + return success(BeanUtils.toBean(template, SmsTemplateRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得短信模板分页") + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult> getSmsTemplatePage(@Valid SmsTemplatePageReqVO pageVO) { + PageResult pageResult = smsTemplateService.getSmsTemplatePage(pageVO); + return success(BeanUtils.toBean(pageResult, SmsTemplateRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出短信模板 Excel") + @PreAuthorize("@ss.hasPermission('system:sms-template:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportSmsTemplateExcel(@Valid SmsTemplatePageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = smsTemplateService.getSmsTemplatePage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "短信模板.xls", "数据", SmsTemplateRespVO.class, + BeanUtils.toBean(list, SmsTemplateRespVO.class)); + } + + @PostMapping("/send-sms") + @Operation(summary = "发送短信") + @PreAuthorize("@ss.hasPermission('system:sms-template:send-sms')") + public CommonResult sendSms(@Valid @RequestBody SmsTemplateSendReqVO sendReqVO) { + return success(smsSendService.sendSingleSmsToAdmin(sendReqVO.getMobile(), null, + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java new file mode 100644 index 0000000..2ec9b2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信渠道分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsChannelPageReqVO extends PageParam { + + @Schema(description = "任务状态", example = "1") + private Integer status; + + @Schema(description = "短信签名,模糊匹配", example = "芋道源码") + private String signature; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java new file mode 100644 index 0000000..70b709e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 短信渠道 Response VO") +@Data +public class SmsChannelRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "短信签名不能为空") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + private String code; + + @Schema(description = "启用状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "启用状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "好吃!") + private String remark; + + @Schema(description = "短信 API 的账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "短信 API 的账号不能为空") + private String apiKey; + + @Schema(description = "短信 API 的密钥", example = "yuanma") + private String apiSecret; + + @Schema(description = "短信发送回调 URL", example = "https://www.iocoder.cn") + @URL(message = "回调 URL 格式不正确") + private String callbackUrl; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java new file mode 100644 index 0000000..47cde1e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSaveReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 短信渠道创建/修改 Request VO") +@Data +public class SmsChannelSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + @NotNull(message = "短信签名不能为空") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + @NotNull(message = "渠道编码不能为空") + private String code; + + @Schema(description = "启用状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "启用状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "好吃!") + private String remark; + + @Schema(description = "短信 API 的账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "短信 API 的账号不能为空") + private String apiKey; + + @Schema(description = "短信 API 的密钥", example = "yuanma") + private String apiSecret; + + @Schema(description = "短信发送回调 URL", example = "http://www.iocoder.cn") + @URL(message = "回调 URL 格式不正确") + private String callbackUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java new file mode 100644 index 0000000..350297c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelSimpleRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 短信渠道精简 Response VO") +@Data +public class SmsChannelSimpleRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "短信签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String signature; + + @Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN") + private String code; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java new file mode 100644 index 0000000..fbf9dcf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.log; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信日志分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsLogPageReqVO extends PageParam { + + @Schema(description = "短信渠道编号", example = "10") + private Long channelId; + + @Schema(description = "模板编号", example = "20") + private Long templateId; + + @Schema(description = "手机号", example = "15601691300") + private String mobile; + + @Schema(description = "发送状态,参见 SmsSendStatusEnum 枚举类", example = "1") + private Integer sendStatus; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "发送时间") + private LocalDateTime[] sendTime; + + @Schema(description = "接收状态,参见 SmsReceiveStatusEnum 枚举类", example = "0") + private Integer receiveStatus; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "接收时间") + private LocalDateTime[] receiveTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java new file mode 100644 index 0000000..77409ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.log; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.framework.excel.core.convert.JsonConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Map; + +@Schema(description = "管理后台 - 短信日志 Response VO") +@Data +@ExcelIgnoreUnannotated +public class SmsLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("短信渠道编号") + private Long channelId; + + @Schema(description = "短信渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALIYUN") + @ExcelProperty("短信渠道编码") + private String channelCode; + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @ExcelProperty("模板编号") + private Long templateId; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test-01") + @ExcelProperty("模板编码") + private String templateCode; + + @Schema(description = "短信类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "短信类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_TEMPLATE_TYPE) + private Integer templateType; + + @Schema(description = "短信内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你的验证码是 1024") + @ExcelProperty("短信内容") + private String templateContent; + + @Schema(description = "短信参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "name,code") + @ExcelProperty(value = "短信参数", converter = JsonConvert.class) + private Map templateParams; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SMS_207945135") + @ExcelProperty("短信 API 的模板编号") + private String apiTemplateId; + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @ExcelProperty("手机号") + private String mobile; + + @Schema(description = "用户编号", example = "10") + @ExcelProperty("用户编号") + private Long userId; + + @Schema(description = "用户类型", example = "1") + @ExcelProperty(value = "用户类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_TYPE) + private Integer userType; + + @Schema(description = "发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "发送状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_SEND_STATUS) + private Integer sendStatus; + + @Schema(description = "发送时间") + @ExcelProperty("发送时间") + private LocalDateTime sendTime; + + @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS") + @ExcelProperty("短信 API 发送结果的编码") + private String apiSendCode; + + @Schema(description = "短信 API 发送失败的提示", example = "成功") + @ExcelProperty("短信 API 发送失败的提示") + private String apiSendMsg; + + @Schema(description = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99") + @ExcelProperty("短信 API 发送返回的唯一请求 ID") + private String apiRequestId; + + @Schema(description = "短信 API 发送返回的序号", example = "62923244790") + @ExcelProperty("短信 API 发送返回的序号") + private String apiSerialNo; + + @Schema(description = "接收状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty(value = "接收状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_RECEIVE_STATUS) + private Integer receiveStatus; + + @Schema(description = "接收时间") + @ExcelProperty("接收时间") + private LocalDateTime receiveTime; + + @Schema(description = "API 接收结果的编码", example = "DELIVRD") + @ExcelProperty("API 接收结果的编码") + private String apiReceiveCode; + + @Schema(description = "API 接收结果的说明", example = "用户接收成功") + @ExcelProperty("API 接收结果的说明") + private String apiReceiveMsg; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java new file mode 100644 index 0000000..acf99e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.template; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 短信模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsTemplatePageReqVO extends PageParam { + + @Schema(description = "短信签名", example = "1") + private Integer type; + + @Schema(description = "开启状态", example = "1") + private Integer status; + + @Schema(description = "模板编码,模糊匹配", example = "test_01") + private String code; + + @Schema(description = "模板内容,模糊匹配", example = "你好,{name}。你长的太{like}啦!") + private String content; + + @Schema(description = "短信 API 的模板编号,模糊匹配", example = "4383920") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", example = "10") + private Long channelId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java new file mode 100644 index 0000000..6b8aeca --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateRespVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.template; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 短信模板 Response VO") +@Data +@ExcelIgnoreUnannotated +public class SmsTemplateRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "短信类型,参见 SmsTemplateTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "短信签名", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_TEMPLATE_TYPE) + private Integer type; + + @Schema(description = "开启状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @ExcelProperty("模板编码") + private String code; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("模板名称") + private String name; + + @Schema(description = "模板内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,{name}。你长的太{like}啦!") + @ExcelProperty("模板内容") + private String content; + + @Schema(description = "参数数组", example = "name,code") + private List params; + + @Schema(description = "备注", example = "哈哈哈") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4383920") + @ExcelProperty("短信 API 的模板编号") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @ExcelProperty("短信渠道编号") + private Long channelId; + + @Schema(description = "短信渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALIYUN") + @ExcelProperty(value = "短信渠道编码", converter = DictConvert.class) + @DictFormat(DictTypeConstants.SMS_CHANNEL_CODE) + private String channelCode; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java new file mode 100644 index 0000000..7199bf3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSaveReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 短信模板创建/修改 Request VO") +@Data +public class SmsTemplateSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "短信类型,参见 SmsTemplateTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "短信类型不能为空") + private Integer type; + + @Schema(description = "开启状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String code; + + @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotNull(message = "模板名称不能为空") + private String name; + + @Schema(description = "模板内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,{name}。你长的太{like}啦!") + @NotNull(message = "模板内容不能为空") + private String content; + + @Schema(description = "备注", example = "哈哈哈") + private String remark; + + @Schema(description = "短信 API 的模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4383920") + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; + + @Schema(description = "短信渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java new file mode 100644 index 0000000..e420966 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSendReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.controller.admin.sms.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(description = "管理后台 - 短信模板的发送 Request VO") +@Data +public class SmsTemplateSendReqVO { + + @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300") + @NotNull(message = "手机号不能为空") + private String mobile; + + @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String templateCode; + + @Schema(description = "模板参数") + private Map templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java new file mode 100644 index 0000000..c9b5f4d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; +import cn.iocoder.yudao.module.system.service.social.SocialClientService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 社交客户端") +@RestController +@RequestMapping("/system/social-client") +@Validated +public class SocialClientController { + + @Resource + private SocialClientService socialClientService; + + @PostMapping("/create") + @Operation(summary = "创建社交客户端") + @PreAuthorize("@ss.hasPermission('system:social-client:create')") + public CommonResult createSocialClient(@Valid @RequestBody SocialClientSaveReqVO createReqVO) { + return success(socialClientService.createSocialClient(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新社交客户端") + @PreAuthorize("@ss.hasPermission('system:social-client:update')") + public CommonResult updateSocialClient(@Valid @RequestBody SocialClientSaveReqVO updateReqVO) { + socialClientService.updateSocialClient(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除社交客户端") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:social-client:delete')") + public CommonResult deleteSocialClient(@RequestParam("id") Long id) { + socialClientService.deleteSocialClient(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得社交客户端") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public CommonResult getSocialClient(@RequestParam("id") Long id) { + SocialClientDO client = socialClientService.getSocialClient(id); + return success(BeanUtils.toBean(client, SocialClientRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得社交客户端分页") + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public CommonResult> getSocialClientPage(@Valid SocialClientPageReqVO pageVO) { + PageResult pageResult = socialClientService.getSocialClientPage(pageVO); + return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialUserController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialUserController.java new file mode 100644 index 0000000..eb2792e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialUserController.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserUnbindReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserRespVO; +import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 社交用户") +@RestController +@RequestMapping("/system/social-user") +@Validated +public class SocialUserController { + + @Resource + private SocialUserService socialUserService; + + @PostMapping("/bind") + @Operation(summary = "社交绑定,使用 code 授权码") + public CommonResult socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) { + socialUserService.bindSocialUser(SocialUserConvert.INSTANCE.convert( + getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO)); + return CommonResult.success(true); + } + + @DeleteMapping("/unbind") + @Operation(summary = "取消社交绑定") + public CommonResult socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) { + socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid()); + return CommonResult.success(true); + } + + // ==================== 社交用户 CRUD ==================== + + @GetMapping("/get") + @Operation(summary = "获得社交用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult getSocialUser(@RequestParam("id") Long id) { + SocialUserDO socialUser = socialUserService.getSocialUser(id); + return success(BeanUtils.toBean(socialUser, SocialUserRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得社交用户分页") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) { + PageResult pageResult = socialUserService.getSocialUserPage(pageVO); + return success(BeanUtils.toBean(pageResult, SocialUserRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java new file mode 100644 index 0000000..a225530 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - 社交客户端分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SocialClientPageReqVO extends PageParam { + + @Schema(description = "应用名", example = "yudao商城") + private String name; + + @Schema(description = "社交平台的类型", example = "31") + private Integer socialType; + + @Schema(description = "用户类型", example = "2") + private Integer userType; + + @Schema(description = "客户端编号", example = "145442115") + private String clientId; + + @Schema(description = "状态", example = "1") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java new file mode 100644 index 0000000..900f363 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 社交客户端 Response VO") +@Data +public class SocialClientRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27162") + private Long id; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao商城") + private String name; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31") + private Integer socialType; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") + private String clientSecret; + + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String agentId; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java new file mode 100644 index 0000000..be89153 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.client; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import java.util.Objects; + +@Schema(description = "管理后台 - 社交客户端创建/修改 Request VO") +@Data +public class SocialClientSaveReqVO { + + @Schema(description = "编号", example = "27162") + private Long id; + + @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao商城") + @NotNull(message = "应用名不能为空") + private String name; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31") + @NotNull(message = "社交平台的类型不能为空") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "用户类型不能为空") + @InEnum(UserTypeEnum.class) + private Integer userType; + + @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54") + @NotNull(message = "客户端编号不能为空") + private String clientId; + + @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") + @NotNull(message = "客户端密钥不能为空") + private String clientSecret; + + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String agentId; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @AssertTrue(message = "agentId 不能为空") + @JsonIgnore + public boolean isAgentIdValid() { + // 如果是企业微信,必须填写 agentId 属性 + return !Objects.equals(socialType, SocialTypeEnum.WECHAT_ENTERPRISE.getType()) + || !StrUtil.isEmpty(agentId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java new file mode 100644 index 0000000..9ba4168 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserBindReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user; + +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 社交绑定 Request VO,使用 code 授权码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SocialUserBindReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java new file mode 100644 index 0000000..3297db4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 社交用户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SocialUserPageReqVO extends PageParam { + + @Schema(description = "社交平台的类型", example = "30") + private Integer type; + + @Schema(description = "用户昵称", example = "李四") + private String nickname; + + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w") + private String openid; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java new file mode 100644 index 0000000..fd37703 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 社交用户 Response VO") +@Data +public class SocialUserRespVO { + + @Schema(description = "主键(自增策略)", requiredMode = Schema.RequiredMode.REQUIRED, example = "14569") + private Long id; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer type; + + @Schema(description = "社交 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String openid; + + @Schema(description = "社交 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String token; + + @Schema(description = "原始 Token 数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawTokenInfo; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "原始用户数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawUserInfo; + + @Schema(description = "最后一次的认证 code", requiredMode = Schema.RequiredMode.REQUIRED, example = "666666") + private String code; + + @Schema(description = "最后一次的认证 state", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String state; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java new file mode 100644 index 0000000..10f07fc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserUnbindReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.socail.vo.user; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 取消社交绑定 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SocialUserUnbindReqVO { + + @Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @InEnum(SocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + @NotEmpty(message = "社交用户的 openid 不能为空") + private String openid; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.http new file mode 100644 index 0000000..a4d5173 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.http @@ -0,0 +1,21 @@ +### 获取租户编号 /admin-api/system/get-id-by-name +GET {{baseUrl}}/system/tenant/get-id-by-name?name=芋道源码 + +### 创建租户 /admin-api/system/tenant/create +POST {{baseUrl}}/system/tenant/create +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +{ + "name": "芋道", + "contactName": "芋艿", + "contactMobile": "15601691300", + "status": 0, + "domain": "https://www.iocoder.cn", + "packageId": 110, + "expireTime": 1699545600000, + "accountCount": 20, + "username": "admin", + "password": "123321" +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java new file mode 100644 index 0000000..bb7aa84 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租户") +@RestController +@RequestMapping("/system/tenant") +public class TenantController { + + @Resource + private TenantService tenantService; + + @GetMapping("/get-id-by-name") + @PermitAll + @Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号") + @Parameter(name = "name", description = "租户名", required = true, example = "1024") + public CommonResult getTenantIdByName(@RequestParam("name") String name) { + TenantDO tenant = tenantService.getTenantByName(name); + return success(tenant != null ? tenant.getId() : null); + } + + @GetMapping("/get-by-website") + @PermitAll + @Operation(summary = "使用域名,获得租户信息", description = "登录界面,根据用户的域名,获得租户信息") + @Parameter(name = "website", description = "域名", required = true, example = "www.iocoder.cn") + public CommonResult getTenantByWebsite(@RequestParam("website") String website) { + TenantDO tenant = tenantService.getTenantByWebsite(website); + return success(BeanUtils.toBean(tenant, TenantSimpleRespVO.class)); + } + + @PostMapping("/create") + @Operation(summary = "创建租户") + @PreAuthorize("@ss.hasPermission('system:tenant:create')") + public CommonResult createTenant(@Valid @RequestBody TenantSaveReqVO createReqVO) { + return success(tenantService.createTenant(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户") + @PreAuthorize("@ss.hasPermission('system:tenant:update')") + public CommonResult updateTenant(@Valid @RequestBody TenantSaveReqVO updateReqVO) { + tenantService.updateTenant(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant:delete')") + public CommonResult deleteTenant(@RequestParam("id") Long id) { + tenantService.deleteTenant(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant:query')") + public CommonResult getTenant(@RequestParam("id") Long id) { + TenantDO tenant = tenantService.getTenant(id); + return success(BeanUtils.toBean(tenant, TenantRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户分页") + @PreAuthorize("@ss.hasPermission('system:tenant:query')") + public CommonResult> getTenantPage(@Valid TenantPageReqVO pageVO) { + PageResult pageResult = tenantService.getTenantPage(pageVO); + return success(BeanUtils.toBean(pageResult, TenantRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出租户 Excel") + @PreAuthorize("@ss.hasPermission('system:tenant:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportTenantExcel(@Valid TenantPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = tenantService.getTenantPage(exportReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "租户.xls", "数据", TenantRespVO.class, + BeanUtils.toBean(list, TenantRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java new file mode 100644 index 0000000..f523d51 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantPackageController.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.*; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.service.tenant.TenantPackageService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租户套餐") +@RestController +@RequestMapping("/system/tenant-package") +@Validated +public class TenantPackageController { + + @Resource + private TenantPackageService tenantPackageService; + + @PostMapping("/create") + @Operation(summary = "创建租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-package:create')") + public CommonResult createTenantPackage(@Valid @RequestBody TenantPackageSaveReqVO createReqVO) { + return success(tenantPackageService.createTenantPackage(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租户套餐") + @PreAuthorize("@ss.hasPermission('system:tenant-package:update')") + public CommonResult updateTenantPackage(@Valid @RequestBody TenantPackageSaveReqVO updateReqVO) { + tenantPackageService.updateTenantPackage(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租户套餐") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:tenant-package:delete')") + public CommonResult deleteTenantPackage(@RequestParam("id") Long id) { + tenantPackageService.deleteTenantPackage(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租户套餐") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:tenant-package:query')") + public CommonResult getTenantPackage(@RequestParam("id") Long id) { + TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(id); + return success(BeanUtils.toBean(tenantPackage, TenantPackageRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租户套餐分页") + @PreAuthorize("@ss.hasPermission('system:tenant-package:query')") + public CommonResult> getTenantPackagePage(@Valid TenantPackagePageReqVO pageVO) { + PageResult pageResult = tenantPackageService.getTenantPackagePage(pageVO); + return success(BeanUtils.toBean(pageResult, TenantPackageRespVO.class)); + } + + @GetMapping({"/get-simple-list", "simple-list"}) + @Operation(summary = "获取租户套餐精简信息列表", description = "只包含被开启的租户套餐,主要用于前端的下拉选项") + public CommonResult> getTenantPackageList() { + List list = tenantPackageService.getTenantPackageListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(BeanUtils.toBean(list, TenantPackageSimpleRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java new file mode 100644 index 0000000..525a5da --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户套餐分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TenantPackagePageReqVO extends PageParam { + + @Schema(description = "套餐名", example = "VIP") + private String name; + + @Schema(description = "状态", example = "1") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java new file mode 100644 index 0000000..16ffd81 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 租户套餐 Response VO") +@Data +public class TenantPackageRespVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Set menuIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java new file mode 100644 index 0000000..3faed3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSaveReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 租户套餐创建/修改 Request VO") +@Data +public class TenantPackageSaveReqVO { + + @Schema(description = "套餐编号", example = "1024") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + @NotEmpty(message = "套餐名不能为空") + private String name; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + @Schema(description = "备注", example = "好") + private String remark; + + @Schema(description = "关联的菜单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "关联的菜单编号不能为空") + private Set menuIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java new file mode 100644 index 0000000..bc3d62a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageSimpleRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租户套餐精简 Response VO") +@Data +public class TenantPackageSimpleRespVO { + + @Schema(description = "套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "套餐编号不能为空") + private Long id; + + @Schema(description = "套餐名", requiredMode = Schema.RequiredMode.REQUIRED, example = "VIP") + @NotNull(message = "套餐名不能为空") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java new file mode 100644 index 0000000..512a4a7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class TenantPageReqVO extends PageParam { + + @Schema(description = "租户名", example = "芋道") + private String name; + + @Schema(description = "联系人", example = "芋艿") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + private String contactMobile; + + @Schema(description = "租户状态(0正常 1停用)", example = "1") + private Integer status; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Schema(description = "创建时间") + private LocalDateTime[] createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java new file mode 100644 index 0000000..5a444b5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantRespVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户 Response VO") +@Data +@ExcelIgnoreUnannotated +public class TenantRespVO { + + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("租户编号") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @ExcelProperty("租户名") + private String name; + + @Schema(description = "联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("联系人") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + @ExcelProperty("联系手机") + private String contactMobile; + + @Schema(description = "租户状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "绑定域名", example = "https://www.iocoder.cn") + private String website; + + @Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long packageId; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime expireTime; + + @Schema(description = "账号数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer accountCount; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java new file mode 100644 index 0000000..117d365 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSaveReqVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租户创建/修改 Request VO") +@Data +public class TenantSaveReqVO { + + @Schema(description = "租户编号", example = "1024") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "租户名不能为空") + private String name; + + @Schema(description = "联系人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotNull(message = "联系人不能为空") + private String contactName; + + @Schema(description = "联系手机", example = "15601691300") + private String contactMobile; + + @Schema(description = "租户状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "租户状态") + private Integer status; + + @Schema(description = "绑定域名", example = "https://www.iocoder.cn") + private String website; + + @Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "租户套餐编号不能为空") + private Long packageId; + + @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "过期时间不能为空") + private LocalDateTime expireTime; + + @Schema(description = "账号数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "账号数量不能为空") + private Integer accountCount; + + // ========== 仅【创建】时,需要传递的字段 ========== + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成") + @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") + private String username; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @AssertTrue(message = "用户账号、密码不能为空") + @JsonIgnore + public boolean isUsernameValid() { + return id != null // 修改时,不需要传递 + || (ObjectUtil.isAllNotEmpty(username, password)); // 新增时,必须都传递 username、password + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java new file mode 100644 index 0000000..4975227 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantSimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 租户精简 Response VO") +@Data +public class TenantSimpleRespVO { + + @Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http new file mode 100644 index 0000000..7d7f622 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http @@ -0,0 +1,5 @@ +### 请求 /system/user/page 接口 => 没有权限 +GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10 +Authorization: Bearer {{token}} +#Authorization: Bearer test100 +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java new file mode 100644 index 0000000..253857b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.system.controller.admin.user; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*; +import cn.iocoder.yudao.module.system.convert.user.UserConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - 用户") +@RestController +@RequestMapping("/system/user") +@Validated +public class UserController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + + @PostMapping("/create") + @Operation(summary = "新增用户") + @PreAuthorize("@ss.hasPermission('system:user:create')") + public CommonResult createUser(@Valid @RequestBody UserSaveReqVO reqVO) { + Long id = userService.createUser(reqVO); + return success(id); + } + + @PutMapping("update") + @Operation(summary = "修改用户") + @PreAuthorize("@ss.hasPermission('system:user:update')") + public CommonResult updateUser(@Valid @RequestBody UserSaveReqVO reqVO) { + userService.updateUser(reqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:user:delete')") + public CommonResult deleteUser(@RequestParam("id") Long id) { + userService.deleteUser(id); + return success(true); + } + + @PutMapping("/update-password") + @Operation(summary = "重置用户密码") + @PreAuthorize("@ss.hasPermission('system:user:update-password')") + public CommonResult updateUserPassword(@Valid @RequestBody UserUpdatePasswordReqVO reqVO) { + userService.updateUserPassword(reqVO.getId(), reqVO.getPassword()); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "修改用户状态") + @PreAuthorize("@ss.hasPermission('system:user:update')") + public CommonResult updateUserStatus(@Valid @RequestBody UserUpdateStatusReqVO reqVO) { + userService.updateUserStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得用户分页列表") + @PreAuthorize("@ss.hasPermission('system:user:list')") + public CommonResult> getUserPage(@Valid UserPageReqVO pageReqVO) { + // 获得用户分页列表 + PageResult pageResult = userService.getUserPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(new PageResult<>(pageResult.getTotal())); + } + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(pageResult.getList(), AdminUserDO::getDeptId)); + return success(new PageResult<>(UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap), + pageResult.getTotal())); + } + + @GetMapping({"/list-all-simple", "/simple-list"}) + @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项") + public CommonResult> getSimpleUserList() { + List list = userService.getUserListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); + } + + @GetMapping("/get") + @Operation(summary = "获得用户详情") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:user:query')") + public CommonResult getUser(@RequestParam("id") Long id) { + AdminUserDO user = userService.getUser(id); + if (user == null) { + return success(null); + } + // 拼接数据 + DeptDO dept = deptService.getDept(user.getDeptId()); + return success(UserConvert.INSTANCE.convert(user, dept)); + } + + @GetMapping("/export") + @Operation(summary = "导出用户") + @PreAuthorize("@ss.hasPermission('system:user:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportUserList(@Validated UserPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = userService.getUserPage(exportReqVO).getList(); + // 输出 Excel + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + ExcelUtils.write(response, "用户数据.xls", "数据", UserRespVO.class, + UserConvert.INSTANCE.convertList(list, deptMap)); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得导入用户模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List list = Arrays.asList( + UserImportExcelVO.builder().username("yunai").deptId(1L).email("yunai@iocoder.cn").mobile("15601691300") + .nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build(), + UserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300") + .nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SexEnum.FEMALE.getSex()).build() + ); + // 输出 + ExcelUtils.write(response, "用户导入模板.xls", "用户列表", UserImportExcelVO.class, list); + } + + @PostMapping("/import") + @Operation(summary = "导入用户") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('system:user:import')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { + List list = ExcelUtils.read(file, UserImportExcelVO.class); + return success(userService.importUserList(list, updateSupport)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.http b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.http new file mode 100644 index 0000000..f06037b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.http @@ -0,0 +1,4 @@ +### 请求 /system/user/profile/get 接口 => 没有权限 +GET {{baseUrl}}/system/user/profile/get +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java new file mode 100644 index 0000000..5fc4cac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.system.controller.admin.user; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import cn.iocoder.yudao.module.system.convert.user.UserConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY; + +@Tag(name = "管理后台 - 用户个人中心") +@RestController +@RequestMapping("/system/user/profile") +@Validated +@Slf4j +public class UserProfileController { + + @Resource + private AdminUserService userService; + @Resource + private DeptService deptService; + @Resource + private PostService postService; + @Resource + private PermissionService permissionService; + @Resource + private RoleService roleService; + @Resource + private SocialUserService socialService; + + @GetMapping("/get") + @Operation(summary = "获得登录用户信息") + @DataPermission(enable = false) // 关闭数据权限,避免只查看自己时,查询不到部门。 + public CommonResult getUserProfile() { + // 获得用户基本信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + // 获得用户角色 + List userRoles = roleService.getRoleListFromCache(permissionService.getUserRoleIdListByUserId(user.getId())); + // 获得部门信息 + DeptDO dept = user.getDeptId() != null ? deptService.getDept(user.getDeptId()) : null; + // 获得岗位信息 + List posts = CollUtil.isNotEmpty(user.getPostIds()) ? postService.getPostList(user.getPostIds()) : null; + // 获得社交用户信息 + List socialUsers = socialService.getSocialUserList(user.getId(), UserTypeEnum.ADMIN.getValue()); + return success(UserConvert.INSTANCE.convert(user, userRoles, dept, posts, socialUsers)); + } + + @PutMapping("/update") + @Operation(summary = "修改用户个人信息") + public CommonResult updateUserProfile(@Valid @RequestBody UserProfileUpdateReqVO reqVO) { + userService.updateUserProfile(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-password") + @Operation(summary = "修改用户个人密码") + public CommonResult updateUserProfilePassword(@Valid @RequestBody UserProfileUpdatePasswordReqVO reqVO) { + userService.updateUserPassword(getLoginUserId(), reqVO); + return success(true); + } + + @RequestMapping(value = "/update-avatar", + method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 + @Operation(summary = "上传用户个人头像") + public CommonResult updateUserAvatar(@RequestParam("avatarFile") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw exception(FILE_IS_EMPTY); + } + String avatar = userService.updateUserAvatar(getLoginUserId(), file.getInputStream()); + return success(avatar); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileRespVO.java new file mode 100644 index 0000000..4f7c71e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileRespVO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.profile; + +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSimpleRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Schema(description = "管理后台 - 用户个人中心信息 Response VO") +public class UserProfileRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1") + private String loginIp; + + @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime loginDate; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + + /** + * 所属角色 + */ + private List roles; + /** + * 所在部门 + */ + private DeptSimpleRespVO dept; + /** + * 所属岗位数组 + */ + private List posts; + /** + * 社交用户数组 + */ + private List socialUsers; + + @Schema(description = "社交用户") + @Data + public static class SocialUser { + + @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer type; + + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") + private String openid; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java new file mode 100644 index 0000000..e731208 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdatePasswordReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.profile; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 用户个人中心更新密码 Request VO") +@Data +public class UserProfileUpdatePasswordReqVO { + + @Schema(description = "旧密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "旧密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String oldPassword; + + @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "654321") + @NotEmpty(message = "新密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String newPassword; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java new file mode 100644 index 0000000..f1e54ac --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.profile; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Size; + + +@Schema(description = "管理后台 - 用户个人信息更新 Request VO") +@Data +public class UserProfileUpdateReqVO { + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过 30 个字符") + private String nickname; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Length(min = 11, max = 11, message = "手机号长度必须 11 位") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportExcelVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportExcelVO.java new file mode 100644 index 0000000..a360f1a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportExcelVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 用户 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +public class UserImportExcelVO { + + @ExcelProperty("登录名称") + private String username; + + @ExcelProperty("用户名称") + private String nickname; + + @ExcelProperty("部门编号") + private Long deptId; + + @ExcelProperty("用户邮箱") + private String email; + + @ExcelProperty("手机号码") + private String mobile; + + @ExcelProperty(value = "用户性别", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_SEX) + private Integer sex; + + @ExcelProperty(value = "账号状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportRespVO.java new file mode 100644 index 0000000..746c5af --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 用户导入 Response VO") +@Data +@Builder +public class UserImportRespVO { + + @Schema(description = "创建成功的用户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List createUsernames; + + @Schema(description = "更新成功的用户名数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List updateUsernames; + + @Schema(description = "导入失败的用户集合,key 为用户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) + private Map failureUsernames; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java new file mode 100644 index 0000000..525cb11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 用户分页 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UserPageReqVO extends PageParam { + + @Schema(description = "用户账号,模糊匹配", example = "yudao") + private String username; + + @Schema(description = "手机号码,模糊匹配", example = "yudao") + private String mobile; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "部门编号,同时筛选子部门", example = "1024") + private Long deptId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java new file mode 100644 index 0000000..2837318 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 用户信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class UserRespVO{ + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("用户编号") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @ExcelProperty("用户名称") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("用户昵称") + private String nickname; + + @Schema(description = "备注", example = "我是一个用户") + private String remark; + + @Schema(description = "部门ID", example = "我是一个用户") + private Long deptId; + @Schema(description = "部门名称", example = "IT 部") + @ExcelProperty("部门名称") + private String deptName; + + @Schema(description = "岗位编号数组", example = "1") + private Set postIds; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @ExcelProperty("用户邮箱") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @ExcelProperty("手机号码") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + @ExcelProperty(value = "用户性别", converter = DictConvert.class) + @DictFormat(DictTypeConstants.USER_SEX) + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "帐号状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1") + @ExcelProperty("最后登录IP") + private String loginIp; + + @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + @ExcelProperty("最后登录时间") + private LocalDateTime loginDate; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") + private LocalDateTime createTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java new file mode 100644 index 0000000..192e053 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.framework.operatelog.core.DeptParseFunction; +import cn.iocoder.yudao.module.system.framework.operatelog.core.PostParseFunction; +import cn.iocoder.yudao.module.system.framework.operatelog.core.SexParseFunction; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.mzt.logapi.starter.annotation.DiffLogField; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.*; +import java.util.Set; + +@Schema(description = "管理后台 - 用户创建/修改 Request VO") +@Data +public class UserSaveReqVO { + + @Schema(description = "用户编号", example = "1024") + private Long id; + + @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @NotBlank(message = "用户账号不能为空") + @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成") + @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") + @DiffLogField(name = "用户账号") + private String username; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过30个字符") + @DiffLogField(name = "用户昵称") + private String nickname; + + @Schema(description = "备注", example = "我是一个用户") + @DiffLogField(name = "备注") + private String remark; + + @Schema(description = "部门编号", example = "我是一个用户") + @DiffLogField(name = "部门", function = DeptParseFunction.NAME) + private Long deptId; + + @Schema(description = "岗位编号数组", example = "1") + @DiffLogField(name = "岗位", function = PostParseFunction.NAME) + private Set postIds; + + @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") + @Email(message = "邮箱格式不正确") + @Size(max = 50, message = "邮箱长度不能超过 50 个字符") + @DiffLogField(name = "用户邮箱") + private String email; + + @Schema(description = "手机号码", example = "15601691300") + @Mobile + @DiffLogField(name = "手机号码") + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + @DiffLogField(name = "用户性别", function = SexParseFunction.NAME) + private Integer sex; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + @DiffLogField(name = "用户头像") + private String avatar; + + // ========== 仅【创建】时,需要传递的字段 ========== + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + + @AssertTrue(message = "密码不能为空") + @JsonIgnore + public boolean isPasswordValid() { + return id != null // 修改时,不需要传递 + || (ObjectUtil.isAllNotEmpty(password)); // 新增时,必须都传递 password + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java new file mode 100644 index 0000000..6dac286 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 用户精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserSimpleRespVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String nickname; + + @Schema(description = "部门ID", example = "我是一个用户") + private Long deptId; + @Schema(description = "部门名称", example = "IT 部") + private String deptName; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java new file mode 100644 index 0000000..42d8c5d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdatePasswordReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户更新密码 Request VO") +@Data +public class UserUpdatePasswordReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long id; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java new file mode 100644 index 0000000..e5a113e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 用户更新状态 Request VO") +@Data +public class UserUpdateStatusReqVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "角色编号不能为空") + private Long id; + + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/AppDictDataController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/AppDictDataController.java new file mode 100644 index 0000000..8c4b97f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/AppDictDataController.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.controller.app.dict; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import cn.iocoder.yudao.module.system.service.dict.DictDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +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; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 字典数据") +@RestController +@RequestMapping("/system/dict-data") +@Validated +public class AppDictDataController { + + @Resource + private DictDataService dictDataService; + + @GetMapping("/type") + @Operation(summary = "根据字典类型查询字典数据信息") + @Parameter(name = "type", description = "字典类型", required = true, example = "common_status") + public CommonResult> getDictDataListByType(@RequestParam("type") String type) { + List list = dictDataService.getDictDataList( + CommonStatusEnum.ENABLE.getStatus(), type); + return success(BeanUtils.toBean(list, AppDictDataRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/vo/AppDictDataRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/vo/AppDictDataRespVO.java new file mode 100644 index 0000000..e2d1416 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/vo/AppDictDataRespVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.controller.app.dict.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Schema(description = "用户 App - 字典数据信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AppDictDataRespVO { + + @Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String label; + + @Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder") + private String value; + + @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex") + private String dictType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java new file mode 100644 index 0000000..54b0e87 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.controller.app.ip; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.system.controller.app.ip.vo.AppAreaNodeRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - 地区") +@RestController +@RequestMapping("/system/area") +@Validated +public class AppAreaController { + + @GetMapping("/tree") + @Operation(summary = "获得地区树") + public CommonResult> getAreaTree() { + Area area = AreaUtils.getArea(Area.ID_CHINA); + Assert.notNull(area, "获取不到中国"); + return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/vo/AppAreaNodeRespVO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/vo/AppAreaNodeRespVO.java new file mode 100644 index 0000000..f6ca4a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/vo/AppAreaNodeRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.controller.app.ip.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 地区节点 Response VO") +@Data +public class AppAreaNodeRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000") + private Integer id; + + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京") + private String name; + + /** + * 子节点 + */ + private List children; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/package-info.java new file mode 100644 index 0000000..659a909 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.system.controller; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java new file mode 100644 index 0000000..18463e7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.system.convert.auth; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import org.slf4j.LoggerFactory; + +import java.util.*; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; + +@Mapper +public interface AuthConvert { + + AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class); + + AuthLoginRespVO convert(OAuth2AccessTokenDO bean); + + default AuthPermissionInfoRespVO convert(AdminUserDO user, List roleList, List menuList) { + return AuthPermissionInfoRespVO.builder() + .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class)) + .roles(convertSet(roleList, RoleDO::getCode)) + // 权限标识信息 + .permissions(convertSet(menuList, MenuDO::getPermission)) + // 菜单树 + .menus(buildMenuTree(menuList)) + .build(); + } + + AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu); + + /** + * 将菜单列表,构建成菜单树 + * + * @param menuList 菜单列表 + * @return 菜单树 + */ + default List buildMenuTree(List menuList) { + if (CollUtil.isEmpty(menuList)) { + return Collections.emptyList(); + } + // 移除按钮 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType())); + // 排序,保证菜单的有序性 + menuList.sort(Comparator.comparing(MenuDO::getSort)); + + // 构建菜单树 + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map treeNodeMap = new LinkedHashMap<>(); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); + // 处理父子关系 + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { + // 获得父节点 + AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); + if (parentNode == null) { + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", + childNode.getId(), childNode.getParentId()); + return; + } + // 将自己添加到父节点中 + if (parentNode.getChildren() == null) { + parentNode.setChildren(new ArrayList<>()); + } + parentNode.getChildren().add(childNode); + }); + // 获得到所有的根节点 + return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId())); + } + + SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO); + + SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); + + SmsCodeUseReqDTO convert(AuthSmsLoginReqVO reqVO, Integer scene, String usedIp); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java new file mode 100644 index 0000000..24c9537 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.system.convert.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Mapper +public interface OAuth2OpenConvert { + + OAuth2OpenConvert INSTANCE = Mappers.getMapper(OAuth2OpenConvert.class); + + default OAuth2OpenAccessTokenRespVO convert(OAuth2AccessTokenDO bean) { + OAuth2OpenAccessTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenAccessTokenRespVO.class); + respVO.setTokenType(SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); + respVO.setExpiresIn(OAuth2Utils.getExpiresIn(bean.getExpiresTime())); + respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); + return respVO; + } + + default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) { + OAuth2OpenCheckTokenRespVO respVO = BeanUtils.toBean(bean, OAuth2OpenCheckTokenRespVO.class); + respVO.setExp(LocalDateTimeUtil.toEpochMilli(bean.getExpiresTime()) / 1000L); + respVO.setUserType(UserTypeEnum.ADMIN.getValue()); + return respVO; + } + + default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List approves) { + // 构建 scopes + List> scopes = new ArrayList<>(client.getScopes().size()); + Map approveMap = CollectionUtils.convertMap(approves, OAuth2ApproveDO::getScope); + client.getScopes().forEach(scope -> { + OAuth2ApproveDO approve = approveMap.get(scope); + scopes.add(new KeyValue<>(scope, approve != null ? approve.getApproved() : false)); + }); + // 拼接返回 + return new OAuth2OpenAuthorizeInfoRespVO( + new OAuth2OpenAuthorizeInfoRespVO.Client(client.getName(), client.getLogo()), scopes); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/package-info.java new file mode 100644 index 0000000..b1ce8e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.system.convert; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java new file mode 100644 index 0000000..9e679a2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/social/SocialUserConvert.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.convert.social; + +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface SocialUserConvert { + + SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class); + + @Mapping(source = "reqVO.type", target = "socialType") + SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java new file mode 100644 index 0000000..669954d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/tenant/TenantConvert.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.convert.tenant; + +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 租户 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface TenantConvert { + + TenantConvert INSTANCE = Mappers.getMapper(TenantConvert.class); + + default UserSaveReqVO convert02(TenantSaveReqVO bean) { + UserSaveReqVO reqVO = new UserSaveReqVO(); + reqVO.setUsername(bean.getUsername()); + reqVO.setPassword(bean.getPassword()); + reqVO.setNickname(bean.getContactName()).setMobile(bean.getContactMobile()); + return reqVO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/user/UserConvert.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/user/UserConvert.java new file mode 100644 index 0000000..b58be21 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/user/UserConvert.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.system.convert.user; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSimpleRespVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserRespVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface UserConvert { + + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + + default List convertList(List list, Map deptMap) { + return CollectionUtils.convertList(list, user -> convert(user, deptMap.get(user.getDeptId()))); + } + + default UserRespVO convert(AdminUserDO user, DeptDO dept) { + UserRespVO userVO = BeanUtils.toBean(user, UserRespVO.class); + if (dept != null) { + userVO.setDeptName(dept.getName()); + } + return userVO; + } + + default List convertSimpleList(List list, Map deptMap) { + return CollectionUtils.convertList(list, user -> { + UserSimpleRespVO userVO = BeanUtils.toBean(user, UserSimpleRespVO.class); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> userVO.setDeptName(dept.getName())); + return userVO; + }); + } + + default UserProfileRespVO convert(AdminUserDO user, List userRoles, + DeptDO dept, List posts, List socialUsers) { + UserProfileRespVO userVO = BeanUtils.toBean(user, UserProfileRespVO.class); + userVO.setRoles(BeanUtils.toBean(userRoles, RoleSimpleRespVO.class)); + userVO.setDept(BeanUtils.toBean(dept, DeptSimpleRespVO.class)); + userVO.setPosts(BeanUtils.toBean(posts, PostSimpleRespVO.class)); + userVO.setSocialUsers(BeanUtils.toBean(socialUsers, UserProfileRespVO.SocialUser.class)); + return userVO; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 0000000..8153487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java new file mode 100644 index 0000000..a59fa8b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 部门表 + * + * @author ruoyi + * @author 芋道源码 + */ +@TableName("system_dept") +@KeySequence("system_dept_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DeptDO extends TenantBaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 部门ID + */ + @TableId + private Long id; + /** + * 部门名称 + */ + private String name; + /** + * 父部门ID + * + * 关联 {@link #id} + */ + private Long parentId; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 负责人 + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long leaderUserId; + /** + * 联系电话 + */ + private String phone; + /** + * 邮箱 + */ + private String email; + /** + * 部门状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java new file mode 100644 index 0000000..3c97a9c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/PostDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 岗位表 + * + * @author ruoyi + */ +@TableName("system_post") +@KeySequence("system_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class PostDO extends BaseDO { + + /** + * 岗位序号 + */ + @TableId + private Long id; + /** + * 岗位名称 + */ + private String name; + /** + * 岗位编码 + */ + private String code; + /** + * 岗位排序 + */ + private Integer sort; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/UserPostDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/UserPostDO.java new file mode 100644 index 0000000..b2a4f52 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/UserPostDO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.dept; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户和岗位关联 + * + * @author ruoyi + */ +@TableName("system_user_post") +@KeySequence("system_user_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class UserPostDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 用户 ID + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long userId; + /** + * 角色 ID + * + * 关联 {@link PostDO#getId()} + */ + private Long postId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictDataDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictDataDO.java new file mode 100644 index 0000000..7e29447 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictDataDO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.dict; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据表 + * + * @author ruoyi + */ +@TableName("system_dict_data") +@KeySequence("system_dict_data_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class DictDataDO extends BaseDO { + + /** + * 字典数据编号 + */ + @TableId + private Long id; + /** + * 字典排序 + */ + private Integer sort; + /** + * 字典标签 + */ + private String label; + /** + * 字典值 + */ + private String value; + /** + * 字典类型 + * + * 冗余 {@link DictDataDO#getDictType()} + */ + private String dictType; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 颜色类型 + * + * 对应到 element-ui 为 default、primary、success、info、warning、danger + */ + private String colorType; + /** + * css 样式 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private String cssClass; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictTypeDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictTypeDO.java new file mode 100644 index 0000000..bff0a63 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dict/DictTypeDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.dict; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 字典类型表 + * + * @author ruoyi + */ +@TableName("system_dict_type") +@KeySequence("system_dict_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DictTypeDO extends BaseDO { + + /** + * 字典主键 + */ + @TableId + private Long id; + /** + * 字典名称 + */ + private String name; + /** + * 字典类型 + */ + private String type; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + + /** + * 删除时间 + */ + private LocalDateTime deletedTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/LoginLogDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/LoginLogDO.java new file mode 100644 index 0000000..d2fbcb9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/LoginLogDO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.logger; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 登录日志表 + * + * 注意,包括登录和登出两种行为 + * + * @author 芋道源码 + */ +@TableName("system_login_log") +@KeySequence("system_login_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class LoginLogDO extends BaseDO { + + /** + * 日志主键 + */ + private Long id; + /** + * 日志类型 + * + * 枚举 {@link LoginLogTypeEnum} + */ + private Integer logType; + /** + * 链路追踪编号 + */ + private String traceId; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 用户账号 + * + * 冗余,因为账号可以变更 + */ + private String username; + /** + * 登录结果 + * + * 枚举 {@link LoginResultEnum} + */ + private Integer result; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java new file mode 100644 index 0000000..3c7d171 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogDO.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.logger; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 操作日志表 + * + * @author 芋道源码 + */ +@TableName(value = "system_operate_log", autoResultMap = true) +@KeySequence("system_operate_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +public class OperateLogDO extends BaseDO { + + /** + * 日志主键 + */ + @TableId + private Long id; + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性 + */ + private Long userId; + /** + * 用户类型 + * + * 关联 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 操作模块类型 + */ + private String type; + /** + * 操作名 + */ + private String subType; + /** + * 操作模块业务编号 + */ + private Long bizId; + /** + * 日志内容,记录整个操作的明细 + * + * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + */ + private String action; + /** + * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ) + * + * 例如说,记录订单编号,{ orderId: "1"} + */ + private String extra; + + /** + * 请求方法名 + */ + private String requestMethod; + /** + * 请求地址 + */ + private String requestUrl; + /** + * 用户 IP + */ + private String userIp; + /** + * 浏览器 UA + */ + private String userAgent; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java new file mode 100644 index 0000000..0f95886 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.mail; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 邮箱账号 DO + * + * 用途:配置发送邮箱的账号 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_account", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +public class MailAccountDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 邮箱 + */ + private String mail; + + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * SMTP 服务器域名 + */ + private String host; + /** + * SMTP 服务器端口 + */ + private Integer port; + /** + * 是否开启 SSL + */ + private Boolean sslEnable; + /** + * 是否开启 STARTTLS + */ + private Boolean starttlsEnable; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java new file mode 100644 index 0000000..0d08c71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java @@ -0,0 +1,121 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.mail; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 邮箱日志 DO + * 记录每一次邮件的发送 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_log", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MailLogDO extends BaseDO implements Serializable { + + /** + * 日志编号,自增 + */ + private Long id; + + /** + * 用户编码 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 接收邮箱地址 + */ + private String toMail; + + /** + * 邮箱账号编号 + * + * 关联 {@link MailAccountDO#getId()} + */ + private Long accountId; + /** + * 发送邮箱地址 + * + * 冗余 {@link MailAccountDO#getMail()} + */ + private String fromMail; + + // ========= 模板相关字段 ========= + /** + * 模版编号 + * + * 关联 {@link MailTemplateDO#getId()} + */ + private Long templateId; + /** + * 模版编码 + * + * 冗余 {@link MailTemplateDO#getCode()} + */ + private String templateCode; + /** + * 模版发送人名称 + * + * 冗余 {@link MailTemplateDO#getNickname()} + */ + private String templateNickname; + /** + * 模版标题 + */ + private String templateTitle; + /** + * 模版内容 + * + * 基于 {@link MailTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 模版参数 + * + * 基于 {@link MailTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + + // ========= 发送相关字段 ========= + /** + * 发送状态 + * + * 枚举 {@link MailSendStatusEnum} + */ + private Integer sendStatus; + /** + * 发送时间 + */ + private LocalDateTime sendTime; + /** + * 发送返回的消息 ID + */ + private String sendMessageId; + /** + * 发送异常 + */ + private String sendException; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java new file mode 100644 index 0000000..f669b45 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.mail; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 邮件模版 DO + * + * @author wangjingyi + * @since 2022-03-21 + */ +@TableName(value = "system_mail_template", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +public class MailTemplateDO extends BaseDO { + + /** + * 主键 + */ + private Long id; + /** + * 模版名称 + */ + private String name; + /** + * 模版编号 + */ + private String code; + /** + * 发送的邮箱账号编号 + * + * 关联 {@link MailAccountDO#getId()} + */ + private Long accountId; + + /** + * 发送人名称 + */ + private String nickname; + /** + * 标题 + */ + private String title; + /** + * 内容 + */ + private String content; + /** + * 参数数组(自动根据内容生成) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java new file mode 100644 index 0000000..e7149d1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notice/NoticeDO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.notice; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.notice.NoticeTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 通知公告表 + * + * @author ruoyi + */ +@TableName("system_notice") +@KeySequence("system_notice_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class NoticeDO extends BaseDO { + + /** + * 公告ID + */ + private Long id; + /** + * 公告标题 + */ + private String title; + /** + * 公告类型 + * + * 枚举 {@link NoticeTypeEnum} + */ + private Integer type; + /** + * 公告内容 + */ + private String content; + /** + * 公告状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java new file mode 100644 index 0000000..e73badf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.notify; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.Map; + +/** + * 站内信 DO + * + * @author xrcoder + */ +@TableName(value = "system_notify_message", autoResultMap = true) +@KeySequence("system_notify_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NotifyMessageDO extends BaseDO { + + /** + * 站内信编号,自增 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 字段、或者 AdminUserDO 的 id 字段 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 模板相关字段 ========= + + /** + * 模版编号 + * + * 关联 {@link NotifyTemplateDO#getId()} + */ + private Long templateId; + /** + * 模版编码 + * + * 关联 {@link NotifyTemplateDO#getCode()} + */ + private String templateCode; + /** + * 模版类型 + * + * 冗余 {@link NotifyTemplateDO#getType()} + */ + private Integer templateType; + /** + * 模版发送人名称 + * + * 冗余 {@link NotifyTemplateDO#getNickname()} + */ + private String templateNickname; + /** + * 模版内容 + * + * 基于 {@link NotifyTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 模版参数 + * + * 基于 {@link NotifyTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + + // ========= 读取相关字段 ========= + + /** + * 是否已读 + */ + private Boolean readStatus; + /** + * 阅读时间 + */ + private LocalDateTime readTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyTemplateDO.java new file mode 100644 index 0000000..1bce809 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyTemplateDO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.notify; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 站内信模版 DO + * + * @author xrcoder + */ +@TableName(value = "system_notify_template", autoResultMap = true) +@KeySequence("system_notify_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NotifyTemplateDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 模版名称 + */ + private String name; + /** + * 模版编码 + */ + private String code; + /** + * 模版类型 + * + * 对应 system_notify_template_type 字典 + */ + private Integer type; + /** + * 发送人名称 + */ + private String nickname; + /** + * 模版内容 + */ + private String content; + /** + * 参数数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java new file mode 100644 index 0000000..ef235ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2AccessTokenDO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * OAuth2 访问令牌 DO + * + * 如下字段,暂时未使用,暂时不支持: + * user_name、authentication(用户信息) + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_access_token", autoResultMap = true) +@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2AccessTokenDO extends TenantBaseDO { + + /** + * 编号,数据库递增 + */ + @TableId + private Long id; + /** + * 访问令牌 + */ + private String accessToken; + /** + * 刷新令牌 + */ + private String refreshToken; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 用户信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map userInfo; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ApproveDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ApproveDO.java new file mode 100644 index 0000000..e07b0a0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ApproveDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * OAuth2 批准 DO + * + * 用户在 sso.vue 界面时,记录接受的 scope 列表 + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_approve", autoResultMap = true) +@KeySequence("system_oauth2_approve_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2ApproveDO extends BaseDO { + + /** + * 编号,数据库自增 + */ + @TableId + private Long id; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + private String scope; + /** + * 是否接受 + * + * true - 接受 + * false - 拒绝 + */ + private Boolean approved; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java new file mode 100644 index 0000000..721a42e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * OAuth2 客户端 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_client", autoResultMap = true) +@KeySequence("system_oauth2_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2ClientDO extends BaseDO { + + /** + * 编号,数据库自增 + * + * 由于 SQL Server 在存储 String 主键有点问题,所以暂时使用 Long 类型 + */ + @TableId + private Long id; + /** + * 客户端编号 + */ + private String clientId; + /** + * 客户端密钥 + */ + private String secret; + /** + * 应用名 + */ + private String name; + /** + * 应用图标 + */ + private String logo; + /** + * 应用描述 + */ + private String description; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 访问令牌的有效期 + */ + private Integer accessTokenValiditySeconds; + /** + * 刷新令牌的有效期 + */ + private Integer refreshTokenValiditySeconds; + /** + * 可重定向的 URI 地址 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List redirectUris; + /** + * 授权类型(模式) + * + * 枚举 {@link OAuth2GrantTypeEnum} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List authorizedGrantTypes; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 自动授权的 Scope + * + * code 授权时,如果 scope 在这个范围内,则自动通过 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List autoApproveScopes; + /** + * 权限 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List authorities; + /** + * 资源 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List resourceIds; + /** + * 附加信息,JSON 格式 + */ + private String additionalInformation; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2CodeDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2CodeDO.java new file mode 100644 index 0000000..fad9c16 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2CodeDO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * OAuth2 授权码 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_code", autoResultMap = true) +@KeySequence("system_oauth2_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class OAuth2CodeDO extends BaseDO { + + /** + * 编号,数据库递增 + */ + private Long id; + /** + * 授权码 + */ + private String code; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getClientId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 重定向地址 + */ + private String redirectUri; + /** + * 状态 + */ + private String state; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java new file mode 100644 index 0000000..70ddea2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2RefreshTokenDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * OAuth2 刷新令牌 + * + * @author 芋道源码 + */ +@TableName(value = "system_oauth2_refresh_token", autoResultMap = true) +// 由于 Oracle 的 SEQ 的名字长度有限制,所以就先用 system_oauth2_access_token_seq 吧,反正也没啥问题 +@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class OAuth2RefreshTokenDO extends BaseDO { + + /** + * 编号,数据库字典 + */ + private Long id; + /** + * 刷新令牌 + */ + private String refreshToken; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 客户端编号 + * + * 关联 {@link OAuth2ClientDO#getId()} + */ + private String clientId; + /** + * 授权范围 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List scopes; + /** + * 过期时间 + */ + private LocalDateTime expiresTime; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/MenuDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/MenuDO.java new file mode 100644 index 0000000..90d5833 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/MenuDO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单 DO + * + * @author ruoyi + */ +@TableName("system_menu") +@KeySequence("system_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class MenuDO extends BaseDO { + + /** + * 菜单编号 - 根节点 + */ + public static final Long ID_ROOT = 0L; + + /** + * 菜单编号 + */ + @TableId + private Long id; + /** + * 菜单名称 + */ + private String name; + /** + * 权限标识 + * + * 一般格式为:${系统}:${模块}:${操作} + * 例如说:system:admin:add,即 system 服务的添加管理员。 + * + * 当我们把该 MenuDO 赋予给角色后,意味着该角色有该资源: + * - 对于后端,配合 @PreAuthorize 注解,配置 API 接口需要该权限,从而对 API 接口进行权限控制。 + * - 对于前端,配合前端标签,配置按钮是否展示,避免用户没有该权限时,结果可以看到该操作。 + */ + private String permission; + /** + * 菜单类型 + * + * 枚举 {@link MenuTypeEnum} + */ + private Integer type; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 父菜单ID + */ + private Long parentId; + /** + * 路由地址 + * + * 如果 path 为 http(s) 时,则它是外链 + */ + private String path; + /** + * 菜单图标 + */ + private String icon; + /** + * 组件路径 + */ + private String component; + /** + * 组件名 + */ + private String componentName; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 是否可见 + * + * 只有菜单、目录使用 + * 当设置为 true 时,该菜单不会展示在侧边栏,但是路由还是存在。例如说,一些独立的编辑页面 /edit/1024 等等 + */ + private Boolean visible; + /** + * 是否缓存 + * + * 只有菜单、目录使用,否使用 Vue 路由的 keep-alive 特性 + * 注意:如果开启缓存,则必须填写 {@link #componentName} 属性,否则无法缓存 + */ + private Boolean keepAlive; + /** + * 是否总是显示 + * + * 如果为 false 时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单 + */ + private Boolean alwaysShow; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java new file mode 100644 index 0000000..ab0ec91 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +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 java.util.Set; + +/** + * 角色 DO + * + * @author ruoyi + */ +@TableName(value = "system_role", autoResultMap = true) +@KeySequence("system_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleDO extends TenantBaseDO { + + /** + * 角色ID + */ + @TableId + private Long id; + /** + * 角色名称 + */ + private String name; + /** + * 角色标识 + * + * 枚举 + */ + private String code; + /** + * 角色排序 + */ + private Integer sort; + /** + * 角色状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 角色类型 + * + * 枚举 {@link RoleTypeEnum} + */ + private Integer type; + /** + * 备注 + */ + private String remark; + + /** + * 数据范围 + * + * 枚举 {@link DataScopeEnum} + */ + private Integer dataScope; + /** + * 数据范围(指定部门数组) + * + * 适用于 {@link #dataScope} 的值为 {@link DataScopeEnum#DEPT_CUSTOM} 时 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set dataScopeDeptIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java new file mode 100644 index 0000000..4978b0e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 角色和菜单关联 + * + * @author ruoyi + */ +@TableName("system_role_menu") +@KeySequence("system_role_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleMenuDO extends TenantBaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 角色ID + */ + private Long roleId; + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/UserRoleDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/UserRoleDO.java new file mode 100644 index 0000000..0101840 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/UserRoleDO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户和角色关联 + * + * @author ruoyi + */ +@TableName("system_user_role") +@KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +public class UserRoleDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 用户 ID + */ + private Long userId; + /** + * 角色 ID + */ + private Long roleId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsChannelDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsChannelDO.java new file mode 100644 index 0000000..6ecb4f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsChannelDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.sms; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 短信渠道 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_channel", autoResultMap = true) +@KeySequence("system_sms_channel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsChannelDO extends BaseDO { + + /** + * 渠道编号 + */ + private Long id; + /** + * 短信签名 + */ + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + private String code; + /** + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 短信 API 的账号 + */ + private String apiKey; + /** + * 短信 API 的密钥 + */ + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java new file mode 100644 index 0000000..00aea3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsCodeDO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.sms; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 手机验证码 DO + * + * idx_mobile 索引:基于 {@link #mobile} 字段 + * + * @author 芋道源码 + */ +@TableName("system_sms_code") +@KeySequence("system_sms_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SmsCodeDO extends BaseDO { + + /** + * 编号 + */ + private Long id; + /** + * 手机号 + */ + private String mobile; + /** + * 验证码 + */ + private String code; + /** + * 发送场景 + * + * 枚举 {@link SmsCodeDO} + */ + private Integer scene; + /** + * 创建 IP + */ + private String createIp; + /** + * 今日发送的第几条 + */ + private Integer todayIndex; + /** + * 是否使用 + */ + private Boolean used; + /** + * 使用时间 + */ + private LocalDateTime usedTime; + /** + * 使用 IP + */ + private String usedIp; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsLogDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsLogDO.java new file mode 100644 index 0000000..9f250ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsLogDO.java @@ -0,0 +1,161 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.sms; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 短信日志 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_log", autoResultMap = true) +@KeySequence("system_sms_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SmsLogDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + // ========= 渠道相关字段 ========= + + /** + * 短信渠道编号 + * + * 关联 {@link SmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SmsChannelDO#getCode()} + */ + private String channelCode; + + // ========= 模板相关字段 ========= + + /** + * 模板编号 + * + * 关联 {@link SmsTemplateDO#getId()} + */ + private Long templateId; + /** + * 模板编码 + * + * 冗余 {@link SmsTemplateDO#getCode()} + */ + private String templateCode; + /** + * 短信类型 + * + * 冗余 {@link SmsTemplateDO#getType()} + */ + private Integer templateType; + /** + * 基于 {@link SmsTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 基于 {@link SmsTemplateDO#getParams()} 输入后的参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map templateParams; + /** + * 短信 API 的模板编号 + * + * 冗余 {@link SmsTemplateDO#getApiTemplateId()} + */ + private String apiTemplateId; + + // ========= 手机相关字段 ========= + + /** + * 手机号 + */ + private String mobile; + /** + * 用户编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 发送相关字段 ========= + + /** + * 发送状态 + * + * 枚举 {@link SmsSendStatusEnum} + */ + private Integer sendStatus; + /** + * 发送时间 + */ + private LocalDateTime sendTime; + /** + * 短信 API 发送结果的编码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiSendCode; + /** + * 短信 API 发送失败的提示 + */ + private String apiSendMsg; + /** + * 短信 API 发送返回的唯一请求 ID + * + * 用于和短信 API 进行定位于排错 + */ + private String apiRequestId; + /** + * 短信 API 发送返回的序号 + * + * 用于和短信 API 平台的发送记录关联 + */ + private String apiSerialNo; + + // ========= 接收相关字段 ========= + + /** + * 接收状态 + * + * 枚举 {@link SmsReceiveStatusEnum} + */ + private Integer receiveStatus; + /** + * 接收时间 + */ + private LocalDateTime receiveTime; + /** + * 短信 API 接收结果的编码 + */ + private String apiReceiveCode; + /** + * 短信 API 接收结果的提示 + */ + private String apiReceiveMsg; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsTemplateDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsTemplateDO.java new file mode 100644 index 0000000..e7f02c1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsTemplateDO.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.sms; + +import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * 短信模板 DO + * + * @author zzf + * @since 2021-01-25 + */ +@TableName(value = "system_sms_template", autoResultMap = true) +@KeySequence("system_sms_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsTemplateDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + // ========= 模板相关字段 ========= + + /** + * 短信类型 + * + * 枚举 {@link SmsTemplateTypeEnum} + */ + private Integer type; + /** + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 模板编码,保证唯一 + */ + private String code; + /** + * 模板名称 + */ + private String name; + /** + * 模板内容 + * + * 内容的参数,使用 {} 包括,例如说 {name} + */ + private String content; + /** + * 参数数组(自动根据内容生成) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 备注 + */ + private String remark; + /** + * 短信 API 的模板编号 + */ + private String apiTemplateId; + + // ========= 渠道相关字段 ========= + + /** + * 短信渠道编号 + * + * 关联 {@link SmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SmsChannelDO#getCode()} + */ + private String channelCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java new file mode 100644 index 0000000..71fc1bc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.social; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.xingyuv.jushauth.config.AuthConfig; +import lombok.*; + +/** + * 社交客户端 DO + * + * 对应 {@link AuthConfig} 配置,满足不同租户,有自己的客户端配置,实现社交(三方)登录 + * + * @author 芋道源码 + */ +@TableName(value = "system_social_client", autoResultMap = true) +@KeySequence("system_social_client_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialClientDO extends TenantBaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 应用名 + */ + private String name; + /** + * 社交类型 + * + * 枚举 {@link SocialTypeEnum} + */ + private Integer socialType; + /** + * 用户类型 + * + * 目的:不同用户类型,对应不同的小程序,需要自己的配置 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 客户端 id + */ + private String clientId; + /** + * 客户端 Secret + */ + private String clientSecret; + + /** + * 代理编号 + * + * 目前只有部分“社交类型”在使用: + * 1. 企业微信:对应授权方的网页应用 ID + */ + private String agentId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserBindDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserBindDO.java new file mode 100644 index 0000000..0f4e41f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserBindDO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.social; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 社交用户的绑定 + * 即 {@link SocialUserDO} 与 UserDO 的关联表 + * + * @author 芋道源码 + */ +@TableName(value = "system_social_user_bind", autoResultMap = true) +@KeySequence("system_social_user_bind_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserBindDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 关联的用户编号 + * + * 关联 UserDO 的编号 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 社交平台的用户编号 + * + * 关联 {@link SocialUserDO#getId()} + */ + private Long socialUserId; + /** + * 社交平台的类型 + * + * 冗余 {@link SocialUserDO#getType()} + */ + private Integer socialType; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserDO.java new file mode 100644 index 0000000..f3adf03 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialUserDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.social; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 社交(三方)用户 + * + * @author weir + */ +@TableName(value = "system_social_user", autoResultMap = true) +@KeySequence("system_social_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocialUserDO extends BaseDO { + + /** + * 自增主键 + */ + @TableId + private Long id; + /** + * 社交平台的类型 + * + * 枚举 {@link SocialTypeEnum} + */ + private Integer type; + + /** + * 社交 openid + */ + private String openid; + /** + * 社交 token + */ + private String token; + /** + * 原始 Token 数据,一般是 JSON 格式 + */ + private String rawTokenInfo; + + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户头像 + */ + private String avatar; + /** + * 原始用户数据,一般是 JSON 格式 + */ + private String rawUserInfo; + + /** + * 最后一次的认证 code + */ + private String code; + /** + * 最后一次的认证 state + */ + private String state; + +} + + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java new file mode 100644 index 0000000..0b78b7d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantDO.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.tenant; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 租户 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_tenant", autoResultMap = true) +@KeySequence("system_tenant_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TenantDO extends BaseDO { + + /** + * 套餐编号 - 系统 + */ + public static final Long PACKAGE_ID_SYSTEM = 0L; + + /** + * 租户编号,自增 + */ + private Long id; + /** + * 租户名,唯一 + */ + private String name; + /** + * 联系人的用户编号 + * + * 关联 {@link AdminUserDO#getId()} + */ + private Long contactUserId; + /** + * 联系人 + */ + private String contactName; + /** + * 联系手机 + */ + private String contactMobile; + /** + * 租户状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 绑定域名 + */ + private String website; + /** + * 租户套餐编号 + * + * 关联 {@link TenantPackageDO#getId()} + * 特殊逻辑:系统内置租户,不使用套餐,暂时使用 {@link #PACKAGE_ID_SYSTEM} 标识 + */ + private Long packageId; + /** + * 过期时间 + */ + private LocalDateTime expireTime; + /** + * 账号数量 + */ + private Integer accountCount; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java new file mode 100644 index 0000000..dba7569 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.tenant; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.Set; + +/** + * 租户套餐 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_tenant_package", autoResultMap = true) +@KeySequence("system_tenant_package_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TenantPackageDO extends BaseDO { + + /** + * 套餐编号,自增 + */ + private Long id; + /** + * 套餐名,唯一 + */ + private String name; + /** + * 租户套餐状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 关联的菜单编号 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set menuIds; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java new file mode 100644 index 0000000..84f54a3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.user; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import java.time.LocalDateTime; +import java.util.Set; + +/** + * 管理后台的用户 DO + * + * @author 芋道源码 + */ +@TableName(value = "system_users", autoResultMap = true) // 由于 SQL Server 的 system_user 是关键字,所以使用 system_users +@KeySequence("system_users_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AdminUserDO extends TenantBaseDO { + + /** + * 用户ID + */ + @TableId + private Long id; + /** + * 用户账号 + */ + private String username; + /** + * 加密后的密码 + * + * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐 + */ + private String password; + /** + * 用户昵称 + */ + private String nickname; + /** + * 备注 + */ + private String remark; + /** + * 部门 ID + */ + private Long deptId; + /** + * 岗位编号数组 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set postIds; + /** + * 用户邮箱 + */ + private String email; + /** + * 手机号码 + */ + private String mobile; + /** + * 用户性别 + * + * 枚举类 {@link SexEnum} + */ + private Integer sex; + /** + * 用户头像 + */ + private String avatar; + /** + * 帐号状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 最后登录IP + */ + private String loginIp; + /** + * 最后登录时间 + */ + private LocalDateTime loginDate; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java new file mode 100644 index 0000000..cc4f334 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.dal.mysql.dept; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DeptMapper extends BaseMapperX { + + default List selectList(DeptListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(DeptDO::getName, reqVO.getName()) + .eqIfPresent(DeptDO::getStatus, reqVO.getStatus())); + } + + default DeptDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(DeptDO::getParentId, parentId, DeptDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(DeptDO::getParentId, parentId); + } + + default List selectListByParentId(Collection parentIds) { + return selectList(DeptDO::getParentId, parentIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/PostMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/PostMapper.java new file mode 100644 index 0000000..e05c38c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/PostMapper.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.system.dal.mysql.dept; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface PostMapper extends BaseMapperX { + + default List selectList(Collection ids, Collection statuses) { + return selectList(new LambdaQueryWrapperX() + .inIfPresent(PostDO::getId, ids) + .inIfPresent(PostDO::getStatus, statuses)); + } + + default PageResult selectPage(PostPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(PostDO::getCode, reqVO.getCode()) + .likeIfPresent(PostDO::getName, reqVO.getName()) + .eqIfPresent(PostDO::getStatus, reqVO.getStatus()) + .orderByDesc(PostDO::getId)); + } + + default PostDO selectByName(String name) { + return selectOne(PostDO::getName, name); + } + + default PostDO selectByCode(String code) { + return selectOne(PostDO::getCode, code); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/UserPostMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/UserPostMapper.java new file mode 100644 index 0000000..addc67d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/UserPostMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.dal.mysql.dept; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface UserPostMapper extends BaseMapperX { + + default List selectListByUserId(Long userId) { + return selectList(UserPostDO::getUserId, userId); + } + + default void deleteByUserIdAndPostId(Long userId, Collection postIds) { + delete(new LambdaQueryWrapperX() + .eq(UserPostDO::getUserId, userId) + .in(UserPostDO::getPostId, postIds)); + } + + default List selectListByPostIds(Collection postIds) { + return selectList(UserPostDO::getPostId, postIds); + } + + default void deleteByUserId(Long userId) { + delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java new file mode 100644 index 0000000..87a05c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.dal.mysql.dict; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +@Mapper +public interface DictDataMapper extends BaseMapperX { + + default DictDataDO selectByDictTypeAndValue(String dictType, String value) { + return selectOne(DictDataDO::getDictType, dictType, DictDataDO::getValue, value); + } + + default DictDataDO selectByDictTypeAndLabel(String dictType, String label) { + return selectOne(DictDataDO::getDictType, dictType, DictDataDO::getLabel, label); + } + + default List selectByDictTypeAndValues(String dictType, Collection values) { + return selectList(new LambdaQueryWrapper().eq(DictDataDO::getDictType, dictType) + .in(DictDataDO::getValue, values)); + } + + default long selectCountByDictType(String dictType) { + return selectCount(DictDataDO::getDictType, dictType); + } + + default PageResult selectPage(DictDataPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DictDataDO::getLabel, reqVO.getLabel()) + .eqIfPresent(DictDataDO::getDictType, reqVO.getDictType()) + .eqIfPresent(DictDataDO::getStatus, reqVO.getStatus()) + .orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort))); + } + + default List selectListByStatusAndDictType(Integer status, String dictType) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(DictDataDO::getStatus, status) + .eqIfPresent(DictDataDO::getDictType, dictType)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java new file mode 100644 index 0000000..52393a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.dal.mysql.dict; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +import java.time.LocalDateTime; + +@Mapper +public interface DictTypeMapper extends BaseMapperX { + + default PageResult selectPage(DictTypePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DictTypeDO::getName, reqVO.getName()) + .likeIfPresent(DictTypeDO::getType, reqVO.getType()) + .eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DictTypeDO::getId)); + } + + default DictTypeDO selectByType(String type) { + return selectOne(DictTypeDO::getType, type); + } + + default DictTypeDO selectByName(String name) { + return selectOne(DictTypeDO::getName, name); + } + + @Update("UPDATE system_dict_type SET deleted = 1, deleted_time = #{deletedTime} WHERE id = #{id}") + void updateToDelete(@Param("id") Long id, @Param("deletedTime") LocalDateTime deletedTime); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java new file mode 100644 index 0000000..0cb47eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.dal.mysql.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface LoginLogMapper extends BaseMapperX { + + default PageResult selectPage(LoginLogPageReqVO reqVO) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .likeIfPresent(LoginLogDO::getUserIp, reqVO.getUserIp()) + .likeIfPresent(LoginLogDO::getUsername, reqVO.getUsername()) + .betweenIfPresent(LoginLogDO::getCreateTime, reqVO.getCreateTime()); + if (Boolean.TRUE.equals(reqVO.getStatus())) { + query.eq(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); + } else if (Boolean.FALSE.equals(reqVO.getStatus())) { + query.gt(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); + } + query.orderByDesc(LoginLogDO::getId); // 降序 + return selectPage(reqVO, query); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java new file mode 100644 index 0000000..14e308b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.dal.mysql.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OperateLogMapper extends BaseMapperX { + + default PageResult selectPage(OperateLogPageReqVO pageReqDTO) { + return selectPage(pageReqDTO, new LambdaQueryWrapperX() + .eqIfPresent(OperateLogDO::getUserId, pageReqDTO.getUserId()) + .eqIfPresent(OperateLogDO::getBizId, pageReqDTO.getBizId()) + .likeIfPresent(OperateLogDO::getType, pageReqDTO.getType()) + .likeIfPresent(OperateLogDO::getSubType, pageReqDTO.getSubType()) + .likeIfPresent(OperateLogDO::getAction, pageReqDTO.getAction()) + .betweenIfPresent(OperateLogDO::getCreateTime, pageReqDTO.getCreateTime()) + .orderByDesc(OperateLogDO::getId)); + } + + default PageResult selectPage(OperateLogPageReqDTO pageReqDTO) { + return selectPage(pageReqDTO, new LambdaQueryWrapperX() + .eqIfPresent(OperateLogDO::getType, pageReqDTO.getType()) + .eqIfPresent(OperateLogDO::getBizId, pageReqDTO.getBizId()) + .eqIfPresent(OperateLogDO::getUserId, pageReqDTO.getUserId()) + .orderByDesc(OperateLogDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java new file mode 100644 index 0000000..e14fc18 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailAccountMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.system.dal.mysql.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailAccountMapper extends BaseMapperX { + + default PageResult selectPage(MailAccountPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(MailAccountDO::getMail, pageReqVO.getMail()) + .likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java new file mode 100644 index 0000000..6b147cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.dal.mysql.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailLogMapper extends BaseMapperX { + + default PageResult selectPage(MailLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MailLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MailLogDO::getUserType, reqVO.getUserType()) + .likeIfPresent(MailLogDO::getToMail, reqVO.getToMail()) + .eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId()) + .eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId()) + .eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime()) + .orderByDesc(MailLogDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java new file mode 100644 index 0000000..f03aa4a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.mysql.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.Date; + +@Mapper +public interface MailTemplateMapper extends BaseMapperX { + + default PageResult selectPage(MailTemplatePageReqVO pageReqVO){ + return selectPage(pageReqVO , new LambdaQueryWrapperX() + .eqIfPresent(MailTemplateDO::getStatus, pageReqVO.getStatus()) + .likeIfPresent(MailTemplateDO::getCode, pageReqVO.getCode()) + .likeIfPresent(MailTemplateDO::getName, pageReqVO.getName()) + .eqIfPresent(MailTemplateDO::getAccountId, pageReqVO.getAccountId()) + .betweenIfPresent(MailTemplateDO::getCreateTime, pageReqVO.getCreateTime())); + } + + default Long selectCountByAccountId(Long accountId) { + return selectCount(MailTemplateDO::getAccountId, accountId); + } + + default MailTemplateDO selectByCode(String code) { + return selectOne(MailTemplateDO::getCode, code); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notice/NoticeMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notice/NoticeMapper.java new file mode 100644 index 0000000..67ff8db --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notice/NoticeMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.system.dal.mysql.notice; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface NoticeMapper extends BaseMapperX { + + default PageResult selectPage(NoticePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NoticeDO::getTitle, reqVO.getTitle()) + .eqIfPresent(NoticeDO::getStatus, reqVO.getStatus()) + .orderByDesc(NoticeDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java new file mode 100644 index 0000000..e9ce6d7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.dal.mysql.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +@Mapper +public interface NotifyMessageMapper extends BaseMapperX { + + default PageResult selectPage(NotifyMessagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId()) + .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType()) + .likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode()) + .eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType()) + .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(NotifyMessageDO::getId)); + } + + default PageResult selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) + .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .orderByDesc(NotifyMessageDO::getId)); + } + + default int updateListRead(Collection ids, Long userId, Integer userType) { + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + new LambdaQueryWrapperX() + .in(NotifyMessageDO::getId, ids) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .eq(NotifyMessageDO::getReadStatus, false)); + } + + default int updateListRead(Long userId, Integer userType) { + return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType) + .eq(NotifyMessageDO::getReadStatus, false)); + } + + default List selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) { + return selectList(new QueryWrapperX() // 由于要使用 limitN 语句,所以只能用 QueryWrapperX + .eq("user_id", userId) + .eq("user_type", userType) + .eq("read_status", false) + .orderByDesc("id").limitN(size)); + } + + default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) { + return selectCount(new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getReadStatus, false) + .eq(NotifyMessageDO::getUserId, userId) + .eq(NotifyMessageDO::getUserType, userType)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java new file mode 100644 index 0000000..1fcb8ee --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.dal.mysql.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface NotifyTemplateMapper extends BaseMapperX { + + default NotifyTemplateDO selectByCode(String code) { + return selectOne(NotifyTemplateDO::getCode, code); + } + + default PageResult selectPage(NotifyTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NotifyTemplateDO::getCode, reqVO.getCode()) + .likeIfPresent(NotifyTemplateDO::getName, reqVO.getName()) + .eqIfPresent(NotifyTemplateDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(NotifyTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(NotifyTemplateDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java new file mode 100644 index 0000000..81ca13f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import org.apache.ibatis.annotations.Mapper; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface OAuth2AccessTokenMapper extends BaseMapperX { + + @TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等 + default OAuth2AccessTokenDO selectByAccessToken(String accessToken) { + return selectOne(OAuth2AccessTokenDO::getAccessToken, accessToken); + } + + default List selectListByRefreshToken(String refreshToken) { + return selectList(OAuth2AccessTokenDO::getRefreshToken, refreshToken); + } + + default PageResult selectPage(OAuth2AccessTokenPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(OAuth2AccessTokenDO::getUserId, reqVO.getUserId()) + .eqIfPresent(OAuth2AccessTokenDO::getUserType, reqVO.getUserType()) + .likeIfPresent(OAuth2AccessTokenDO::getClientId, reqVO.getClientId()) + .gt(OAuth2AccessTokenDO::getExpiresTime, LocalDateTime.now()) + .orderByDesc(OAuth2AccessTokenDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ApproveMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ApproveMapper.java new file mode 100644 index 0000000..61a976f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ApproveMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface OAuth2ApproveMapper extends BaseMapperX { + + default int update(OAuth2ApproveDO updateObj) { + return update(updateObj, new LambdaQueryWrapperX() + .eq(OAuth2ApproveDO::getUserId, updateObj.getUserId()) + .eq(OAuth2ApproveDO::getUserType, updateObj.getUserType()) + .eq(OAuth2ApproveDO::getClientId, updateObj.getClientId()) + .eq(OAuth2ApproveDO::getScope, updateObj.getScope())); + } + + default List selectListByUserIdAndUserTypeAndClientId(Long userId, Integer userType, String clientId) { + return selectList(new LambdaQueryWrapperX() + .eq(OAuth2ApproveDO::getUserId, userId) + .eq(OAuth2ApproveDO::getUserType, userType) + .eq(OAuth2ApproveDO::getClientId, clientId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ClientMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ClientMapper.java new file mode 100644 index 0000000..e6012b0 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ClientMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import org.apache.ibatis.annotations.Mapper; + + +/** + * OAuth2 客户端 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface OAuth2ClientMapper extends BaseMapperX { + + default PageResult selectPage(OAuth2ClientPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(OAuth2ClientDO::getName, reqVO.getName()) + .eqIfPresent(OAuth2ClientDO::getStatus, reqVO.getStatus()) + .orderByDesc(OAuth2ClientDO::getId)); + } + + default OAuth2ClientDO selectByClientId(String clientId) { + return selectOne(OAuth2ClientDO::getClientId, clientId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2CodeMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2CodeMapper.java new file mode 100644 index 0000000..c85581c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2CodeMapper.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OAuth2CodeMapper extends BaseMapperX { + + default OAuth2CodeDO selectByCode(String code) { + return selectOne(OAuth2CodeDO::getCode, code); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java new file mode 100644 index 0000000..713be89 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OAuth2RefreshTokenMapper extends BaseMapperX { + + default int deleteByRefreshToken(String refreshToken) { + return delete(new LambdaQueryWrapperX() + .eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken)); + } + + default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) { + return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/package-info.java new file mode 100644 index 0000000..6ad304f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/package-info.java @@ -0,0 +1,9 @@ +/** + * DAL = Data Access Layer 数据访问层 + * 1. data object:数据对象 + * 2. redis:Redis 的 CRUD 操作 + * 3. mysql:MySQL 的 CRUD 操作 + * + * 其中,MySQL 的表以 system_ 作为前缀 + */ +package cn.iocoder.yudao.module.system.dal.mysql; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java new file mode 100644 index 0000000..8458faa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.dal.mysql.permission; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MenuMapper extends BaseMapperX { + + default MenuDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(MenuDO::getParentId, parentId, MenuDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(MenuDO::getParentId, parentId); + } + + default List selectList(MenuListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(MenuDO::getName, reqVO.getName()) + .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); + } + + default List selectListByPermission(String permission) { + return selectList(MenuDO::getPermission, permission); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java new file mode 100644 index 0000000..2e4da2b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.dal.mysql.permission; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface RoleMapper extends BaseMapperX { + + default PageResult selectPage(RolePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RoleDO::getName, reqVO.getName()) + .likeIfPresent(RoleDO::getCode, reqVO.getCode()) + .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(RoleDO::getSort)); + } + + default RoleDO selectByName(String name) { + return selectOne(RoleDO::getName, name); + } + + default RoleDO selectByCode(String code) { + return selectOne(RoleDO::getCode, code); + } + + default List selectListByStatus(@Nullable Collection statuses) { + return selectList(RoleDO::getStatus, statuses); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMenuMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMenuMapper.java new file mode 100644 index 0000000..02cb6b8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMenuMapper.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.dal.mysql.permission; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface RoleMenuMapper extends BaseMapperX { + + default List selectListByRoleId(Long roleId) { + return selectList(RoleMenuDO::getRoleId, roleId); + } + + default List selectListByRoleId(Collection roleIds) { + return selectList(RoleMenuDO::getRoleId, roleIds); + } + + default List selectListByMenuId(Long menuId) { + return selectList(RoleMenuDO::getMenuId, menuId); + } + + default void deleteListByRoleIdAndMenuIds(Long roleId, Collection menuIds) { + delete(new LambdaQueryWrapper() + .eq(RoleMenuDO::getRoleId, roleId) + .in(RoleMenuDO::getMenuId, menuIds)); + } + + default void deleteListByMenuId(Long menuId) { + delete(new LambdaQueryWrapper().eq(RoleMenuDO::getMenuId, menuId)); + } + + default void deleteListByRoleId(Long roleId) { + delete(new LambdaQueryWrapper().eq(RoleMenuDO::getRoleId, roleId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/UserRoleMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/UserRoleMapper.java new file mode 100644 index 0000000..12ff88a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/UserRoleMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.dal.mysql.permission; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface UserRoleMapper extends BaseMapperX { + + default List selectListByUserId(Long userId) { + return selectList(UserRoleDO::getUserId, userId); + } + + default void deleteListByUserIdAndRoleIdIds(Long userId, Collection roleIds) { + delete(new LambdaQueryWrapper() + .eq(UserRoleDO::getUserId, userId) + .in(UserRoleDO::getRoleId, roleIds)); + } + + default void deleteListByUserId(Long userId) { + delete(new LambdaQueryWrapper().eq(UserRoleDO::getUserId, userId)); + } + + default void deleteListByRoleId(Long roleId) { + delete(new LambdaQueryWrapper().eq(UserRoleDO::getRoleId, roleId)); + } + + default List selectListByRoleIds(Collection roleIds) { + return selectList(UserRoleDO::getRoleId, roleIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java new file mode 100644 index 0000000..1f356ed --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.dal.mysql.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsChannelMapper extends BaseMapperX { + + default PageResult selectPage(SmsChannelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SmsChannelDO::getSignature, reqVO.getSignature()) + .eqIfPresent(SmsChannelDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(SmsChannelDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SmsChannelDO::getId)); + } + + default SmsChannelDO selectByCode(String code) { + return selectOne(SmsChannelDO::getCode, code); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsCodeMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsCodeMapper.java new file mode 100644 index 0000000..599c1ab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsCodeMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.dal.mysql.sms; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsCodeMapper extends BaseMapperX { + + /** + * 获得手机号的最后一个手机验证码 + * + * @param mobile 手机号 + * @param scene 发送场景,选填 + * @param code 验证码 选填 + * @return 手机验证码 + */ + default SmsCodeDO selectLastByMobile(String mobile, String code, Integer scene) { + return selectOne(new QueryWrapperX() + .eq("mobile", mobile) + .eqIfPresent("scene", scene) + .eqIfPresent("code", code) + .orderByDesc("id") + .limitN(1)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java new file mode 100644 index 0000000..f238871 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.dal.mysql.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsLogMapper extends BaseMapperX { + + default PageResult selectPage(SmsLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SmsLogDO::getChannelId, reqVO.getChannelId()) + .eqIfPresent(SmsLogDO::getTemplateId, reqVO.getTemplateId()) + .likeIfPresent(SmsLogDO::getMobile, reqVO.getMobile()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(SmsLogDO::getSendTime, reqVO.getSendTime()) + .eqIfPresent(SmsLogDO::getReceiveStatus, reqVO.getReceiveStatus()) + .betweenIfPresent(SmsLogDO::getReceiveTime, reqVO.getReceiveTime()) + .orderByDesc(SmsLogDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java new file mode 100644 index 0000000..a9a1ebb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.dal.mysql.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsTemplateMapper extends BaseMapperX { + + default SmsTemplateDO selectByCode(String code) { + return selectOne(SmsTemplateDO::getCode, code); + } + + default PageResult selectPage(SmsTemplatePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SmsTemplateDO::getType, reqVO.getType()) + .eqIfPresent(SmsTemplateDO::getStatus, reqVO.getStatus()) + .likeIfPresent(SmsTemplateDO::getCode, reqVO.getCode()) + .likeIfPresent(SmsTemplateDO::getContent, reqVO.getContent()) + .likeIfPresent(SmsTemplateDO::getApiTemplateId, reqVO.getApiTemplateId()) + .eqIfPresent(SmsTemplateDO::getChannelId, reqVO.getChannelId()) + .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SmsTemplateDO::getId)); + } + + default Long selectCountByChannelId(Long channelId) { + return selectCount(SmsTemplateDO::getChannelId, channelId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialClientMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialClientMapper.java new file mode 100644 index 0000000..4ebe226 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialClientMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.dal.mysql.social; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SocialClientMapper extends BaseMapperX { + + default SocialClientDO selectBySocialTypeAndUserType(Integer socialType, Integer userType) { + return selectOne(SocialClientDO::getSocialType, socialType, + SocialClientDO::getUserType, userType); + } + + default PageResult selectPage(SocialClientPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(SocialClientDO::getName, reqVO.getName()) + .eqIfPresent(SocialClientDO::getSocialType, reqVO.getSocialType()) + .eqIfPresent(SocialClientDO::getUserType, reqVO.getUserType()) + .likeIfPresent(SocialClientDO::getClientId, reqVO.getClientId()) + .eqIfPresent(SocialClientDO::getStatus, reqVO.getStatus()) + .orderByDesc(SocialClientDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserBindMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserBindMapper.java new file mode 100644 index 0000000..d9957f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserBindMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.system.dal.mysql.social; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SocialUserBindMapper extends BaseMapperX { + + default void deleteByUserTypeAndUserIdAndSocialType(Integer userType, Long userId, Integer socialType) { + delete(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getSocialType, socialType)); + } + + default void deleteByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { + delete(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getSocialUserId, socialUserId)); + } + + default SocialUserBindDO selectByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { + return selectOne(SocialUserBindDO::getUserType, userType, + SocialUserBindDO::getSocialUserId, socialUserId); + } + + default List selectListByUserIdAndUserType(Long userId, Integer userType) { + return selectList(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getUserType, userType)); + } + + default SocialUserBindDO selectByUserIdAndUserTypeAndSocialType(Long userId, Integer userType, Integer socialType) { + return selectOne(new LambdaQueryWrapperX() + .eq(SocialUserBindDO::getUserId, userId) + .eq(SocialUserBindDO::getUserType, userType) + .eq(SocialUserBindDO::getSocialType, socialType)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserMapper.java new file mode 100644 index 0000000..af30ece --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.dal.mysql.social; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SocialUserMapper extends BaseMapperX { + + default SocialUserDO selectByTypeAndCodeAnState(Integer type, String code, String state) { + return selectOne(new LambdaQueryWrapper() + .eq(SocialUserDO::getType, type) + .eq(SocialUserDO::getCode, code) + .eq(SocialUserDO::getState, state)); + } + + default SocialUserDO selectByTypeAndOpenid(Integer type, String openid) { + return selectOne(new LambdaQueryWrapper() + .eq(SocialUserDO::getType, type) + .eq(SocialUserDO::getOpenid, openid)); + } + + default PageResult selectPage(SocialUserPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SocialUserDO::getType, reqVO.getType()) + .likeIfPresent(SocialUserDO::getNickname, reqVO.getNickname()) + .likeIfPresent(SocialUserDO::getOpenid, reqVO.getOpenid()) + .betweenIfPresent(SocialUserDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(SocialUserDO::getId)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java new file mode 100644 index 0000000..aaca016 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.system.dal.mysql.tenant; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 租户 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface TenantMapper extends BaseMapperX { + + default PageResult selectPage(TenantPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TenantDO::getName, reqVO.getName()) + .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) + .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) + .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(TenantDO::getId)); + } + + default TenantDO selectByName(String name) { + return selectOne(TenantDO::getName, name); + } + + default TenantDO selectByWebsite(String website) { + return selectOne(TenantDO::getWebsite, website); + } + + default Long selectCountByPackageId(Long packageId) { + return selectCount(TenantDO::getPackageId, packageId); + } + + default List selectListByPackageId(Long packageId) { + return selectList(TenantDO::getPackageId, packageId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java new file mode 100644 index 0000000..e8a41c7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.dal.mysql.tenant; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 租户套餐 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface TenantPackageMapper extends BaseMapperX { + + default PageResult selectPage(TenantPackagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(TenantPackageDO::getName, reqVO.getName()) + .eqIfPresent(TenantPackageDO::getStatus, reqVO.getStatus()) + .likeIfPresent(TenantPackageDO::getRemark, reqVO.getRemark()) + .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(TenantPackageDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(TenantPackageDO::getStatus, status); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java new file mode 100644 index 0000000..75bf3fa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.dal.mysql.user; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface AdminUserMapper extends BaseMapperX { + + default AdminUserDO selectByUsername(String username) { + return selectOne(AdminUserDO::getUsername, username); + } + + default AdminUserDO selectByEmail(String email) { + return selectOne(AdminUserDO::getEmail, email); + } + + default AdminUserDO selectByMobile(String mobile) { + return selectOne(AdminUserDO::getMobile, mobile); + } + + default PageResult selectPage(UserPageReqVO reqVO, Collection deptIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername()) + .likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile()) + .eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime()) + .inIfPresent(AdminUserDO::getDeptId, deptIds) + .orderByDesc(AdminUserDO::getId)); + } + + default List selectListByNickname(String nickname) { + return selectList(new LambdaQueryWrapperX().like(AdminUserDO::getNickname, nickname)); + } + + default List selectListByStatus(Integer status) { + return selectList(AdminUserDO::getStatus, status); + } + + default List selectListByDeptIds(Collection deptIds) { + return selectList(AdminUserDO::getDeptId, deptIds); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java new file mode 100644 index 0000000..8b9e768 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.system.dal.redis; + +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; + +/** + * System Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 指定部门的所有子部门编号数组的缓存 + *

+ * KEY 格式:dept_children_ids:{id} + * VALUE 数据类型:String 子部门编号集合 + */ + String DEPT_CHILDREN_ID_LIST = "dept_children_ids"; + + /** + * 角色的缓存 + *

+ * KEY 格式:role:{id} + * VALUE 数据类型:String 角色信息 + */ + String ROLE = "role"; + + /** + * 用户拥有的角色编号的缓存 + *

+ * KEY 格式:user_role_ids:{userId} + * VALUE 数据类型:String 角色编号集合 + */ + String USER_ROLE_ID_LIST = "user_role_ids"; + + /** + * 拥有指定菜单的角色编号的缓存 + *

+ * KEY 格式:menu_role_ids:{menuId} + * VALUE 数据类型:String 角色编号集合 + */ + String MENU_ROLE_ID_LIST = "menu_role_ids"; + + /** + * 拥有权限对应的菜单编号数组的缓存 + *

+ * KEY 格式:permission_menu_ids:{permission} + * VALUE 数据类型:String 菜单编号数组 + */ + String PERMISSION_MENU_ID_LIST = "permission_menu_ids"; + + /** + * OAuth2 客户端的缓存 + *

+ * KEY 格式:oauth_client:{id} + * VALUE 数据类型:String 客户端信息 + */ + String OAUTH_CLIENT = "oauth_client"; + + /** + * 访问令牌的缓存 + *

+ * KEY 格式:oauth2_access_token:{token} + * VALUE 数据类型:String 访问令牌信息 {@link OAuth2AccessTokenDO} + *

+ * 由于动态过期时间,使用 RedisTemplate 操作 + */ + String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s"; + + /** + * 站内信模版的缓存 + *

+ * KEY 格式:notify_template:{code} + * VALUE 数据格式:String 模版信息 + */ + String NOTIFY_TEMPLATE = "notify_template"; + + /** + * 邮件账号的缓存 + *

+ * KEY 格式:mail_account:{id} + * VALUE 数据格式:String 账号信息 + */ + String MAIL_ACCOUNT = "mail_account"; + + /** + * 邮件模版的缓存 + *

+ * KEY 格式:mail_template:{code} + * VALUE 数据格式:String 模版信息 + */ + String MAIL_TEMPLATE = "mail_template"; + + /** + * 短信模版的缓存 + *

+ * KEY 格式:sms_template:{id} + * VALUE 数据格式:String 模版信息 + */ + String SMS_TEMPLATE = "sms_template"; +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java new file mode 100644 index 0000000..7827dfa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.system.dal.redis.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN; + +/** + * {@link OAuth2AccessTokenDO} 的 RedisDAO + * + * @author 芋道源码 + */ +@Repository +public class OAuth2AccessTokenRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public OAuth2AccessTokenDO get(String accessToken) { + String redisKey = formatKey(accessToken); + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class); + } + + public void set(OAuth2AccessTokenDO accessTokenDO) { + String redisKey = formatKey(accessTokenDO.getAccessToken()); + // 清理多余字段,避免缓存 + accessTokenDO.setUpdater(null).setUpdateTime(null).setCreateTime(null).setCreator(null).setDeleted(null); + long time = LocalDateTimeUtil.between(LocalDateTime.now(), accessTokenDO.getExpiresTime(), ChronoUnit.SECONDS); + if (time > 0) { + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(accessTokenDO), time, TimeUnit.SECONDS); + } + } + + public void delete(String accessToken) { + String redisKey = formatKey(accessToken); + stringRedisTemplate.delete(redisKey); + } + + public void deleteList(Collection accessTokens) { + List redisKeys = CollectionUtils.convertList(accessTokens, OAuth2AccessTokenRedisDAO::formatKey); + stringRedisTemplate.delete(redisKeys); + } + + private static String formatKey(String accessToken) { + return String.format(OAUTH2_ACCESS_TOKEN, accessToken); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/config/YudaoCaptchaConfiguration.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/config/YudaoCaptchaConfiguration.java new file mode 100644 index 0000000..23c8d78 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/config/YudaoCaptchaConfiguration.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.framework.captcha.config; + +import cn.iocoder.yudao.module.system.framework.captcha.core.RedisCaptchaServiceImpl; +import com.xingyuv.captcha.properties.AjCaptchaProperties; +import com.xingyuv.captcha.service.CaptchaCacheService; +import com.xingyuv.captcha.service.impl.CaptchaServiceFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * 验证码的配置类 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class YudaoCaptchaConfiguration { + + @Bean + public CaptchaCacheService captchaCacheService(AjCaptchaProperties config, + StringRedisTemplate stringRedisTemplate) { + CaptchaCacheService captchaCacheService = CaptchaServiceFactory.getCache(config.getCacheType().name()); + if (captchaCacheService instanceof RedisCaptchaServiceImpl) { + ((RedisCaptchaServiceImpl) captchaCacheService).setStringRedisTemplate(stringRedisTemplate); + } + return captchaCacheService; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/RedisCaptchaServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/RedisCaptchaServiceImpl.java new file mode 100644 index 0000000..d69b88c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/core/RedisCaptchaServiceImpl.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.framework.captcha.core; + +import com.xingyuv.captcha.service.CaptchaCacheService; +import lombok.Setter; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * 基于 Redis 实现验证码的存储 + * + * @author 星语 + */ +@Setter +public class RedisCaptchaServiceImpl implements CaptchaCacheService { + + private StringRedisTemplate stringRedisTemplate; + + @Override + public String type() { + return "redis"; + } + + @Override + public void set(String key, String value, long expiresInSeconds) { + stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS); + } + + @Override + public boolean exists(String key) { + return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key)); + } + + @Override + public void delete(String key) { + stringRedisTemplate.delete(key); + } + + @Override + public String get(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + @Override + public Long increment(String key, long val) { + return stringRedisTemplate.opsForValue().increment(key,val); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/package-info.java new file mode 100644 index 0000000..a94be21 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/captcha/package-info.java @@ -0,0 +1,8 @@ +/** + * 验证码拓展 + * + * 基于 aj-captcha 实现滑块验证码,文档:https://ajcaptcha.beliefteam.cn/captcha-doc/ + * + * @author 星语 + */ +package cn.iocoder.yudao.module.system.framework.captcha; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/config/DataPermissionConfiguration.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/config/DataPermissionConfiguration.java new file mode 100644 index 0000000..136866c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/config/DataPermissionConfiguration.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.framework.datapermission.config; + +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * system 模块的数据权限 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class DataPermissionConfiguration { + + @Bean + public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() { + return rule -> { + // dept + rule.addDeptColumn(AdminUserDO.class); + rule.addDeptColumn(DeptDO.class, "id"); + // user + rule.addUserColumn(AdminUserDO.class, "id"); + }; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/package-info.java new file mode 100644 index 0000000..a666845 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/datapermission/package-info.java @@ -0,0 +1,4 @@ +/** + * system 模块的数据权限配置 + */ +package cn.iocoder.yudao.module.system.framework.datapermission; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java new file mode 100644 index 0000000..a883217 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 管理员名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class AdminUserParseFunction implements IParseFunction { + + public static final String NAME = "getAdminUserById"; + + @Resource + private AdminUserService adminUserService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取用户信息 + AdminUserDO user = adminUserService.getUser(Convert.toLong(value)); + if (user == null) { + log.warn("[apply][获取用户{{}}为空", value); + return ""; + } + // 返回格式 芋道源码(13888888888) + String nickname = user.getNickname(); + if (StrUtil.isEmpty(user.getMobile())) { + return nickname; + } + return StrUtil.format("{}({})", nickname, user.getMobile()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java new file mode 100644 index 0000000..f2b9089 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 地名的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class AreaParseFunction implements IParseFunction { + + public static final String NAME = "getArea"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return AreaUtils.format(Convert.toInt(value)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java new file mode 100644 index 0000000..106dfcb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 是否类型的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class BooleanParseFunction implements IParseFunction { + + public static final String NAME = "getBoolean"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java new file mode 100644 index 0000000..e2a6fdc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 部门名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class DeptParseFunction implements IParseFunction { + + public static final String NAME = "getDeptById"; + + @Resource + private DeptService deptService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取部门信息 + DeptDO dept = deptService.getDept(Convert.toLong(value)); + if (dept == null) { + log.warn("[apply][获取部门{{}}为空", value); + return ""; + } + return dept.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/PostParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/PostParseFunction.java new file mode 100644 index 0000000..40a13b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/PostParseFunction.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 岗位名字的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Slf4j +@Component +public class PostParseFunction implements IParseFunction { + + public static final String NAME = "getPostById"; + + @Resource + private PostService postService; + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + + // 获取岗位信息 + PostDO post = postService.getPost(Convert.toLong(value)); + if (post == null) { + log.warn("[apply][获取岗位{{}}为空", value); + return ""; + } + return post.getName(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java new file mode 100644 index 0000000..d510f69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.framework.operatelog.core; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import com.mzt.logapi.service.IParseFunction; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 行业的 {@link IParseFunction} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class SexParseFunction implements IParseFunction { + + public static final String NAME = "getSex"; + + @Override + public boolean executeBefore() { + return true; // 先转换值后对比 + } + + @Override + public String functionName() { + return NAME; + } + + @Override + public String apply(Object value) { + if (StrUtil.isEmptyIfStr(value)) { + return ""; + } + return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java new file mode 100644 index 0000000..c7f1248 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位文件,避免文件夹缩进 + */ +package cn.iocoder.yudao.module.system.framework.operatelog; \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/package-info.java new file mode 100644 index 0000000..4b84406 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 system 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.system.framework; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsCodeProperties.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsCodeProperties.java new file mode 100644 index 0000000..4f3a50c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsCodeProperties.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.framework.sms.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import java.time.Duration; + +@ConfigurationProperties(prefix = "yudao.sms-code") +@Validated +@Data +public class SmsCodeProperties { + + /** + * 过期时间 + */ + @NotNull(message = "过期时间不能为空") + private Duration expireTimes; + /** + * 短信发送频率 + */ + @NotNull(message = "短信发送频率不能为空") + private Duration sendFrequency; + /** + * 每日发送最大数量 + */ + @NotNull(message = "每日发送最大数量不能为空") + private Integer sendMaximumQuantityPerDay; + /** + * 验证码最小值 + */ + @NotNull(message = "验证码最小值不能为空") + private Integer beginCode; + /** + * 验证码最大值 + */ + @NotNull(message = "验证码最大值不能为空") + private Integer endCode; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsConfiguration.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsConfiguration.java new file mode 100644 index 0000000..eb34775 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/config/SmsConfiguration.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.framework.sms.config; + +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.module.system.framework.sms.core.client.impl.SmsClientFactoryImpl; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 短信配置类,包括短信客户端、短信验证码两部分 + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +@EnableConfigurationProperties(SmsCodeProperties.class) +public class SmsConfiguration { + + @Bean + public SmsClientFactory smsClientFactory() { + return new SmsClientFactoryImpl(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClient.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClient.java new file mode 100644 index 0000000..4622466 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClient.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; + +import java.util.List; + +/** + * 短信客户端,用于对接各短信平台的 SDK,实现短信发送等功能 + * + * @author zzf + * @since 2021/1/25 14:14 + */ +public interface SmsClient { + + /** + * 获得渠道编号 + * + * @return 渠道编号 + */ + Long getId(); + + /** + * 发送消息 + * + * @param logId 日志编号 + * @param mobile 手机号 + * @param apiTemplateId 短信 API 的模板编号 + * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 + * @return 短信发送结果 + */ + SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable; + + /** + * 解析接收短信的接收结果 + * + * @param text 结果 + * @return 结果内容 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常 + */ + List parseSmsReceiveStatus(String text) throws Throwable; + + /** + * 查询指定的短信模板 + * + * @param apiTemplateId 短信 API 的模板编号 + * @return 短信模板 + */ + SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClientFactory.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClientFactory.java new file mode 100644 index 0000000..a113317 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/SmsClientFactory.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client; + +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; + +/** + * 短信客户端的工厂接口 + * + * @author zzf + * @since 2021/1/28 14:01 + */ +public interface SmsClientFactory { + + /** + * 获得短信 Client + * + * @param channelId 渠道编号 + * @return 短信 Client + */ + SmsClient getSmsClient(Long channelId); + + /** + * 获得短信 Client + * + * @param channelCode 渠道编码 + * @return 短信 Client + */ + SmsClient getSmsClient(String channelCode); + + /** + * 创建短信 Client + * + * @param properties 配置对象 + */ + void createOrUpdateSmsClient(SmsChannelProperties properties); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java new file mode 100644 index 0000000..c90a33e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 消息接收 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsReceiveRespDTO { + + /** + * 是否接收成功 + */ + private Boolean success; + /** + * API 接收结果的编码 + */ + private String errorCode; + /** + * API 接收结果的说明 + */ + private String errorMsg; + + /** + * 手机号 + */ + private String mobile; + /** + * 用户接收时间 + */ + private LocalDateTime receiveTime; + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + /** + * 短信日志编号 + * + * 对应 SysSmsLogDO 的编号 + */ + private Long logId; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsSendRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsSendRespDTO.java new file mode 100644 index 0000000..9f3094b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsSendRespDTO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.dto; + +import lombok.Data; + +/** + * 短信发送 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsSendRespDTO { + + /** + * 是否成功 + */ + private Boolean success; + + /** + * API 请求编号 + */ + private String apiRequestId; + + // ==================== 成功时字段 ==================== + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + + // ==================== 失败时字段 ==================== + + /** + * API 返回错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiCode; + /** + * API 返回提示 + */ + private String apiMsg; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java new file mode 100644 index 0000000..38a43aa --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/dto/SmsTemplateRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.dto; + +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import lombok.Data; + +/** + * 短信模板 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsTemplateRespDTO { + + /** + * 模板编号 + */ + private String id; + /** + * 短信内容 + */ + private String content; + /** + * 审核状态 + * + * 枚举 {@link SmsTemplateAuditStatusEnum} + */ + private Integer auditStatus; + /** + * 审核未通过的理由 + */ + private String auditReason; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AbstractSmsClient.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AbstractSmsClient.java new file mode 100644 index 0000000..3b6e0eb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AbstractSmsClient.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; + +/** + * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码 + * + * @author zzf + * @since 2021/2/1 9:28 + */ +@Slf4j +public abstract class AbstractSmsClient implements SmsClient { + + /** + * 短信渠道配置 + */ + protected volatile SmsChannelProperties properties; + + public AbstractSmsClient(SmsChannelProperties properties) { + this.properties = properties; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.debug("[init][配置({}) 初始化完成]", properties); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + public final void refresh(SmsChannelProperties properties) { + // 判断是否更新 + if (properties.equals(this.properties)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", properties); + this.properties = properties; + // 初始化 + this.init(); + } + + @Override + public Long getId() { + return properties.getId(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java new file mode 100644 index 0000000..7d01e6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java @@ -0,0 +1,182 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 阿里短信客户端的实现类 + * + * @author zzf + * @since 2021/1/25 14:17 + */ +@Slf4j +public class AliyunSmsClient extends AbstractSmsClient { + + /** + * 调用成功 code + */ + public static final String API_CODE_SUCCESS = "OK"; + + /** + * REGION, 使用杭州 + */ + private static final String ENDPOINT = "cn-hangzhou"; + + /** + * 阿里云客户端 + */ + private volatile IAcsClient client; + + public AliyunSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + protected void doInit() { + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); + client = new DefaultAcsClient(profile); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId, + List> templateParams) throws Throwable { + // 构建请求 + SendSmsRequest request = new SendSmsRequest(); + request.setPhoneNumbers(mobile); + request.setSignName(properties.getSignature()); + request.setTemplateCode(apiTemplateId); + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); + request.setOutId(String.valueOf(sendLogId)); + // 执行请求 + SendSmsResponse response = client.getAcsResponse(request); + return new SmsSendRespDTO().setSuccess(Objects.equals(response.getCode(), API_CODE_SUCCESS)).setSerialNo(response.getBizId()) + .setApiRequestId(response.getRequestId()).setApiCode(response.getCode()).setApiMsg(response.getMessage()); + } + + @Override + public List parseSmsReceiveStatus(String text) { + List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(status.getSuccess()) + .setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg()) + .setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime()) + .setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()))); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 构建请求 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); + request.setTemplateCode(apiTemplateId); + // 执行请求 + QuerySmsTemplateResponse response = client.getAcsResponse(request); + if (response.getTemplateStatus() == null) { + return null; + } + return new SmsTemplateRespDTO().setId(response.getTemplateCode()).setContent(response.getTemplateContent()) + .setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason()); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(Integer templateStatus) { + switch (templateStatus) { + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + /** + * 短信接收状态 + * + * 参见 文档 + * + * @author 芋道源码 + */ + @Data + public static class SmsReceiveStatus { + + /** + * 手机号 + */ + @JsonProperty("phone_number") + private String phoneNumber; + /** + * 发送时间 + */ + @JsonProperty("send_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime sendTime; + /** + * 状态报告时间 + */ + @JsonProperty("report_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime reportTime; + /** + * 是否接收成功 + */ + private Boolean success; + /** + * 状态报告说明 + */ + @JsonProperty("err_msg") + private String errMsg; + /** + * 状态报告编码 + */ + @JsonProperty("err_code") + private String errCode; + /** + * 发送序列号 + */ + @JsonProperty("biz_id") + private String bizId; + /** + * 用户序列号 + * + * 这里我们传递的是 SysSmsLogDO 的日志编号 + */ + @JsonProperty("out_id") + private String outId; + /** + * 短信长度,例如说 1、2、3 + * + * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送 + */ + @JsonProperty("sms_size") + private Integer smsSize; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java new file mode 100644 index 0000000..e9fcc6c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/DebugDingTalkSmsClient.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 基于钉钉 WebHook 实现的调试的短信客户端实现类 + * + * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。 + * + * @author 芋道源码 + */ +public class DebugDingTalkSmsClient extends AbstractSmsClient { + + public DebugDingTalkSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + protected void doInit() { + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + // 构建请求 + String url = buildUrl("robot/send"); + Map params = new HashMap<>(); + params.put("msgtype", "text"); + String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s", + mobile, sendLogId, MapUtils.convertMap(templateParams)); + params.put("text", MapUtil.builder().put("content", content).build()); + // 执行请求 + String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); + // 解析结果 + Map responseObj = JsonUtils.parseObject(responseText, Map.class); + String errorCode = MapUtil.getStr(responseObj, "errcode"); + return new SmsSendRespDTO().setSuccess(Objects.equals(errorCode, "0")).setSerialNo(StrUtil.uuid()) + .setApiCode(errorCode).setApiMsg(MapUtil.getStr(responseObj, "errorMsg")); + } + + /** + * 构建请求地址 + * + * 参见 文档 + * + * @param path 请求路径 + * @return 请求地址 + */ + @SuppressWarnings("SameParameterValue") + private String buildUrl(String path) { + // 生成 timestamp + long timestamp = System.currentTimeMillis(); + // 生成 sign + String secret = properties.getApiSecret(); + String stringToSign = timestamp + "\n" + secret; + byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign); + String sign = Base64.encode(signData); + // 构建最终 URL + return String.format("https://oapi.dingtalk.com/%s?access_token=%s×tamp=%d&sign=%s", + path, properties.getApiKey(), timestamp, sign); + } + + @Override + public List parseSmsReceiveStatus(String text) { + throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) { + return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("") + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(""); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java new file mode 100644 index 0000000..94fe88d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 短信客户端工厂接口 + * + * @author zzf + */ +@Validated +@Slf4j +public class SmsClientFactoryImpl implements SmsClientFactory { + + /** + * 短信客户端 Map + * key:渠道编号,使用 {@link SmsChannelProperties#getId()} + */ + private final ConcurrentMap channelIdClients = new ConcurrentHashMap<>(); + + /** + * 短信客户端 Map + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} + * + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} + */ + private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); + + public SmsClientFactoryImpl() { + // 初始化 channelCodeClients 集合 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { + // 创建一个空的 SmsChannelProperties 对象 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()) + .setApiKey("default default").setApiSecret("default"); + // 创建 Sms 客户端 + AbstractSmsClient smsClient = createSmsClient(properties); + channelCodeClients.put(channel.getCode(), smsClient); + }); + } + + @Override + public SmsClient getSmsClient(Long channelId) { + return channelIdClients.get(channelId); + } + + @Override + public SmsClient getSmsClient(String channelCode) { + return channelCodeClients.get(channelCode); + } + + @Override + public void createOrUpdateSmsClient(SmsChannelProperties properties) { + AbstractSmsClient client = channelIdClients.get(properties.getId()); + if (client == null) { + client = this.createSmsClient(properties); + client.init(); + channelIdClients.put(client.getId(), client); + } else { + client.refresh(properties); + } + } + + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) { + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode()); + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum)); + // 创建客户端 + switch (channelEnum) { + case ALIYUN: return new AliyunSmsClient(properties); + case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties); + case TENCENT: return new TencentSmsClient(properties); + } + // 创建失败,错误日志 + 抛出异常 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties); + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClient.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClient.java new file mode 100644 index 0000000..dc238be --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClient.java @@ -0,0 +1,218 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.*; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 腾讯云短信功能实现 + * + * 参见 文档 + * + * @author shiwp + */ +public class TencentSmsClient extends AbstractSmsClient { + + /** + * 调用成功 code + */ + public static final String API_CODE_SUCCESS = "Ok"; + + /** + * REGION,使用南京 + */ + private static final String ENDPOINT = "ap-nanjing"; + + /** + * 是否国际/港澳台短信: + * + * 0:表示国内短信。 + * 1:表示国际/港澳台短信。 + */ + private static final long INTERNATIONAL_CHINA = 0L; + + private SmsClient client; + + public TencentSmsClient(SmsChannelProperties properties) { + super(properties); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + validateSdkAppId(properties); + } + + @Override + protected void doInit() { + // 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey + Credential credential = new Credential(getApiKey(), properties.getApiSecret()); + client = new SmsClient(credential, ENDPOINT); + } + + /** + * 参数校验腾讯云的 SDK AppId + * + * 原因是:腾讯云发放短信的时候,需要额外的参数 sdkAppId + * + * 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。 + * + * @param properties 配置 + */ + private static void validateSdkAppId(SmsChannelProperties properties) { + String combineKey = properties.getApiKey(); + Assert.notEmpty(combineKey, "apiKey 不能为空"); + String[] keys = combineKey.trim().split(" "); + Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]"); + } + + private String getSdkAppId() { + return StrUtil.subAfter(properties.getApiKey(), " ", true); + } + + private String getApiKey() { + return StrUtil.subBefore(properties.getApiKey(), " ", true); + } + + @Override + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + // 构建请求 + SendSmsRequest request = new SendSmsRequest(); + request.setSmsSdkAppId(getSdkAppId()); + request.setPhoneNumberSet(new String[]{mobile}); + request.setSignName(properties.getSignature()); + request.setTemplateId(apiTemplateId); + request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue()))); + request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId))); + // 执行请求 + SendSmsResponse response = client.SendSms(request); + SendStatus status = response.getSendStatusSet()[0]; + return new SmsSendRespDTO().setSuccess(Objects.equals(status.getCode(), API_CODE_SUCCESS)).setSerialNo(status.getSerialNo()) + .setApiRequestId(response.getRequestId()).setApiCode(status.getCode()).setApiMsg(status.getMessage()); + } + + @Override + public List parseSmsReceiveStatus(String text) { + List callback = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return convertList(callback, status -> new SmsReceiveRespDTO() + .setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus())) + .setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription()) + .setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime()) + .setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId())); + } + + @Override + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { + // 构建请求 + DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest(); + request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)}); + request.setInternational(INTERNATIONAL_CHINA); + // 执行请求 + DescribeSmsTemplateListResponse response = client.DescribeSmsTemplateList(request); + DescribeTemplateListStatus status = response.getDescribeTemplateStatusSet()[0]; + if (status == null || status.getStatusCode() == null) { + return null; + } + return new SmsTemplateRespDTO().setId(status.getTemplateId().toString()).setContent(status.getTemplateContent()) + .setAuditStatus(convertSmsTemplateAuditStatus(status.getStatusCode().intValue())).setAuditReason(status.getReviewReply()); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(int templateStatus) { + switch (templateStatus) { + case 1: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 0: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case -1: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + @Data + private static class SmsReceiveStatus { + + /** + * 短信接受成功 code + */ + public static final String SUCCESS_CODE = "SUCCESS"; + + /** + * 用户实际接收到短信的时间 + */ + @JsonProperty("user_receive_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private LocalDateTime receiveTime; + + /** + * 国家(或地区)码 + */ + @JsonProperty("nationcode") + private String nationCode; + + /** + * 手机号码 + */ + private String mobile; + + /** + * 实际是否收到短信接收状态,SUCCESS(成功)、FAIL(失败) + */ + @JsonProperty("report_status") + private String status; + + /** + * 用户接收短信状态码错误信息 + */ + @JsonProperty("errmsg") + private String errCode; + + /** + * 用户接收短信状态描述 + */ + @JsonProperty("description") + private String description; + + /** + * 本次发送标识 ID(与发送接口返回的SerialNo对应) + */ + @JsonProperty("sid") + private String serialNo; + + /** + * 用户的 session 内容(与发送接口的请求参数 SessionContext 一致) + */ + @JsonProperty("ext") + private SessionContext sessionContext; + + } + + @VisibleForTesting + @Data + static class SessionContext { + + /** + * 发送短信记录id + */ + private Long logId; + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsChannelEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsChannelEnum.java new file mode 100644 index 0000000..7bd1922 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsChannelEnum.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信渠道枚举 + * + * @author zzf + * @since 2021/1/25 10:56 + */ +@Getter +@AllArgsConstructor +public enum SmsChannelEnum { + + DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"), + ALIYUN("ALIYUN", "阿里云"), + TENCENT("TENCENT", "腾讯云"), +// HUA_WEI("HUA_WEI", "华为云"), + ; + + /** + * 编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static SmsChannelEnum getByCode(String code) { + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java new file mode 100644 index 0000000..489f69e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信模板的审核状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum SmsTemplateAuditStatusEnum { + + CHECKING(1), + SUCCESS(2), + FAIL(3); + + private final Integer status; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/property/SmsChannelProperties.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/property/SmsChannelProperties.java new file mode 100644 index 0000000..793b049 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/property/SmsChannelProperties.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.property; + +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信渠道配置类 + * + * @author zzf + * @since 2021/1/25 17:01 + */ +@Data +@Validated +public class SmsChannelProperties { + + /** + * 渠道编号 + */ + @NotNull(message = "短信渠道 ID 不能为空") + private Long id; + /** + * 短信签名 + */ + @NotEmpty(message = "短信签名不能为空") + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + @NotEmpty(message = "渠道编码不能为空") + private String code; + /** + * 短信 API 的账号 + */ + @NotEmpty(message = "短信 API 的账号不能为空") + private String apiKey; + /** + * 短信 API 的密钥 + */ + @NotEmpty(message = "短信 API 的密钥不能为空") + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/config/SystemWebConfiguration.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/config/SystemWebConfiguration.java new file mode 100644 index 0000000..5b1b235 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/config/SystemWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * system 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class SystemWebConfiguration { + + /** + * system 模块的 API 分组 + */ + @Bean + public GroupedOpenApi systemGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("system"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/package-info.java new file mode 100644 index 0000000..1a17a3d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * system 模块的 web 配置 + */ +package cn.iocoder.yudao.module.system.framework.web; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java new file mode 100644 index 0000000..70bb92a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/DemoJob.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.job; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +@Component +public class DemoJob implements JobHandler { + + @Resource + private AdminUserMapper adminUserMapper; + + @Override + @TenantJob // 标记多租户 + public String execute(String param) { + System.out.println("当前租户:" + TenantContextHolder.getTenantId()); + List users = adminUserMapper.selectList(); + return "用户数量:" + users.size(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/package-info.java new file mode 100644 index 0000000..a7f5954 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.system.job; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java new file mode 100644 index 0000000..7e7b487 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.mq.consumer.mail; + +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.service.mail.MailSendService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link MailSendMessage} 的消费者 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class MailSendConsumer { + + @Resource + private MailSendService mailSendService; + + @EventListener + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + public void onMessage(MailSendMessage message) { + log.info("[onMessage][消息内容({})]", message); + mailSendService.doSendMail(message); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java new file mode 100644 index 0000000..39753b6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.mq.consumer.sms; + +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; +import cn.iocoder.yudao.module.system.service.sms.SmsSendService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link SmsSendMessage} 的消费者 + * + * @author zzf + */ +@Component +@Slf4j +public class SmsSendConsumer { + + @Resource + private SmsSendService smsSendService; + + @EventListener + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + public void onMessage(SmsSendMessage message) { + log.info("[onMessage][消息内容({})]", message); + smsSendService.doSendSms(message); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java new file mode 100644 index 0000000..943d69b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.mq.message.mail; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 邮箱发送消息 + * + * @author 芋道源码 + */ +@Data +public class MailSendMessage { + + /** + * 邮件日志编号 + */ + @NotNull(message = "邮件日志编号不能为空") + private Long logId; + /** + * 接收邮件地址 + */ + @NotNull(message = "接收邮件地址不能为空") + private String mail; + /** + * 邮件账号编号 + */ + @NotNull(message = "邮件账号编号不能为空") + private Long accountId; + + /** + * 邮件发件人 + */ + private String nickname; + /** + * 邮件标题 + */ + @NotEmpty(message = "邮件标题不能为空") + private String title; + /** + * 邮件内容 + */ + @NotEmpty(message = "邮件内容不能为空") + private String content; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsSendMessage.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsSendMessage.java new file mode 100644 index 0000000..e4baefc --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsSendMessage.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.mq.message.sms; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 短信发送消息 + * + * @author 芋道源码 + */ +@Data +public class SmsSendMessage { + + /** + * 短信日志编号 + */ + @NotNull(message = "短信日志编号不能为空") + private Long logId; + /** + * 手机号 + */ + @NotNull(message = "手机号不能为空") + private String mobile; + /** + * 短信渠道编号 + */ + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + /** + * 短信 API 的模板编号 + */ + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; + /** + * 短信模板参数 + */ + private List> templateParams; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java new file mode 100644 index 0000000..5894332 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.mq.producer.mail; + +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * Mail 邮件相关消息的 Producer + * + * @author wangjingyi + * @since 2021/4/19 13:33 + */ +@Slf4j +@Component +public class MailProducer { + + @Resource + private ApplicationContext applicationContext; + + /** + * 发送 {@link MailSendMessage} 消息 + * + * @param sendLogId 发送日志编码 + * @param mail 接收邮件地址 + * @param accountId 邮件账号编号 + * @param nickname 邮件发件人 + * @param title 邮件标题 + * @param content 邮件内容 + */ + public void sendMailSendMessage(Long sendLogId, String mail, Long accountId, + String nickname, String title, String content) { + MailSendMessage message = new MailSendMessage() + .setLogId(sendLogId).setMail(mail).setAccountId(accountId) + .setNickname(nickname).setTitle(title).setContent(content); + applicationContext.publishEvent(message); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java new file mode 100644 index 0000000..379f2e2 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.system.mq.producer.sms; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * Sms 短信相关消息的 Producer + * + * @author zzf + * @since 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsProducer { + + @Resource + private ApplicationContext applicationContext; + + /** + * 发送 {@link SmsSendMessage} 消息 + * + * @param logId 短信日志编号 + * @param mobile 手机号 + * @param channelId 渠道编号 + * @param apiTemplateId 短信模板编号 + * @param templateParams 短信模板参数 + */ + public void sendSmsSendMessage(Long logId, String mobile, + Long channelId, String apiTemplateId, List> templateParams) { + SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile); + message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); + applicationContext.publishEvent(message); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/package-info.java new file mode 100644 index 0000000..df82ac7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/package-info.java @@ -0,0 +1,8 @@ +/** + * system 模块下,我们放通用业务,支撑上层的核心业务。 + * 例如说:用户、部门、权限、数据字典等等 + * + * 1. Controller URL:以 /system/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 system_ 开头,方便在数据库中区分 + */ +package cn.iocoder.yudao.module.system; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java new file mode 100644 index 0000000..52796ec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.service.auth; + +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; + +import javax.validation.Valid; + +/** + * 管理后台的认证 Service 接口 + * + * 提供用户的登录、登出的能力 + * + * @author 芋道源码 + */ +public interface AdminAuthService { + + /** + * 验证账号 + 密码。如果通过,则返回用户 + * + * @param username 账号 + * @param password 密码 + * @return 用户 + */ + AdminUserDO authenticate(String username, String password); + + /** + * 账号登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO login(@Valid AuthLoginReqVO reqVO); + + /** + * 基于 token 退出登录 + * + * @param token token + * @param logType 登出类型 + */ + void logout(String token, Integer logType); + + /** + * 短信验证码发送 + * + * @param reqVO 发送请求 + */ + void sendSmsCode(AuthSmsSendReqVO reqVO); + + /** + * 短信登录 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) ; + + /** + * 社交快捷登录,使用 code 授权码 + * + * @param reqVO 登录信息 + * @return 登录结果 + */ + AuthLoginRespVO socialLogin(@Valid AuthSocialLoginReqVO reqVO); + + /** + * 刷新访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 登录结果 + */ + AuthLoginRespVO refreshToken(String refreshToken); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java new file mode 100644 index 0000000..6add073 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -0,0 +1,250 @@ +package cn.iocoder.yudao.module.system.service.auth; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; +import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import cn.iocoder.yudao.module.system.service.logger.LoginLogService; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * Auth Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class AdminAuthServiceImpl implements AdminAuthService { + + @Resource + private AdminUserService userService; + @Resource + private LoginLogService loginLogService; + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private SocialUserService socialUserService; + @Resource + private MemberService memberService; + @Resource + private Validator validator; + @Resource + private CaptchaService captchaService; + @Resource + private SmsCodeApi smsCodeApi; + + /** + * 验证码的开关,默认为 true + */ + @Value("${yudao.captcha.enable:true}") + private Boolean captchaEnable; + + @Override + public AdminUserDO authenticate(String username, String password) { + final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME; + // 校验账号是否存在 + AdminUserDO user = userService.getUserByUsername(username); + if (user == null) { + createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + if (!userService.isPasswordMatch(password, user.getPassword())) { + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); + throw exception(AUTH_LOGIN_BAD_CREDENTIALS); + } + // 校验是否禁用 + if (CommonStatusEnum.isDisable(user.getStatus())) { + createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED); + throw exception(AUTH_LOGIN_USER_DISABLED); + } + return user; + } + + @Override + public AuthLoginRespVO login(AuthLoginReqVO reqVO) { + // 校验验证码 + validateCaptcha(reqVO); + + // 使用账号密码,进行登录 + AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); + + // 如果 socialType 非空,说明需要绑定社交用户 + if (reqVO.getSocialType() != null) { + socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); + } + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); + } + + @Override + public void sendSmsCode(AuthSmsSendReqVO reqVO) { + // 登录场景,验证是否存在 + if (userService.getUserByMobile(reqVO.getMobile()) == null) { + throw exception(AUTH_MOBILE_NOT_EXISTS); + } + // 发送验证码 + smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); + } + + @Override + public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) { + // 校验验证码 + smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP())); + + // 获得用户信息 + AdminUserDO user = userService.getUserByMobile(reqVO.getMobile()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); + } + + private void createLoginLog(Long userId, String username, + LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) { + // 插入登录日志 + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(logTypeEnum.getType()); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(getUserType().getValue()); + reqDTO.setUsername(username); + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(ServletUtils.getClientIP()); + reqDTO.setResult(loginResult.getResult()); + loginLogService.createLoginLog(reqDTO); + // 更新最后登录时间 + if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { + userService.updateUserLogin(userId, ServletUtils.getClientIP()); + } + } + + @Override + public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { + // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), + reqVO.getCode(), reqVO.getState()); + if (socialUser == null || socialUser.getUserId() == null) { + throw exception(AUTH_THIRD_LOGIN_NOT_BIND); + } + + // 获得用户 + AdminUserDO user = userService.getUser(socialUser.getUserId()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + + // 创建 Token 令牌,记录登录日志 + return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); + } + + @VisibleForTesting + void validateCaptcha(AuthLoginReqVO reqVO) { + // 如果验证码关闭,则不进行校验 + if (!captchaEnable) { + return; + } + // 校验验证码 + ValidationUtils.validate(validator, reqVO, AuthLoginReqVO.CodeEnableGroup.class); + CaptchaVO captchaVO = new CaptchaVO(); + captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification()); + ResponseModel response = captchaService.verification(captchaVO); + // 验证不通过 + if (!response.isSuccess()) { + // 创建登录失败日志(验证码不正确) + createLoginLog(null, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR); + throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg()); + } + } + + private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) { + // 插入登陆日志 + createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS); + // 创建访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(), + OAuth2ClientConstants.CLIENT_ID_DEFAULT, null); + // 构建返回结果 + return AuthConvert.INSTANCE.convert(accessTokenDO); + } + + @Override + public AuthLoginRespVO refreshToken(String refreshToken) { + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); + return AuthConvert.INSTANCE.convert(accessTokenDO); + } + + @Override + public void logout(String token, Integer logType) { + // 删除访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token); + if (accessTokenDO == null) { + return; + } + // 删除成功,则记录登出日志 + createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType); + } + + private void createLogoutLog(Long userId, Integer userType, Integer logType) { + LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO(); + reqDTO.setLogType(logType); + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setUserId(userId); + reqDTO.setUserType(userType); + if (ObjectUtil.equal(getUserType().getValue(), userType)) { + reqDTO.setUsername(getUsername(userId)); + } else { + reqDTO.setUsername(memberService.getMemberUserMobile(userId)); + } + reqDTO.setUserAgent(ServletUtils.getUserAgent()); + reqDTO.setUserIp(ServletUtils.getClientIP()); + reqDTO.setResult(LoginResultEnum.SUCCESS.getResult()); + loginLogService.createLoginLog(reqDTO); + } + + private String getUsername(Long userId) { + if (userId == null) { + return null; + } + AdminUserDO user = userService.getUser(userId); + return user != null ? user.getUsername() : null; + } + + private UserTypeEnum getUserType() { + return UserTypeEnum.ADMIN; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java new file mode 100644 index 0000000..11cb5f4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 部门 Service 接口 + * + * @author 芋道源码 + */ +public interface DeptService { + + /** + * 创建部门 + * + * @param createReqVO 部门信息 + * @return 部门编号 + */ + Long createDept(DeptSaveReqVO createReqVO); + + /** + * 更新部门 + * + * @param updateReqVO 部门信息 + */ + void updateDept(DeptSaveReqVO updateReqVO); + + /** + * 删除部门 + * + * @param id 部门编号 + */ + void deleteDept(Long id); + + /** + * 获得部门信息 + * + * @param id 部门编号 + * @return 部门信息 + */ + DeptDO getDept(Long id); + + /** + * 获得部门信息数组 + * + * @param ids 部门编号数组 + * @return 部门信息数组 + */ + List getDeptList(Collection ids); + + /** + * 筛选部门列表 + * + * @param reqVO 筛选条件请求 VO + * @return 部门列表 + */ + List getDeptList(DeptListReqVO reqVO); + + /** + * 获得指定编号的部门 Map + * + * @param ids 部门编号数组 + * @return 部门 Map + */ + default Map getDeptMap(Collection ids) { + List list = getDeptList(ids); + return CollectionUtils.convertMap(list, DeptDO::getId); + } + + /** + * 获得指定部门的所有子部门 + * + * @param id 部门编号 + * @return 子部门列表 + */ + List getChildDeptList(Long id); + + /** + * 获得所有子部门,从缓存中 + * + * @param id 父部门编号 + * @return 子部门列表 + */ + Set getChildDeptIdListFromCache(Long id); + + /** + * 校验部门们是否有效。如下情况,视为无效: + * 1. 部门编号不存在 + * 2. 部门被禁用 + * + * @param ids 角色编号数组 + */ + void validateDeptList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java new file mode 100644 index 0000000..183f11f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java @@ -0,0 +1,218 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 部门 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class DeptServiceImpl implements DeptService { + + @Resource + private DeptMapper deptMapper; + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public Long createDept(DeptSaveReqVO createReqVO) { + if (createReqVO.getParentId() == null) { + createReqVO.setParentId(DeptDO.PARENT_ID_ROOT); + } + // 校验父部门的有效性 + validateParentDept(null, createReqVO.getParentId()); + // 校验部门名的唯一性 + validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入部门 + DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class); + deptMapper.insert(dept); + return dept.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public void updateDept(DeptSaveReqVO updateReqVO) { + if (updateReqVO.getParentId() == null) { + updateReqVO.setParentId(DeptDO.PARENT_ID_ROOT); + } + // 校验自己存在 + validateDeptExists(updateReqVO.getId()); + // 校验父部门的有效性 + validateParentDept(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验部门名的唯一性 + validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新部门 + DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class); + deptMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 + public void deleteDept(Long id) { + // 校验是否存在 + validateDeptExists(id); + // 校验是否有子部门 + if (deptMapper.selectCountByParentId(id) > 0) { + throw exception(DEPT_EXITS_CHILDREN); + } + // 删除部门 + deptMapper.deleteById(id); + } + + @VisibleForTesting + void validateDeptExists(Long id) { + if (id == null) { + return; + } + DeptDO dept = deptMapper.selectById(id); + if (dept == null) { + throw exception(DEPT_NOT_FOUND); + } + } + + @VisibleForTesting + void validateParentDept(Long id, Long parentId) { + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父部门 + if (Objects.equals(id, parentId)) { + throw exception(DEPT_PARENT_ERROR); + } + // 2. 父部门不存在 + DeptDO parentDept = deptMapper.selectById(parentId); + if (parentDept == null) { + throw exception(DEPT_PARENT_NOT_EXITS); + } + // 3. 递归校验父部门,如果父部门是自己的子部门,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentDept.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(DEPT_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父部门 + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentDept = deptMapper.selectById(parentId); + if (parentDept == null) { + break; + } + } + } + + @VisibleForTesting + void validateDeptNameUnique(Long id, Long parentId, String name) { + DeptDO dept = deptMapper.selectByParentIdAndName(parentId, name); + if (dept == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的部门 + if (id == null) { + throw exception(DEPT_NAME_DUPLICATE); + } + if (ObjectUtil.notEqual(dept.getId(), id)) { + throw exception(DEPT_NAME_DUPLICATE); + } + } + + @Override + public DeptDO getDept(Long id) { + return deptMapper.selectById(id); + } + + @Override + public List getDeptList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return deptMapper.selectBatchIds(ids); + } + + @Override + public List getDeptList(DeptListReqVO reqVO) { + List list = deptMapper.selectList(reqVO); + list.sort(Comparator.comparing(DeptDO::getSort)); + return list; + } + + @Override + public List getChildDeptList(Long id) { + List children = new LinkedList<>(); + // 遍历每一层 + Collection parentIds = Collections.singleton(id); + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子部门 + List depts = deptMapper.selectListByParentId(parentIds); + // 1. 如果没有子部门,则结束遍历 + if (CollUtil.isEmpty(depts)) { + break; + } + // 2. 如果有子部门,继续遍历 + children.addAll(depts); + parentIds = convertSet(depts, DeptDO::getId); + } + return children; + } + + @Override + @DataPermission(enable = false) // 禁用数据权限,避免建立不正确的缓存 + @Cacheable(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, key = "#id") + public Set getChildDeptIdListFromCache(Long id) { + List children = getChildDeptList(id); + return convertSet(children, DeptDO::getId); + } + + @Override + public void validateDeptList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得科室信息 + Map deptMap = getDeptMap(ids); + // 校验 + ids.forEach(id -> { + DeptDO dept = deptMap.get(id); + if (dept == null) { + throw exception(DEPT_NOT_FOUND); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) { + throw exception(DEPT_NOT_ENABLE, dept.getName()); + } + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java new file mode 100644 index 0000000..25604ce --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * 岗位 Service 接口 + * + * @author 芋道源码 + */ +public interface PostService { + + /** + * 创建岗位 + * + * @param createReqVO 岗位信息 + * @return 岗位编号 + */ + Long createPost(PostSaveReqVO createReqVO); + + /** + * 更新岗位 + * + * @param updateReqVO 岗位信息 + */ + void updatePost(PostSaveReqVO updateReqVO); + + /** + * 删除岗位信息 + * + * @param id 岗位编号 + */ + void deletePost(Long id); + + /** + * 获得岗位列表 + * + * @param ids 岗位编号数组 + * @return 部门列表 + */ + List getPostList(@Nullable Collection ids); + + /** + * 获得符合条件的岗位列表 + * + * @param ids 岗位编号数组。如果为空,不进行筛选 + * @param statuses 状态数组。如果为空,不进行筛选 + * @return 部门列表 + */ + List getPostList(@Nullable Collection ids, + @Nullable Collection statuses); + + /** + * 获得岗位分页列表 + * + * @param reqVO 分页条件 + * @return 部门分页列表 + */ + PageResult getPostPage(PostPageReqVO reqVO); + + /** + * 获得岗位信息 + * + * @param id 岗位编号 + * @return 岗位信息 + */ + PostDO getPost(Long id); + + /** + * 校验岗位们是否有效。如下情况,视为无效: + * 1. 岗位编号不存在 + * 2. 岗位被禁用 + * + * @param ids 岗位编号数组 + */ + void validatePostList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java new file mode 100644 index 0000000..168386e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java @@ -0,0 +1,153 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 岗位 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PostServiceImpl implements PostService { + + @Resource + private PostMapper postMapper; + + @Override + public Long createPost(PostSaveReqVO createReqVO) { + // 校验正确性 + validatePostForCreateOrUpdate(null, createReqVO.getName(), createReqVO.getCode()); + + // 插入岗位 + PostDO post = BeanUtils.toBean(createReqVO, PostDO.class); + postMapper.insert(post); + return post.getId(); + } + + @Override + public void updatePost(PostSaveReqVO updateReqVO) { + // 校验正确性 + validatePostForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getCode()); + + // 更新岗位 + PostDO updateObj = BeanUtils.toBean(updateReqVO, PostDO.class); + postMapper.updateById(updateObj); + } + + @Override + public void deletePost(Long id) { + // 校验是否存在 + validatePostExists(id); + // 删除部门 + postMapper.deleteById(id); + } + + private void validatePostForCreateOrUpdate(Long id, String name, String code) { + // 校验自己存在 + validatePostExists(id); + // 校验岗位名的唯一性 + validatePostNameUnique(id, name); + // 校验岗位编码的唯一性 + validatePostCodeUnique(id, code); + } + + private void validatePostNameUnique(Long id, String name) { + PostDO post = postMapper.selectByName(name); + if (post == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的岗位 + if (id == null) { + throw exception(POST_NAME_DUPLICATE); + } + if (!post.getId().equals(id)) { + throw exception(POST_NAME_DUPLICATE); + } + } + + private void validatePostCodeUnique(Long id, String code) { + PostDO post = postMapper.selectByCode(code); + if (post == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的岗位 + if (id == null) { + throw exception(POST_CODE_DUPLICATE); + } + if (!post.getId().equals(id)) { + throw exception(POST_CODE_DUPLICATE); + } + } + + private void validatePostExists(Long id) { + if (id == null) { + return; + } + if (postMapper.selectById(id) == null) { + throw exception(POST_NOT_FOUND); + } + } + + @Override + public List getPostList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return postMapper.selectBatchIds(ids); + } + + @Override + public List getPostList(Collection ids, Collection statuses) { + return postMapper.selectList(ids, statuses); + } + + @Override + public PageResult getPostPage(PostPageReqVO reqVO) { + return postMapper.selectPage(reqVO); + } + + @Override + public PostDO getPost(Long id) { + return postMapper.selectById(id); + } + + @Override + public void validatePostList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得岗位信息 + List posts = postMapper.selectBatchIds(ids); + Map postMap = convertMap(posts, PostDO::getId); + // 校验 + ids.forEach(id -> { + PostDO post = postMap.get(id); + if (post == null) { + throw exception(POST_NOT_FOUND); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) { + throw exception(POST_NOT_ENABLE, post.getName()); + } + }); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java new file mode 100644 index 0000000..fc2498f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.List; + +/** + * 字典数据 Service 接口 + * + * @author ruoyi + */ +public interface DictDataService { + + /** + * 创建字典数据 + * + * @param createReqVO 字典数据信息 + * @return 字典数据编号 + */ + Long createDictData(DictDataSaveReqVO createReqVO); + + /** + * 更新字典数据 + * + * @param updateReqVO 字典数据信息 + */ + void updateDictData(DictDataSaveReqVO updateReqVO); + + /** + * 删除字典数据 + * + * @param id 字典数据编号 + */ + void deleteDictData(Long id); + + /** + * 获得字典数据列表 + * + * @param status 状态 + * @param dictType 字典类型 + * @return 字典数据全列表 + */ + List getDictDataList(@Nullable Integer status, @Nullable String dictType); + + /** + * 获得字典数据分页列表 + * + * @param pageReqVO 分页请求 + * @return 字典数据分页列表 + */ + PageResult getDictDataPage(DictDataPageReqVO pageReqVO); + + /** + * 获得字典数据详情 + * + * @param id 字典数据编号 + * @return 字典数据 + */ + DictDataDO getDictData(Long id); + + /** + * 获得指定字典类型的数据数量 + * + * @param dictType 字典类型 + * @return 数据数量 + */ + long getDictDataCountByDictType(String dictType); + + /** + * 校验字典数据们是否有效。如下情况,视为无效: + * 1. 字典数据不存在 + * 2. 字典数据被禁用 + * + * @param dictType 字典类型 + * @param values 字典数据值的数组 + */ + void validateDictDataList(String dictType, Collection values); + + /** + * 获得指定的字典数据 + * + * @param dictType 字典类型 + * @param value 字典数据值 + * @return 字典数据 + */ + DictDataDO getDictData(String dictType, String value); + + /** + * 解析获得指定的字典数据,从缓存中 + * + * @param dictType 字典类型 + * @param label 字典数据标签 + * @return 字典数据 + */ + DictDataDO parseDictData(String dictType, String label); + + /** + * 获得指定数据类型的字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + List getDictDataListByDictType(String dictType); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java new file mode 100644 index 0000000..e9f215d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java @@ -0,0 +1,179 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 字典数据 Service 实现类 + * + * @author ruoyi + */ +@Service +@Slf4j +public class DictDataServiceImpl implements DictDataService { + + /** + * 排序 dictType > sort + */ + private static final Comparator COMPARATOR_TYPE_AND_SORT = Comparator + .comparing(DictDataDO::getDictType) + .thenComparingInt(DictDataDO::getSort); + + @Resource + private DictTypeService dictTypeService; + + @Resource + private DictDataMapper dictDataMapper; + + @Override + public List getDictDataList(Integer status, String dictType) { + List list = dictDataMapper.selectListByStatusAndDictType(status, dictType); + list.sort(COMPARATOR_TYPE_AND_SORT); + return list; + } + + @Override + public PageResult getDictDataPage(DictDataPageReqVO pageReqVO) { + return dictDataMapper.selectPage(pageReqVO); + } + + @Override + public DictDataDO getDictData(Long id) { + return dictDataMapper.selectById(id); + } + + @Override + public Long createDictData(DictDataSaveReqVO createReqVO) { + // 校验字典类型有效 + validateDictTypeExists(createReqVO.getDictType()); + // 校验字典数据的值的唯一性 + validateDictDataValueUnique(null, createReqVO.getDictType(), createReqVO.getValue()); + + // 插入字典类型 + DictDataDO dictData = BeanUtils.toBean(createReqVO, DictDataDO.class); + dictDataMapper.insert(dictData); + return dictData.getId(); + } + + @Override + public void updateDictData(DictDataSaveReqVO updateReqVO) { + // 校验自己存在 + validateDictDataExists(updateReqVO.getId()); + // 校验字典类型有效 + validateDictTypeExists(updateReqVO.getDictType()); + // 校验字典数据的值的唯一性 + validateDictDataValueUnique(updateReqVO.getId(), updateReqVO.getDictType(), updateReqVO.getValue()); + + // 更新字典类型 + DictDataDO updateObj = BeanUtils.toBean(updateReqVO, DictDataDO.class); + dictDataMapper.updateById(updateObj); + } + + @Override + public void deleteDictData(Long id) { + // 校验是否存在 + validateDictDataExists(id); + + // 删除字典数据 + dictDataMapper.deleteById(id); + } + + @Override + public long getDictDataCountByDictType(String dictType) { + return dictDataMapper.selectCountByDictType(dictType); + } + + @VisibleForTesting + public void validateDictDataValueUnique(Long id, String dictType, String value) { + DictDataDO dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value); + if (dictData == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典数据 + if (id == null) { + throw exception(DICT_DATA_VALUE_DUPLICATE); + } + if (!dictData.getId().equals(id)) { + throw exception(DICT_DATA_VALUE_DUPLICATE); + } + } + + @VisibleForTesting + public void validateDictDataExists(Long id) { + if (id == null) { + return; + } + DictDataDO dictData = dictDataMapper.selectById(id); + if (dictData == null) { + throw exception(DICT_DATA_NOT_EXISTS); + } + } + + @VisibleForTesting + public void validateDictTypeExists(String type) { + DictTypeDO dictType = dictTypeService.getDictType(type); + if (dictType == null) { + throw exception(DICT_TYPE_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) { + throw exception(DICT_TYPE_NOT_ENABLE); + } + } + + @Override + public void validateDictDataList(String dictType, Collection values) { + if (CollUtil.isEmpty(values)) { + return; + } + Map dictDataMap = CollectionUtils.convertMap( + dictDataMapper.selectByDictTypeAndValues(dictType, values), DictDataDO::getValue); + // 校验 + values.forEach(value -> { + DictDataDO dictData = dictDataMap.get(value); + if (dictData == null) { + throw exception(DICT_DATA_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) { + throw exception(DICT_DATA_NOT_ENABLE, dictData.getLabel()); + } + }); + } + + @Override + public DictDataDO getDictData(String dictType, String value) { + return dictDataMapper.selectByDictTypeAndValue(dictType, value); + } + + @Override + public DictDataDO parseDictData(String dictType, String label) { + return dictDataMapper.selectByDictTypeAndLabel(dictType, label); + } + + @Override + public List getDictDataListByDictType(String dictType) { + List list = dictDataMapper.selectList(DictDataDO::getDictType, dictType); + list.sort(Comparator.comparing(DictDataDO::getSort)); + return list; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeService.java new file mode 100644 index 0000000..4091189 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeService.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; + +import java.util.List; + +/** + * 字典类型 Service 接口 + * + * @author 芋道源码 + */ +public interface DictTypeService { + + /** + * 创建字典类型 + * + * @param createReqVO 字典类型信息 + * @return 字典类型编号 + */ + Long createDictType(DictTypeSaveReqVO createReqVO); + + /** + * 更新字典类型 + * + * @param updateReqVO 字典类型信息 + */ + void updateDictType(DictTypeSaveReqVO updateReqVO); + + /** + * 删除字典类型 + * + * @param id 字典类型编号 + */ + void deleteDictType(Long id); + + /** + * 获得字典类型分页列表 + * + * @param pageReqVO 分页请求 + * @return 字典类型分页列表 + */ + PageResult getDictTypePage(DictTypePageReqVO pageReqVO); + + /** + * 获得字典类型详情 + * + * @param id 字典类型编号 + * @return 字典类型 + */ + DictTypeDO getDictType(Long id); + + /** + * 获得字典类型详情 + * + * @param type 字典类型 + * @return 字典类型详情 + */ + DictTypeDO getDictType(String type); + + /** + * 获得全部字典类型列表 + * + * @return 字典类型列表 + */ + List getDictTypeList(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImpl.java new file mode 100644 index 0000000..5e7f27e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImpl.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.dict.DictTypeMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 字典类型 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class DictTypeServiceImpl implements DictTypeService { + + @Resource + private DictDataService dictDataService; + + @Resource + private DictTypeMapper dictTypeMapper; + + @Override + public PageResult getDictTypePage(DictTypePageReqVO pageReqVO) { + return dictTypeMapper.selectPage(pageReqVO); + } + + @Override + public DictTypeDO getDictType(Long id) { + return dictTypeMapper.selectById(id); + } + + @Override + public DictTypeDO getDictType(String type) { + return dictTypeMapper.selectByType(type); + } + + @Override + public Long createDictType(DictTypeSaveReqVO createReqVO) { + // 校验字典类型的名字的唯一性 + validateDictTypeNameUnique(null, createReqVO.getName()); + // 校验字典类型的类型的唯一性 + validateDictTypeUnique(null, createReqVO.getType()); + + // 插入字典类型 + DictTypeDO dictType = BeanUtils.toBean(createReqVO, DictTypeDO.class); + dictType.setDeletedTime(LocalDateTimeUtils.EMPTY); // 唯一索引,避免 null 值 + dictTypeMapper.insert(dictType); + return dictType.getId(); + } + + @Override + public void updateDictType(DictTypeSaveReqVO updateReqVO) { + // 校验自己存在 + validateDictTypeExists(updateReqVO.getId()); + // 校验字典类型的名字的唯一性 + validateDictTypeNameUnique(updateReqVO.getId(), updateReqVO.getName()); + // 校验字典类型的类型的唯一性 + validateDictTypeUnique(updateReqVO.getId(), updateReqVO.getType()); + + // 更新字典类型 + DictTypeDO updateObj = BeanUtils.toBean(updateReqVO, DictTypeDO.class); + dictTypeMapper.updateById(updateObj); + } + + @Override + public void deleteDictType(Long id) { + // 校验是否存在 + DictTypeDO dictType = validateDictTypeExists(id); + // 校验是否有字典数据 + if (dictDataService.getDictDataCountByDictType(dictType.getType()) > 0) { + throw exception(DICT_TYPE_HAS_CHILDREN); + } + // 删除字典类型 + dictTypeMapper.updateToDelete(id, LocalDateTime.now()); + } + + @Override + public List getDictTypeList() { + return dictTypeMapper.selectList(); + } + + @VisibleForTesting + void validateDictTypeNameUnique(Long id, String name) { + DictTypeDO dictType = dictTypeMapper.selectByName(name); + if (dictType == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(DICT_TYPE_NAME_DUPLICATE); + } + if (!dictType.getId().equals(id)) { + throw exception(DICT_TYPE_NAME_DUPLICATE); + } + } + + @VisibleForTesting + void validateDictTypeUnique(Long id, String type) { + if (StrUtil.isEmpty(type)) { + return; + } + DictTypeDO dictType = dictTypeMapper.selectByType(type); + if (dictType == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(DICT_TYPE_TYPE_DUPLICATE); + } + if (!dictType.getId().equals(id)) { + throw exception(DICT_TYPE_TYPE_DUPLICATE); + } + } + + @VisibleForTesting + DictTypeDO validateDictTypeExists(Long id) { + if (id == null) { + return null; + } + DictTypeDO dictType = dictTypeMapper.selectById(id); + if (dictType == null) { + throw exception(DICT_TYPE_NOT_EXISTS); + } + return dictType; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogService.java new file mode 100644 index 0000000..64cd07b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogService.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; + +import javax.validation.Valid; + +/** + * 登录日志 Service 接口 + */ +public interface LoginLogService { + + /** + * 获得登录日志分页 + * + * @param pageReqVO 分页条件 + * @return 登录日志分页 + */ + PageResult getLoginLogPage(LoginLogPageReqVO pageReqVO); + + /** + * 创建登录日志 + * + * @param reqDTO 日志信息 + */ + void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImpl.java new file mode 100644 index 0000000..e1de978 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; +import cn.iocoder.yudao.module.system.dal.mysql.logger.LoginLogMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 登录日志 Service 实现 + */ +@Service +@Validated +public class LoginLogServiceImpl implements LoginLogService { + + @Resource + private LoginLogMapper loginLogMapper; + + @Override + public PageResult getLoginLogPage(LoginLogPageReqVO pageReqVO) { + return loginLogMapper.selectPage(pageReqVO); + } + + @Override + public void createLoginLog(LoginLogCreateReqDTO reqDTO) { + LoginLogDO loginLog = BeanUtils.toBean(reqDTO, LoginLogDO.class); + loginLogMapper.insert(loginLog); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java new file mode 100644 index 0000000..56f7130 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; + +/** + * 操作日志 Service 接口 + * + * @author 芋道源码 + */ +public interface OperateLogService { + + /** + * 记录操作日志 + * + * @param createReqDTO 创建请求 + */ + void createOperateLog(OperateLogCreateReqDTO createReqDTO); + + /** + * 获得操作日志分页列表 + * + * @param pageReqVO 分页条件 + * @return 操作日志分页列表 + */ + PageResult getOperateLogPage(OperateLogPageReqVO pageReqVO); + + /** + * 获得操作日志分页列表 + * + * @param pageReqVO 分页条件 + * @return 操作日志分页列表 + */ + PageResult getOperateLogPage(OperateLogPageReqDTO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java new file mode 100644 index 0000000..269ec70 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; +import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 操作日志 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class OperateLogServiceImpl implements OperateLogService { + + @Resource + private OperateLogMapper operateLogMapper; + + @Override + public void createOperateLog(OperateLogCreateReqDTO createReqDTO) { + OperateLogDO log = BeanUtils.toBean(createReqDTO, OperateLogDO.class); + operateLogMapper.insert(log); + } + + @Override + public PageResult getOperateLogPage(OperateLogPageReqVO pageReqVO) { + return operateLogMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getOperateLogPage(OperateLogPageReqDTO pageReqDTO) { + return operateLogMapper.selectPage(pageReqDTO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java new file mode 100644 index 0000000..72d6256 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 邮箱账号 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailAccountService { + + /** + * 创建邮箱账号 + * + * @param createReqVO 邮箱账号信息 + * @return 编号 + */ + Long createMailAccount(@Valid MailAccountSaveReqVO createReqVO); + + /** + * 修改邮箱账号 + * + * @param updateReqVO 邮箱账号信息 + */ + void updateMailAccount(@Valid MailAccountSaveReqVO updateReqVO); + + /** + * 删除邮箱账号 + * + * @param id 编号 + */ + void deleteMailAccount(Long id); + + /** + * 获取邮箱账号信息 + * + * @param id 编号 + * @return 邮箱账号信息 + */ + MailAccountDO getMailAccount(Long id); + + /** + * 从缓存中获取邮箱账号 + * + * @param id 编号 + * @return 邮箱账号 + */ + MailAccountDO getMailAccountFromCache(Long id); + + /** + * 获取邮箱账号分页信息 + * + * @param pageReqVO 邮箱账号分页参数 + * @return 邮箱账号分页信息 + */ + PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO); + + /** + * 获取邮箱数组信息 + * + * @return 邮箱账号信息数组 + */ + List getMailAccountList(); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java new file mode 100644 index 0000000..73cd9d3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS; + +/** + * 邮箱账号 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailAccountServiceImpl implements MailAccountService { + + @Resource + private MailAccountMapper mailAccountMapper; + + @Resource + private MailTemplateService mailTemplateService; + + @Override + public Long createMailAccount(MailAccountSaveReqVO createReqVO) { + MailAccountDO account = BeanUtils.toBean(createReqVO, MailAccountDO.class); + mailAccountMapper.insert(account); + return account.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id") + public void updateMailAccount(MailAccountSaveReqVO updateReqVO) { + // 校验是否存在 + validateMailAccountExists(updateReqVO.getId()); + + // 更新 + MailAccountDO updateObj = BeanUtils.toBean(updateReqVO, MailAccountDO.class); + mailAccountMapper.updateById(updateObj); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id") + public void deleteMailAccount(Long id) { + // 校验是否存在账号 + validateMailAccountExists(id); + // 校验是否存在关联模版 + if (mailTemplateService.getMailTemplateCountByAccountId(id) > 0) { + throw exception(MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS); + } + + // 删除 + mailAccountMapper.deleteById(id); + } + + private void validateMailAccountExists(Long id) { + if (mailAccountMapper.selectById(id) == null) { + throw exception(MAIL_ACCOUNT_NOT_EXISTS); + } + } + + @Override + public MailAccountDO getMailAccount(Long id) { + return mailAccountMapper.selectById(id); + } + + @Override + @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id", unless = "#result == null") + public MailAccountDO getMailAccountFromCache(Long id) { + return getMailAccount(id); + } + + @Override + public PageResult getMailAccountPage(MailAccountPageReqVO pageReqVO) { + return mailAccountMapper.selectPage(pageReqVO); + } + + @Override + public List getMailAccountList() { + return mailAccountMapper.selectList(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java new file mode 100644 index 0000000..4a0b204 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogService.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; + +import java.util.Map; + +/** + * 邮件日志 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailLogService { + + /** + * 邮件日志分页 + * + * @param pageVO 分页参数 + * @return 分页结果 + */ + PageResult getMailLogPage(MailLogPageReqVO pageVO); + + /** + * 获得指定编号的邮件日志 + * + * @param id 日志编号 + * @return 邮件日志 + */ + MailLogDO getMailLog(Long id); + + /** + * 创建邮件日志 + * + * @param userId 用户编码 + * @param userType 用户类型 + * @param toMail 收件人邮件 + * @param account 邮件账号信息 + * @param template 模版信息 + * @param templateContent 模版内容 + * @param templateParams 模版参数 + * @param isSend 是否发送成功 + * @return 日志编号 + */ + Long createMailLog(Long userId, Integer userType, String toMail, + MailAccountDO account, MailTemplateDO template , + String templateContent, Map templateParams, Boolean isSend); + + /** + * 更新邮件发送结果 + * + * @param logId 日志编号 + * @param messageId 发送后的消息编号 + * @param exception 发送异常 + */ + void updateMailSendResult(Long logId, String messageId, Exception exception); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java new file mode 100644 index 0000000..292acab --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImpl.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper; +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; + +/** + * 邮件日志 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +public class MailLogServiceImpl implements MailLogService { + + @Resource + private MailLogMapper mailLogMapper; + + @Override + public PageResult getMailLogPage(MailLogPageReqVO pageVO) { + return mailLogMapper.selectPage(pageVO); + } + + @Override + public MailLogDO getMailLog(Long id) { + return mailLogMapper.selectById(id); + } + + @Override + public Long createMailLog(Long userId, Integer userType, String toMail, + MailAccountDO account, MailTemplateDO template, + String templateContent, Map templateParams, Boolean isSend) { + MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder(); + // 根据是否要发送,设置状态 + logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus() + : MailSendStatusEnum.IGNORE.getStatus()) + // 用户信息 + .userId(userId).userType(userType).toMail(toMail) + .accountId(account.getId()).fromMail(account.getMail()) + // 模板相关字段 + .templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname()) + .templateTitle(template.getTitle()).templateContent(templateContent).templateParams(templateParams); + + // 插入数据库 + MailLogDO logDO = logDOBuilder.build(); + mailLogMapper.insert(logDO); + return logDO.getId(); + } + + @Override + public void updateMailSendResult(Long logId, String messageId, Exception exception) { + // 1. 成功 + if (exception == null) { + mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now()) + .setSendStatus(MailSendStatusEnum.SUCCESS.getStatus()).setSendMessageId(messageId)); + return; + } + // 2. 失败 + mailLogMapper.updateById(new MailLogDO().setId(logId).setSendTime(LocalDateTime.now()) + .setSendStatus(MailSendStatusEnum.FAILURE.getStatus()).setSendException(getRootCauseMessage(exception))); + + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java new file mode 100644 index 0000000..8988168 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; + +import java.util.Map; + +/** + * 邮件发送 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailSendService { + + /** + * 发送单条邮件给管理后台的用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 APP 的用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMailToMember(String mail, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条邮件给用户 + * + * @param mail 邮箱 + * @param userId 用户编码 + * @param userType 用户类型 + * @param templateCode 邮件模版编码 + * @param templateParams 邮件模版参数 + * @return 发送日志编号 + */ + Long sendSingleMail(String mail, Long userId, Integer userType, + String templateCode, Map templateParams); + + /** + * 执行真正的邮件发送 + * 注意,该方法仅仅提供给 MQ Consumer 使用 + * + * @param message 邮件 + */ + void doSendMail(MailSendMessage message); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java new file mode 100644 index 0000000..ea139cf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -0,0 +1,174 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 邮箱发送 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailSendServiceImpl implements MailSendService { + + @Resource + private AdminUserService adminUserService; + @Resource + private MemberService memberService; + + @Resource + private MailAccountService mailAccountService; + @Resource + private MailTemplateService mailTemplateService; + + @Resource + private MailLogService mailLogService; + @Resource + private MailProducer mailProducer; + + @Override + public Long sendSingleMailToAdmin(String mail, Long userId, + String templateCode, Map templateParams) { + // 如果 mail 为空,则加载用户编号对应的邮箱 + if (StrUtil.isEmpty(mail)) { + AdminUserDO user = adminUserService.getUser(userId); + if (user != null) { + mail = user.getEmail(); + } + } + // 执行发送 + return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleMailToMember(String mail, Long userId, + String templateCode, Map templateParams) { + // 如果 mail 为空,则加载用户编号对应的邮箱 + if (StrUtil.isEmpty(mail)) { + mail = memberService.getMemberUserEmail(userId); + } + // 执行发送 + return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleMail(String mail, Long userId, Integer userType, + String templateCode, Map templateParams) { + // 校验邮箱模版是否合法 + MailTemplateDO template = validateMailTemplate(templateCode); + // 校验邮箱账号是否合法 + MailAccountDO account = validateMailAccount(template.getAccountId()); + + // 校验邮箱是否存在 + mail = validateMail(mail); + validateTemplateParams(template, templateParams); + + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); + String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams); + String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams); + Long sendLogId = mailLogService.createMailLog(userId, userType, mail, + account, template, content, templateParams, isSend); + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(), + template.getNickname(), title, content); + } + return sendLogId; + } + + @Override + public void doSendMail(MailSendMessage message) { + // 1. 创建发送账号 + MailAccountDO account = validateMailAccount(message.getAccountId()); + MailAccount mailAccount = buildMailAccount(account, message.getNickname()); + // 2. 发送邮件 + try { + String messageId = MailUtil.send(mailAccount, message.getMail(), + message.getTitle(), message.getContent(), true); + // 3. 更新结果(成功) + mailLogService.updateMailSendResult(message.getLogId(), messageId, null); + } catch (Exception e) { + // 3. 更新结果(异常) + mailLogService.updateMailSendResult(message.getLogId(), null, e); + } + } + + private MailAccount buildMailAccount(MailAccountDO account, String nickname) { + String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail(); + return new MailAccount().setFrom(from).setAuth(true) + .setUser(account.getUsername()).setPass(account.getPassword()) + .setHost(account.getHost()).setPort(account.getPort()) + .setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable()); + } + + @VisibleForTesting + MailTemplateDO validateMailTemplate(String templateCode) { + // 获得邮件模板。考虑到效率,从缓存中获取 + MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); + // 邮件模板不存在 + if (template == null) { + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + return template; + } + + @VisibleForTesting + MailAccountDO validateMailAccount(Long accountId) { + // 获得邮箱账号。考虑到效率,从缓存中获取 + MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId); + // 邮箱账号不存在 + if (account == null) { + throw exception(MAIL_ACCOUNT_NOT_EXISTS); + } + return account; + } + + @VisibleForTesting + String validateMail(String mail) { + if (StrUtil.isEmpty(mail)) { + throw exception(MAIL_SEND_MAIL_NOT_EXISTS); + } + return mail; + } + + /** + * 校验邮件参数是否确实 + * + * @param template 邮箱模板 + * @param templateParams 参数列表 + */ + @VisibleForTesting + void validateTemplateParams(MailTemplateDO template, Map templateParams) { + template.getParams().forEach(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key); + } + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java new file mode 100644 index 0000000..0f5a49f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +/** + * 邮件模版 Service 接口 + * + * @author wangjingyi + * @since 2022-03-21 + */ +public interface MailTemplateService { + + /** + * 邮件模版创建 + * + * @param createReqVO 邮件信息 + * @return 编号 + */ + Long createMailTemplate(@Valid MailTemplateSaveReqVO createReqVO); + + /** + * 邮件模版修改 + * + * @param updateReqVO 邮件信息 + */ + void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO); + + /** + * 邮件模版删除 + * + * @param id 编号 + */ + void deleteMailTemplate(Long id); + + /** + * 获取邮件模版 + * + * @param id 编号 + * @return 邮件模版 + */ + MailTemplateDO getMailTemplate(Long id); + + /** + * 获取邮件模版分页 + * + * @param pageReqVO 模版信息 + * @return 邮件模版分页信息 + */ + PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO); + + /** + * 获取邮件模板数组 + * + * @return 模版数组 + */ + List getMailTemplateList(); + + /** + * 从缓存中获取邮件模版 + * + * @param code 模板编码 + * @return 邮件模板 + */ + MailTemplateDO getMailTemplateByCodeFromCache(String code); + + /** + * 邮件模版内容合成 + * + * @param content 邮件模版 + * @param params 合成参数 + * @return 格式化后的内容 + */ + String formatMailTemplateContent(String content, Map params); + + /** + * 获得指定邮件账号下的邮件模板数量 + * + * @param accountId 账号编号 + * @return 数量 + */ + long getMailTemplateCountByAccountId(Long accountId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java new file mode 100644 index 0000000..b19c7a4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_CODE_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; + +/** + * 邮箱模版 Service 实现类 + * + * @author wangjingyi + * @since 2022-03-21 + */ +@Service +@Validated +@Slf4j +public class MailTemplateServiceImpl implements MailTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private MailTemplateMapper mailTemplateMapper; + + @Override + public Long createMailTemplate(MailTemplateSaveReqVO createReqVO) { + // 校验 code 是否唯一 + validateCodeUnique(null, createReqVO.getCode()); + + // 插入 + MailTemplateDO template = BeanUtils.toBean(createReqVO, MailTemplateDO.class) + .setParams(parseTemplateContentParams(createReqVO.getContent())); + mailTemplateMapper.insert(template); + return template.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateMailTemplate(@Valid MailTemplateSaveReqVO updateReqVO) { + // 校验是否存在 + validateMailTemplateExists(updateReqVO.getId()); + // 校验 code 是否唯一 + validateCodeUnique(updateReqVO.getId(),updateReqVO.getCode()); + + // 更新 + MailTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MailTemplateDO.class) + .setParams(parseTemplateContentParams(updateReqVO.getContent())); + mailTemplateMapper.updateById(updateObj); + } + + @VisibleForTesting + void validateCodeUnique(Long id, String code) { + MailTemplateDO template = mailTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 存在 template 记录的情况下 + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, template.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(MAIL_TEMPLATE_CODE_EXISTS); + } + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.MAIL_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteMailTemplate(Long id) { + // 校验是否存在 + validateMailTemplateExists(id); + + // 删除 + mailTemplateMapper.deleteById(id); + } + + private void validateMailTemplateExists(Long id) { + if (mailTemplateMapper.selectById(id) == null) { + throw exception(MAIL_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);} + + @Override + @Cacheable(value = RedisKeyConstants.MAIL_TEMPLATE, key = "#code", unless = "#result == null") + public MailTemplateDO getMailTemplateByCodeFromCache(String code) { + return mailTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getMailTemplatePage(MailTemplatePageReqVO pageReqVO) { + return mailTemplateMapper.selectPage(pageReqVO); + } + + @Override + public List getMailTemplateList() {return mailTemplateMapper.selectList();} + + @Override + public String formatMailTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + + @Override + public long getMailTemplateCountByAccountId(Long accountId) { + return mailTemplateMapper.selectCountByAccountId(accountId); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java new file mode 100644 index 0000000..933e5bf --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberService.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.service.member; + +/** + * Member Service 接口 + * + * @author 芋道源码 + */ +public interface MemberService { + + /** + * 获得会员用户的手机号码 + * + * @param id 会员用户编号 + * @return 手机号码 + */ + String getMemberUserMobile(Long id); + + /** + * 获得会员用户的邮箱 + * + * @param id 会员用户编号 + * @return 邮箱 + */ + String getMemberUserEmail(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java new file mode 100644 index 0000000..7b31e04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/MemberServiceImpl.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.service.member; + +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Member Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class MemberServiceImpl implements MemberService { + + @Value("${yudao.info.base-package}") + private String basePackage; + + private volatile Object memberUserApi; + + @Override + public String getMemberUserMobile(Long id) { + Object user = getMemberUser(id); + if (user == null) { + return null; + } + return ReflectUtil.invoke(user, "getMobile"); + } + + @Override + public String getMemberUserEmail(Long id) { + Object user = getMemberUser(id); + if (user == null) { + return null; + } + return ReflectUtil.invoke(user, "getEmail"); + } + + private Object getMemberUser(Long id) { + if (id == null) { + return null; + } + return ReflectUtil.invoke(getMemberUserApi(), "getUser", id); + } + + private Object getMemberUserApi() { + if (memberUserApi == null) { + memberUserApi = SpringUtil.getBean(ClassUtil.loadClass(String.format("%s.module.member.api.user.MemberUserApi", basePackage))); + } + return memberUserApi; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/package-info.java new file mode 100644 index 0000000..ce080b4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/member/package-info.java @@ -0,0 +1,4 @@ +/** + * yudao-module-member 模块的适配,解除 yudao-module-system 对它们的依赖 + */ +package cn.iocoder.yudao.module.system.service.member; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeService.java new file mode 100644 index 0000000..c935c49 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeService.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.system.service.notice; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; + +/** + * 通知公告 Service 接口 + */ +public interface NoticeService { + + /** + * 创建通知公告 + * + * @param createReqVO 通知公告 + * @return 编号 + */ + Long createNotice(NoticeSaveReqVO createReqVO); + + /** + * 更新通知公告 + * + * @param reqVO 通知公告 + */ + void updateNotice(NoticeSaveReqVO reqVO); + + /** + * 删除通知公告 + * + * @param id 编号 + */ + void deleteNotice(Long id); + + /** + * 获得通知公告分页列表 + * + * @param reqVO 分页条件 + * @return 部门分页列表 + */ + PageResult getNoticePage(NoticePageReqVO reqVO); + + /** + * 获得通知公告 + * + * @param id 编号 + * @return 通知公告 + */ + NoticeDO getNotice(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImpl.java new file mode 100644 index 0000000..f0204c3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImpl.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.service.notice; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; +import cn.iocoder.yudao.module.system.dal.mysql.notice.NoticeMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND; + +/** + * 通知公告 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class NoticeServiceImpl implements NoticeService { + + @Resource + private NoticeMapper noticeMapper; + + @Override + public Long createNotice(NoticeSaveReqVO createReqVO) { + NoticeDO notice = BeanUtils.toBean(createReqVO, NoticeDO.class); + noticeMapper.insert(notice); + return notice.getId(); + } + + @Override + public void updateNotice(NoticeSaveReqVO updateReqVO) { + // 校验是否存在 + validateNoticeExists(updateReqVO.getId()); + // 更新通知公告 + NoticeDO updateObj = BeanUtils.toBean(updateReqVO, NoticeDO.class); + noticeMapper.updateById(updateObj); + } + + @Override + public void deleteNotice(Long id) { + // 校验是否存在 + validateNoticeExists(id); + // 删除通知公告 + noticeMapper.deleteById(id); + } + + @Override + public PageResult getNoticePage(NoticePageReqVO reqVO) { + return noticeMapper.selectPage(reqVO); + } + + @Override + public NoticeDO getNotice(Long id) { + return noticeMapper.selectById(id); + } + + @VisibleForTesting + public void validateNoticeExists(Long id) { + if (id == null) { + return; + } + NoticeDO notice = noticeMapper.selectById(id); + if (notice == null) { + throw exception(NOTICE_NOT_FOUND); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageService.java new file mode 100644 index 0000000..b06aef3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 站内信 Service 接口 + * + * @author xrcoder + */ +public interface NotifyMessageService { + + /** + * 创建站内信 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param template 模版信息 + * @param templateContent 模版内容 + * @param templateParams 模版参数 + * @return 站内信编号 + */ + Long createNotifyMessage(Long userId, Integer userType, + NotifyTemplateDO template, String templateContent, Map templateParams); + + /** + * 获得站内信分页 + * + * @param pageReqVO 分页查询 + * @return 站内信分页 + */ + PageResult getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO); + + /** + * 获得【我的】站内信分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @param userType 用户类型 + * @return 站内信分页 + */ + PageResult getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType); + + /** + * 获得站内信 + * + * @param id 编号 + * @return 站内信 + */ + NotifyMessageDO getNotifyMessage(Long id); + + /** + * 获得【我的】未读站内信列表 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param size 数量 + * @return 站内信列表 + */ + List getUnreadNotifyMessageList(Long userId, Integer userType, Integer size); + + /** + * 统计用户未读站内信条数 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 返回未读站内信条数 + */ + Long getUnreadNotifyMessageCount(Long userId, Integer userType); + + /** + * 标记站内信为已读 + * + * @param ids 站内信编号集合 + * @param userId 用户编号 + * @param userType 用户类型 + * @return 更新到的条数 + */ + int updateNotifyMessageRead(Collection ids, Long userId, Integer userType); + + /** + * 标记所有站内信为已读 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 更新到的条数 + */ + int updateAllNotifyMessageRead(Long userId, Integer userType); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImpl.java new file mode 100644 index 0000000..1ac4c04 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImpl.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 站内信 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +public class NotifyMessageServiceImpl implements NotifyMessageService { + + @Resource + private NotifyMessageMapper notifyMessageMapper; + + @Override + public Long createNotifyMessage(Long userId, Integer userType, + NotifyTemplateDO template, String templateContent, Map templateParams) { + NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType) + .setTemplateId(template.getId()).setTemplateCode(template.getCode()) + .setTemplateType(template.getType()).setTemplateNickname(template.getNickname()) + .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false); + notifyMessageMapper.insert(message); + return message.getId(); + } + + @Override + public PageResult getNotifyMessagePage(NotifyMessagePageReqVO pageReqVO) { + return notifyMessageMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getMyMyNotifyMessagePage(NotifyMessageMyPageReqVO pageReqVO, Long userId, Integer userType) { + return notifyMessageMapper.selectPage(pageReqVO, userId, userType); + } + + @Override + public NotifyMessageDO getNotifyMessage(Long id) { + return notifyMessageMapper.selectById(id); + } + + @Override + public List getUnreadNotifyMessageList(Long userId, Integer userType, Integer size) { + return notifyMessageMapper.selectUnreadListByUserIdAndUserType(userId, userType, size); + } + + @Override + public Long getUnreadNotifyMessageCount(Long userId, Integer userType) { + return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType); + } + + @Override + public int updateNotifyMessageRead(Collection ids, Long userId, Integer userType) { + return notifyMessageMapper.updateListRead(ids, userId, userType); + } + + @Override + public int updateAllNotifyMessageRead(Long userId, Integer userType) { + return notifyMessageMapper.updateListRead(userId, userType); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java new file mode 100644 index 0000000..d848bcb --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import java.util.List; +import java.util.Map; + +/** + * 站内信发送 Service 接口 + * + * @author xrcoder + */ +public interface NotifySendService { + + /** + * 发送单条站内信给管理后台的用户 + * + * 在 mobile 为空时,使用 userId 加载对应管理员的手机号 + * + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotifyToAdmin(Long userId, + String templateCode, Map templateParams); + /** + * 发送单条站内信给用户 APP 的用户 + * + * 在 mobile 为空时,使用 userId 加载对应会员的手机号 + * + * @param userId 用户编号 + * @param templateCode 站内信模板编号 + * @param templateParams 站内信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotifyToMember(Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条站内信给用户 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param templateCode 站内信模板编号 + * @param templateParams 站内信模板参数 + * @return 发送日志编号 + */ + Long sendSingleNotify( Long userId, Integer userType, + String templateCode, Map templateParams); + + default void sendBatchNotify(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams) { + throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java new file mode 100644 index 0000000..f71c5fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImpl.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 站内信发送 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +@Slf4j +public class NotifySendServiceImpl implements NotifySendService { + + @Resource + private NotifyTemplateService notifyTemplateService; + + @Resource + private NotifyMessageService notifyMessageService; + + @Override + public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map templateParams) { + return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleNotifyToMember(Long userId, String templateCode, Map templateParams) { + return sendSingleNotify(userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleNotify(Long userId, Integer userType, String templateCode, Map templateParams) { + // 校验模版 + NotifyTemplateDO template = validateNotifyTemplate(templateCode); + if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType); + return null; + } + // 校验参数 + validateTemplateParams(template, templateParams); + + // 发送站内信 + String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams); + return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams); + } + + @VisibleForTesting + public NotifyTemplateDO validateNotifyTemplate(String templateCode) { + // 获得站内信模板。考虑到效率,从缓存中获取 + NotifyTemplateDO template = notifyTemplateService.getNotifyTemplateByCodeFromCache(templateCode); + // 站内信模板不存在 + if (template == null) { + throw exception(NOTICE_NOT_FOUND); + } + return template; + } + + /** + * 校验站内信模版参数是否确实 + * + * @param template 邮箱模板 + * @param templateParams 参数列表 + */ + @VisibleForTesting + public void validateTemplateParams(NotifyTemplateDO template, Map templateParams) { + template.getParams().forEach(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(NOTIFY_SEND_TEMPLATE_PARAM_MISS, key); + } + }); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java new file mode 100644 index 0000000..76e1554 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; + +import javax.validation.Valid; +import java.util.Map; + +/** + * 站内信模版 Service 接口 + * + * @author xrcoder + */ +public interface NotifyTemplateService { + + /** + * 创建站内信模版 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createNotifyTemplate(@Valid NotifyTemplateSaveReqVO createReqVO); + + /** + * 更新站内信模版 + * + * @param updateReqVO 更新信息 + */ + void updateNotifyTemplate(@Valid NotifyTemplateSaveReqVO updateReqVO); + + /** + * 删除站内信模版 + * + * @param id 编号 + */ + void deleteNotifyTemplate(Long id); + + /** + * 获得站内信模版 + * + * @param id 编号 + * @return 站内信模版 + */ + NotifyTemplateDO getNotifyTemplate(Long id); + + /** + * 获得站内信模板,从缓存中 + * + * @param code 模板编码 + * @return 站内信模板 + */ + NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code); + + /** + * 获得站内信模版分页 + * + * @param pageReqVO 分页查询 + * @return 站内信模版分页 + */ + PageResult getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO); + + /** + * 格式化站内信内容 + * + * @param content 站内信模板的内容 + * @param params 站内信内容的参数 + * @return 格式化后的内容 + */ + String formatNotifyTemplateContent(String content, Map params); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java new file mode 100644 index 0000000..cd8e907 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java @@ -0,0 +1,138 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; + +/** + * 站内信模版 Service 实现类 + * + * @author xrcoder + */ +@Service +@Validated +@Slf4j +public class NotifyTemplateServiceImpl implements NotifyTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private NotifyTemplateMapper notifyTemplateMapper; + + @Override + public Long createNotifyTemplate(NotifyTemplateSaveReqVO createReqVO) { + // 校验站内信编码是否重复 + validateNotifyTemplateCodeDuplicate(null, createReqVO.getCode()); + + // 插入 + NotifyTemplateDO notifyTemplate = BeanUtils.toBean(createReqVO, NotifyTemplateDO.class); + notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent())); + notifyTemplateMapper.insert(notifyTemplate); + return notifyTemplate.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateNotifyTemplate(NotifyTemplateSaveReqVO updateReqVO) { + // 校验存在 + validateNotifyTemplateExists(updateReqVO.getId()); + // 校验站内信编码是否重复 + validateNotifyTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + + // 更新 + NotifyTemplateDO updateObj = BeanUtils.toBean(updateReqVO, NotifyTemplateDO.class); + updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); + notifyTemplateMapper.updateById(updateObj); + } + + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteNotifyTemplate(Long id) { + // 校验存在 + validateNotifyTemplateExists(id); + // 删除 + notifyTemplateMapper.deleteById(id); + } + + private void validateNotifyTemplateExists(Long id) { + if (notifyTemplateMapper.selectById(id) == null) { + throw exception(NOTIFY_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public NotifyTemplateDO getNotifyTemplate(Long id) { + return notifyTemplateMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, key = "#code", + unless = "#result == null") + public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) { + return notifyTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) { + return notifyTemplateMapper.selectPage(pageReqVO); + } + + @VisibleForTesting + void validateNotifyTemplateCodeDuplicate(Long id, String code) { + NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code); + } + if (!template.getId().equals(id)) { + throw exception(NOTIFY_TEMPLATE_CODE_DUPLICATE, code); + } + } + + /** + * 格式化站内信内容 + * + * @param content 站内信模板的内容 + * @param params 站内信内容的参数 + * @return 格式化后的内容 + */ + @Override + public String formatNotifyTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java new file mode 100644 index 0000000..def3e5e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveService.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * OAuth2 批准 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 ApprovalStoreUserApprovalHandler 的功能,记录用户针对指定客户端的授权,减少手动确定。 + * + * @author 芋道源码 + */ +public interface OAuth2ApproveService { + + /** + * 获得指定用户,针对指定客户端的指定授权,是否通过 + * + * 参考 ApprovalStoreUserApprovalHandler 的 checkForPreApproval 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param requestedScopes 授权范围 + * @return 是否授权通过 + */ + boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection requestedScopes); + + /** + * 在用户发起批准时,基于 scopes 的选项,计算最终是否通过 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param requestedScopes 授权范围 + * @return 是否授权通过 + */ + boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map requestedScopes); + + /** + * 获得用户的批准列表,排除已过期的 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @return 是否授权通过 + */ + List getApproveList(Long userId, Integer userType, String clientId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java new file mode 100644 index 0000000..29f0f11 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ApproveMapper; +import com.google.common.annotations.VisibleForTesting; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * OAuth2 批准 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class OAuth2ApproveServiceImpl implements OAuth2ApproveService { + + /** + * 批准的过期时间,默认 30 天 + */ + private static final Integer TIMEOUT = 30 * 24 * 60 * 60; // 单位:秒 + + @Resource + private OAuth2ClientService oauth2ClientService; + + @Resource + private OAuth2ApproveMapper oauth2ApproveMapper; + + @Override + @Transactional + public boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection requestedScopes) { + // 第一步,基于 Client 的自动授权计算,如果 scopes 都在自动授权中,则返回 true 通过 + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + Assert.notNull(clientDO, "客户端不能为空"); // 防御性编程 + if (CollUtil.containsAll(clientDO.getAutoApproveScopes(), requestedScopes)) { + // gh-877 - if all scopes are auto approved, approvals still need to be added to the approval store. + LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT); + for (String scope : requestedScopes) { + saveApprove(userId, userType, clientId, scope, true, expireTime); + } + return true; + } + + // 第二步,算上用户已经批准的授权。如果 scopes 都包含,则返回 true + List approveDOs = getApproveList(userId, userType, clientId); + Set scopes = convertSet(approveDOs, OAuth2ApproveDO::getScope, + OAuth2ApproveDO::getApproved); // 只保留未过期的 + 同意的 + return CollUtil.containsAll(scopes, requestedScopes); + } + + @Override + @Transactional + public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map requestedScopes) { + // 如果 requestedScopes 为空,说明没有要求,则返回 true 通过 + if (CollUtil.isEmpty(requestedScopes)) { + return true; + } + + // 更新批准的信息 + boolean success = false; // 需要至少有一个同意 + LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT); + for (Map.Entry entry : requestedScopes.entrySet()) { + if (entry.getValue()) { + success = true; + } + saveApprove(userId, userType, clientId, entry.getKey(), entry.getValue(), expireTime); + } + return success; + } + + @Override + public List getApproveList(Long userId, Integer userType, String clientId) { + List approveDOs = oauth2ApproveMapper.selectListByUserIdAndUserTypeAndClientId( + userId, userType, clientId); + approveDOs.removeIf(o -> DateUtils.isExpired(o.getExpiresTime())); + return approveDOs; + } + + @VisibleForTesting + void saveApprove(Long userId, Integer userType, String clientId, + String scope, Boolean approved, LocalDateTime expireTime) { + // 先更新 + OAuth2ApproveDO approveDO = new OAuth2ApproveDO().setUserId(userId).setUserType(userType) + .setClientId(clientId).setScope(scope).setApproved(approved).setExpiresTime(expireTime); + if (oauth2ApproveMapper.update(approveDO) == 1) { + return; + } + // 失败,则说明不存在,进行更新 + oauth2ApproveMapper.insert(approveDO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java new file mode 100644 index 0000000..1073553 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; + +import javax.validation.Valid; +import java.util.Collection; + +/** + * OAuth2.0 Client Service 接口 + * + * 从功能上,和 JdbcClientDetailsService 的功能,提供客户端的操作 + * + * @author 芋道源码 + */ +public interface OAuth2ClientService { + + /** + * 创建 OAuth2 客户端 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createOAuth2Client(@Valid OAuth2ClientSaveReqVO createReqVO); + + /** + * 更新 OAuth2 客户端 + * + * @param updateReqVO 更新信息 + */ + void updateOAuth2Client(@Valid OAuth2ClientSaveReqVO updateReqVO); + + /** + * 删除 OAuth2 客户端 + * + * @param id 编号 + */ + void deleteOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端 + * + * @param id 编号 + * @return OAuth2 客户端 + */ + OAuth2ClientDO getOAuth2Client(Long id); + + /** + * 获得 OAuth2 客户端,从缓存中 + * + * @param clientId 客户端编号 + * @return OAuth2 客户端 + */ + OAuth2ClientDO getOAuth2ClientFromCache(String clientId); + + /** + * 获得 OAuth2 客户端分页 + * + * @param pageReqVO 分页查询 + * @return OAuth2 客户端分页 + */ + PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO); + + /** + * 从缓存中,校验客户端是否合法 + * + * @return 客户端 + */ + default OAuth2ClientDO validOAuthClientFromCache(String clientId) { + return validOAuthClientFromCache(clientId, null, null, null, null); + } + + /** + * 从缓存中,校验客户端是否合法 + * + * 非空时,进行校验 + * + * @param clientId 客户端编号 + * @param clientSecret 客户端密钥 + * @param authorizedGrantType 授权方式 + * @param scopes 授权范围 + * @param redirectUri 重定向地址 + * @return 客户端 + */ + OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, + Collection scopes, String redirectUri); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java new file mode 100644 index 0000000..66392b1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java @@ -0,0 +1,153 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * OAuth2.0 Client Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class OAuth2ClientServiceImpl implements OAuth2ClientService { + + @Resource + private OAuth2ClientMapper oauth2ClientMapper; + + @Override + public Long createOAuth2Client(OAuth2ClientSaveReqVO createReqVO) { + validateClientIdExists(null, createReqVO.getClientId()); + // 插入 + OAuth2ClientDO client = BeanUtils.toBean(createReqVO, OAuth2ClientDO.class); + oauth2ClientMapper.insert(client); + return client.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 clientId 字段,不好清理 + public void updateOAuth2Client(OAuth2ClientSaveReqVO updateReqVO) { + // 校验存在 + validateOAuth2ClientExists(updateReqVO.getId()); + // 校验 Client 未被占用 + validateClientIdExists(updateReqVO.getId(), updateReqVO.getClientId()); + + // 更新 + OAuth2ClientDO updateObj = BeanUtils.toBean(updateReqVO, OAuth2ClientDO.class); + oauth2ClientMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 key,不好清理 + public void deleteOAuth2Client(Long id) { + // 校验存在 + validateOAuth2ClientExists(id); + // 删除 + oauth2ClientMapper.deleteById(id); + } + + private void validateOAuth2ClientExists(Long id) { + if (oauth2ClientMapper.selectById(id) == null) { + throw exception(OAUTH2_CLIENT_NOT_EXISTS); + } + } + + @VisibleForTesting + void validateClientIdExists(Long id, String clientId) { + OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId); + if (client == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的客户端 + if (id == null) { + throw exception(OAUTH2_CLIENT_EXISTS); + } + if (!client.getId().equals(id)) { + throw exception(OAUTH2_CLIENT_EXISTS); + } + } + + @Override + public OAuth2ClientDO getOAuth2Client(Long id) { + return oauth2ClientMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId", + unless = "#result == null") + public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) { + return oauth2ClientMapper.selectByClientId(clientId); + } + + @Override + public PageResult getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) { + return oauth2ClientMapper.selectPage(pageReqVO); + } + + @Override + public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, + Collection scopes, String redirectUri) { + // 校验客户端存在、且开启 + OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientId); + if (client == null) { + throw exception(OAUTH2_CLIENT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(client.getStatus())) { + throw exception(OAUTH2_CLIENT_DISABLE); + } + + // 校验客户端密钥 + if (StrUtil.isNotEmpty(clientSecret) && ObjectUtil.notEqual(client.getSecret(), clientSecret)) { + throw exception(OAUTH2_CLIENT_CLIENT_SECRET_ERROR); + } + // 校验授权方式 + if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) { + throw exception(OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); + } + // 校验授权范围 + if (CollUtil.isNotEmpty(scopes) && !CollUtil.containsAll(client.getScopes(), scopes)) { + throw exception(OAUTH2_CLIENT_SCOPE_OVER); + } + // 校验回调地址 + if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, client.getRedirectUris())) { + throw exception(OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, redirectUri); + } + return client; + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private OAuth2ClientServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java new file mode 100644 index 0000000..5ace87e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; + +import java.util.List; + +/** + * OAuth2.0 授权码 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 JdbcAuthorizationCodeServices 的功能,提供授权码的操作 + * + * @author 芋道源码 + */ +public interface OAuth2CodeService { + + /** + * 创建授权码 + * + * 参考 JdbcAuthorizationCodeServices 的 createAuthorizationCode 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 授权码的信息 + */ + OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, + List scopes, String redirectUri, String state); + + /** + * 使用授权码 + * + * @param code 授权码 + */ + OAuth2CodeDO consumeAuthorizationCode(String code); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImpl.java new file mode 100644 index 0000000..df6d4c8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImpl.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_EXPIRE; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS; + +/** + * OAuth2.0 授权码 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class OAuth2CodeServiceImpl implements OAuth2CodeService { + + /** + * 授权码的过期时间,默认 5 分钟 + */ + private static final Integer TIMEOUT = 5 * 60; + + @Resource + private OAuth2CodeMapper oauth2CodeMapper; + + @Override + public OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, + List scopes, String redirectUri, String state) { + OAuth2CodeDO codeDO = new OAuth2CodeDO().setCode(generateCode()) + .setUserId(userId).setUserType(userType) + .setClientId(clientId).setScopes(scopes) + .setExpiresTime(LocalDateTime.now().plusSeconds(TIMEOUT)) + .setRedirectUri(redirectUri).setState(state); + oauth2CodeMapper.insert(codeDO); + return codeDO; + } + + @Override + public OAuth2CodeDO consumeAuthorizationCode(String code) { + OAuth2CodeDO codeDO = oauth2CodeMapper.selectByCode(code); + if (codeDO == null) { + throw exception(OAUTH2_CODE_NOT_EXISTS); + } + if (DateUtils.isExpired(codeDO.getExpiresTime())) { + throw exception(OAUTH2_CODE_EXPIRE); + } + oauth2CodeMapper.deleteById(codeDO.getId()); + return codeDO; + } + + private static String generateCode() { + return IdUtil.fastSimpleUUID(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java new file mode 100644 index 0000000..fef1d5e --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantService.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; + +import java.util.List; + +/** + * OAuth2 授予 Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 TokenGranter 的功能,提供访问令牌、刷新令牌的操作 + * + * 将自身的 AdminUser 用户,授权给第三方应用,采用 OAuth2.0 的协议。 + * + * 问题:为什么自身也作为一个第三方应用,也走这套流程呢? + * 回复:当然可以这么做,采用 password 模式。考虑到大多数开发者使用不到这个特性,OAuth2.0 毕竟有一定学习成本,所以暂时没有采取这种方式。 + * + * @author 芋道源码 + */ +public interface OAuth2GrantService { + + /** + * 简化模式 + * + * 对应 Spring Security OAuth2 的 ImplicitTokenGranter 功能 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, List scopes); + + /** + * 授权码模式,第一阶段,获得 code 授权码 + * + * 对应 Spring Security OAuth2 的 AuthorizationEndpoint 的 generateCode 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 授权码 + */ + String grantAuthorizationCodeForCode(Long userId, Integer userType, + String clientId, List scopes, + String redirectUri, String state); + + /** + * 授权码模式,第二阶段,获得 accessToken 访问令牌 + * + * 对应 Spring Security OAuth2 的 AuthorizationCodeTokenGranter 功能 + * + * @param clientId 客户端编号 + * @param code 授权码 + * @param redirectUri 重定向 URI + * @param state 状态 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, + String redirectUri, String state); + + /** + * 密码模式 + * + * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能 + * + * @param username 账号 + * @param password 密码 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantPassword(String username, String password, + String clientId, List scopes); + + /** + * 刷新模式 + * + * 对应 Spring Security OAuth2 的 ResourceOwnerPasswordTokenGranter 功能 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId); + + /** + * 客户端模式 + * + * 对应 Spring Security OAuth2 的 ClientCredentialsTokenGranter 功能 + * + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌 + */ + OAuth2AccessTokenDO grantClientCredentials(String clientId, List scopes); + + /** + * 移除访问令牌 + * + * 对应 Spring Security OAuth2 的 ConsumerTokenServices 的 revokeToken 方法 + * + * @param accessToken 访问令牌 + * @param clientId 客户端编号 + * @return 是否移除到 + */ + boolean revokeToken(String clientId, String accessToken); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java new file mode 100644 index 0000000..adb07f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * OAuth2 授予 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2GrantServiceImpl implements OAuth2GrantService { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private OAuth2CodeService oauth2CodeService; + @Resource + private AdminAuthService adminAuthService; + + @Override + public OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, List scopes) { + return oauth2TokenService.createAccessToken(userId, userType, clientId, scopes); + } + + @Override + public String grantAuthorizationCodeForCode(Long userId, Integer userType, + String clientId, List scopes, + String redirectUri, String state) { + return oauth2CodeService.createAuthorizationCode(userId, userType, clientId, scopes, + redirectUri, state).getCode(); + } + + @Override + public OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, + String redirectUri, String state) { + OAuth2CodeDO codeDO = oauth2CodeService.consumeAuthorizationCode(code); + Assert.notNull(codeDO, "授权码不能为空"); // 防御性编程 + // 校验 clientId 是否匹配 + if (!StrUtil.equals(clientId, codeDO.getClientId())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_CLIENT_ID_MISMATCH); + } + // 校验 redirectUri 是否匹配 + if (!StrUtil.equals(redirectUri, codeDO.getRedirectUri())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_REDIRECT_URI_MISMATCH); + } + // 校验 state 是否匹配 + state = StrUtil.nullToDefault(state, ""); // 数据库 state 为 null 时,会设置为 "" 空串 + if (!StrUtil.equals(state, codeDO.getState())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_STATE_MISMATCH); + } + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(codeDO.getUserId(), codeDO.getUserType(), + codeDO.getClientId(), codeDO.getScopes()); + } + + @Override + public OAuth2AccessTokenDO grantPassword(String username, String password, String clientId, List scopes) { + // 使用账号 + 密码进行登录 + AdminUserDO user = adminAuthService.authenticate(username, password); + Assert.notNull(user, "用户不能为空!"); // 防御性编程 + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(user.getId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes); + } + + @Override + public OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId) { + return oauth2TokenService.refreshAccessToken(refreshToken, clientId); + } + + @Override + public OAuth2AccessTokenDO grantClientCredentials(String clientId, List scopes) { + // TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景 + throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式"); + } + + @Override + public boolean revokeToken(String clientId, String accessToken) { + // 先查询,保证 clientId 时匹配的 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.getAccessToken(accessToken); + if (accessTokenDO == null || ObjectUtil.notEqual(clientId, accessTokenDO.getClientId())) { + return false; + } + // 再删除 + return oauth2TokenService.removeAccessToken(accessToken) != null; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java new file mode 100644 index 0000000..977d935 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenService.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; + +import java.util.List; + +/** + * OAuth2.0 Token Service 接口 + * + * 从功能上,和 Spring Security OAuth 的 DefaultTokenServices + JdbcTokenStore 的功能,提供访问令牌、刷新令牌的操作 + * + * @author 芋道源码 + */ +public interface OAuth2TokenService { + + /** + * 创建访问令牌 + * 注意:该流程中,会包含创建刷新令牌的创建 + * + * 参考 DefaultTokenServices 的 createAccessToken 方法 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @param clientId 客户端编号 + * @param scopes 授权范围 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes); + + /** + * 刷新访问令牌 + * + * 参考 DefaultTokenServices 的 refreshAccessToken 方法 + * + * @param refreshToken 刷新令牌 + * @param clientId 客户端编号 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId); + + /** + * 获得访问令牌 + * + * 参考 DefaultTokenServices 的 getAccessToken 方法 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO getAccessToken(String accessToken); + + /** + * 校验访问令牌 + * + * @param accessToken 访问令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO checkAccessToken(String accessToken); + + /** + * 移除访问令牌 + * 注意:该流程中,会移除相关的刷新令牌 + * + * 参考 DefaultTokenServices 的 revokeToken 方法 + * + * @param accessToken 刷新令牌 + * @return 访问令牌的信息 + */ + OAuth2AccessTokenDO removeAccessToken(String accessToken); + + /** + * 获得访问令牌分页 + * + * @param reqVO 请求 + * @return 访问令牌分页 + */ + PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java new file mode 100644 index 0000000..d2cfa71 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java @@ -0,0 +1,197 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; +import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * OAuth2.0 Token Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class OAuth2TokenServiceImpl implements OAuth2TokenService { + + @Resource + private OAuth2AccessTokenMapper oauth2AccessTokenMapper; + @Resource + private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; + + @Resource + private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO; + + @Resource + private OAuth2ClientService oauth2ClientService; + @Resource + @Lazy // 懒加载,避免循环依赖 + private AdminUserService adminUserService; + + @Override + @Transactional + public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List scopes) { + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + // 创建刷新令牌 + OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO, scopes); + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + public OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId) { + // 查询访问令牌 + OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(refreshToken); + if (refreshTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "无效的刷新令牌"); + } + + // 校验 Client 匹配 + OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId); + if (ObjectUtil.notEqual(clientId, refreshTokenDO.getClientId())) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "刷新令牌的客户端编号不正确"); + } + + // 移除相关的访问令牌 + List accessTokenDOs = oauth2AccessTokenMapper.selectListByRefreshToken(refreshToken); + if (CollUtil.isNotEmpty(accessTokenDOs)) { + oauth2AccessTokenMapper.deleteBatchIds(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getId)); + oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs, OAuth2AccessTokenDO::getAccessToken)); + } + + // 已过期的情况下,删除刷新令牌 + if (DateUtils.isExpired(refreshTokenDO.getExpiresTime())) { + oauth2RefreshTokenMapper.deleteById(refreshTokenDO.getId()); + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "刷新令牌已过期"); + } + + // 创建访问令牌 + return createOAuth2AccessToken(refreshTokenDO, clientDO); + } + + @Override + public OAuth2AccessTokenDO getAccessToken(String accessToken) { + // 优先从 Redis 中获取 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken); + if (accessTokenDO != null) { + return accessTokenDO; + } + + // 获取不到,从 MySQL 中获取 + accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + // 如果在 MySQL 存在,则往 Redis 中写入 + if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + oauth2AccessTokenRedisDAO.set(accessTokenDO); + } + return accessTokenDO; + } + + @Override + public OAuth2AccessTokenDO checkAccessToken(String accessToken) { + OAuth2AccessTokenDO accessTokenDO = getAccessToken(accessToken); + if (accessTokenDO == null) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌不存在"); + } + if (DateUtils.isExpired(accessTokenDO.getExpiresTime())) { + throw exception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(), "访问令牌已过期"); + } + return accessTokenDO; + } + + @Override + public OAuth2AccessTokenDO removeAccessToken(String accessToken) { + // 删除访问令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken); + if (accessTokenDO == null) { + return null; + } + oauth2AccessTokenMapper.deleteById(accessTokenDO.getId()); + oauth2AccessTokenRedisDAO.delete(accessToken); + // 删除刷新令牌 + oauth2RefreshTokenMapper.deleteByRefreshToken(accessTokenDO.getRefreshToken()); + return accessTokenDO; + } + + @Override + public PageResult getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO) { + return oauth2AccessTokenMapper.selectPage(reqVO); + } + + private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, OAuth2ClientDO clientDO) { + OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken()) + .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType()) + .setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType())) + .setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes()) + .setRefreshToken(refreshTokenDO.getRefreshToken()) + .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds())); + accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号 + oauth2AccessTokenMapper.insert(accessTokenDO); + // 记录到 Redis 中 + oauth2AccessTokenRedisDAO.set(accessTokenDO); + return accessTokenDO; + } + + private OAuth2RefreshTokenDO createOAuth2RefreshToken(Long userId, Integer userType, OAuth2ClientDO clientDO, List scopes) { + OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setRefreshToken(generateRefreshToken()) + .setUserId(userId).setUserType(userType) + .setClientId(clientDO.getClientId()).setScopes(scopes) + .setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds())); + oauth2RefreshTokenMapper.insert(refreshToken); + return refreshToken; + } + + /** + * 加载用户信息,方便 {@link cn.iocoder.yudao.framework.security.core.LoginUser} 获取到昵称、部门等信息 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 用户信息 + */ + private Map buildUserInfo(Long userId, Integer userType) { + if (userType.equals(UserTypeEnum.ADMIN.getValue())) { + AdminUserDO user = adminUserService.getUser(userId); + return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname()) + .put(LoginUser.INFO_KEY_DEPT_ID, StrUtil.toStringOrNull(user.getDeptId())).build(); + } else if (userType.equals(UserTypeEnum.MEMBER.getValue())) { + // 注意:目前 Member 暂时不读取,可以按需实现 + return Collections.emptyMap(); + } + return null; + } + + private static String generateAccessToken() { + return IdUtil.fastSimpleUUID(); + } + + private static String generateRefreshToken() { + return IdUtil.fastSimpleUUID(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java new file mode 100644 index 0000000..d74dc61 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; + +import java.util.Collection; +import java.util.List; + +/** + * 菜单 Service 接口 + * + * @author 芋道源码 + */ +public interface MenuService { + + /** + * 创建菜单 + * + * @param createReqVO 菜单信息 + * @return 创建出来的菜单编号 + */ + Long createMenu(MenuSaveVO createReqVO); + + /** + * 更新菜单 + * + * @param updateReqVO 菜单信息 + */ + void updateMenu(MenuSaveVO updateReqVO); + + /** + * 删除菜单 + * + * @param id 菜单编号 + */ + void deleteMenu(Long id); + + /** + * 获得所有菜单列表 + * + * @return 菜单列表 + */ + List getMenuList(); + + /** + * 基于租户,筛选菜单列表 + * 注意,如果是系统租户,返回的还是全菜单 + * + * @param reqVO 筛选条件请求 VO + * @return 菜单列表 + */ + List getMenuListByTenant(MenuListReqVO reqVO); + + /** + * 过滤掉关闭的菜单及其子菜单 + * + * @param list 菜单列表 + * @return 过滤后的菜单列表 + */ + List filterDisableMenus(List list); + + /** + * 筛选菜单列表 + * + * @param reqVO 筛选条件请求 VO + * @return 菜单列表 + */ + List getMenuList(MenuListReqVO reqVO); + + /** + * 获得权限对应的菜单编号数组 + * + * @param permission 权限标识 + * @return 数组 + */ + List getMenuIdListByPermissionFromCache(String permission); + + /** + * 获得菜单 + * + * @param id 菜单编号 + * @return 菜单 + */ + MenuDO getMenu(Long id); + + /** + * 获得菜单数组 + * + * @param ids 菜单编号数组 + * @return 菜单数组 + */ + List getMenuList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java new file mode 100644 index 0000000..a31f5fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java @@ -0,0 +1,260 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 菜单 Service 实现 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class MenuServiceImpl implements MenuService { + + @Resource + private MenuMapper menuMapper; + @Resource + private PermissionService permissionService; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantService tenantService; + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", + condition = "#createReqVO.permission != null") + public Long createMenu(MenuSaveVO createReqVO) { + // 校验父菜单存在 + validateParentMenu(createReqVO.getParentId(), null); + // 校验菜单(自己) + validateMenu(createReqVO.getParentId(), createReqVO.getName(), null); + + // 插入数据库 + MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class); + initMenuProperty(menu); + menuMapper.insert(menu); + // 返回 + return menu.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 + public void updateMenu(MenuSaveVO updateReqVO) { + // 校验更新的菜单是否存在 + if (menuMapper.selectById(updateReqVO.getId()) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 校验父菜单存在 + validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId()); + // 校验菜单(自己) + validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId()); + + // 更新到数据库 + MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class); + initMenuProperty(updateObj); + menuMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 + public void deleteMenu(Long id) { + // 校验是否还有子菜单 + if (menuMapper.selectCountByParentId(id) > 0) { + throw exception(MENU_EXISTS_CHILDREN); + } + // 校验删除的菜单是否存在 + if (menuMapper.selectById(id) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 标记删除 + menuMapper.deleteById(id); + // 删除授予给角色的权限 + permissionService.processMenuDeleted(id); + } + + @Override + public List getMenuList() { + return menuMapper.selectList(); + } + + @Override + public List getMenuListByTenant(MenuListReqVO reqVO) { + // 查询所有菜单,并过滤掉关闭的节点 + List menus = getMenuList(reqVO); + // 开启多租户的情况下,需要过滤掉未开通的菜单 + tenantService.handleTenantMenu(menuIds -> menus.removeIf(menu -> !CollUtil.contains(menuIds, menu.getId()))); + return menus; + } + + @Override + public List filterDisableMenus(List menuList) { + if (CollUtil.isEmpty(menuList)){ + return Collections.emptyList(); + } + Map menuMap = convertMap(menuList, MenuDO::getId); + + // 遍历 menu 菜单,查找不是禁用的菜单,添加到 enabledMenus 结果 + List enabledMenus = new ArrayList<>(); + Set disabledMenuCache = new HashSet<>(); // 存下递归搜索过被禁用的菜单,防止重复的搜索 + for (MenuDO menu : menuList) { + if (isMenuDisabled(menu, menuMap, disabledMenuCache)) { + continue; + } + enabledMenus.add(menu); + } + return enabledMenus; + } + + private boolean isMenuDisabled(MenuDO node, Map menuMap, Set disabledMenuCache) { + // 如果已经判定是禁用的节点,直接结束 + if (disabledMenuCache.contains(node.getId())) { + return true; + } + + // 1. 遍历到 parentId 为根节点,则无需判断 + Long parentId = node.getParentId(); + if (ObjUtil.equal(parentId, ID_ROOT)) { + if (CommonStatusEnum.isDisable(node.getStatus())) { + disabledMenuCache.add(node.getId()); + return true; + } + return false; + } + + // 2. 继续遍历 parent 节点 + MenuDO parent = menuMap.get(parentId); + if (parent == null || isMenuDisabled(parent, menuMap, disabledMenuCache)) { + disabledMenuCache.add(node.getId()); + return true; + } + return false; + } + + @Override + public List getMenuList(MenuListReqVO reqVO) { + return menuMapper.selectList(reqVO); + } + + @Override + @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") + public List getMenuIdListByPermissionFromCache(String permission) { + List menus = menuMapper.selectListByPermission(permission); + return convertList(menus, MenuDO::getId); + } + + @Override + public MenuDO getMenu(Long id) { + return menuMapper.selectById(id); + } + + @Override + public List getMenuList(Collection ids) { + // 当 ids 为空时,返回一个空的实例对象 + if (CollUtil.isEmpty(ids)) { + return Lists.newArrayList(); + } + return menuMapper.selectBatchIds(ids); + } + + /** + * 校验父菜单是否合法 + *

+ * 1. 不能设置自己为父菜单 + * 2. 父菜单不存在 + * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 + * + * @param parentId 父菜单编号 + * @param childId 当前菜单编号 + */ + @VisibleForTesting + void validateParentMenu(Long parentId, Long childId) { + if (parentId == null || ID_ROOT.equals(parentId)) { + return; + } + // 不能设置自己为父菜单 + if (parentId.equals(childId)) { + throw exception(MENU_PARENT_ERROR); + } + MenuDO menu = menuMapper.selectById(parentId); + // 父菜单不存在 + if (menu == null) { + throw exception(MENU_PARENT_NOT_EXISTS); + } + // 父菜单必须是目录或者菜单类型 + if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) + && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { + throw exception(MENU_PARENT_NOT_DIR_OR_MENU); + } + } + + /** + * 校验菜单是否合法 + *

+ * 1. 校验相同父菜单编号下,是否存在相同的菜单名 + * + * @param name 菜单名字 + * @param parentId 父菜单编号 + * @param id 菜单编号 + */ + @VisibleForTesting + void validateMenu(Long parentId, String name, Long id) { + MenuDO menu = menuMapper.selectByParentIdAndName(parentId, name); + if (menu == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的菜单 + if (id == null) { + throw exception(MENU_NAME_DUPLICATE); + } + if (!menu.getId().equals(id)) { + throw exception(MENU_NAME_DUPLICATE); + } + } + + /** + * 初始化菜单的通用属性。 + *

+ * 例如说,只有目录或者菜单类型的菜单,才设置 icon + * + * @param menu 菜单 + */ + private void initMenuProperty(MenuDO menu) { + // 菜单为按钮类型时,无需 component、icon、path 属性,进行置空 + if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) { + menu.setComponent(""); + menu.setComponentName(""); + menu.setIcon(""); + menu.setPath(""); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java new file mode 100644 index 0000000..efc4714 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; + +import java.util.Collection; +import java.util.Set; + +import static java.util.Collections.singleton; + +/** + * 权限 Service 接口 + *

+ * 提供用户-角色、角色-菜单、角色-部门的关联权限处理 + * + * @author 芋道源码 + */ +public interface PermissionService { + + /** + * 判断是否有权限,任一一个即可 + * + * @param userId 用户编号 + * @param permissions 权限 + * @return 是否 + */ + boolean hasAnyPermissions(Long userId, String... permissions); + + /** + * 判断是否有角色,任一一个即可 + * + * @param roles 角色数组 + * @return 是否 + */ + boolean hasAnyRoles(Long userId, String... roles); + + // ========== 角色-菜单的相关方法 ========== + + /** + * 设置角色菜单 + * + * @param roleId 角色编号 + * @param menuIds 菜单编号集合 + */ + void assignRoleMenu(Long roleId, Set menuIds); + + /** + * 处理角色删除时,删除关联授权数据 + * + * @param roleId 角色编号 + */ + void processRoleDeleted(Long roleId); + + /** + * 处理菜单删除时,删除关联授权数据 + * + * @param menuId 菜单编号 + */ + void processMenuDeleted(Long menuId); + + /** + * 获得角色拥有的菜单编号集合 + * + * @param roleId 角色编号 + * @return 菜单编号集合 + */ + default Set getRoleMenuListByRoleId(Long roleId) { + return getRoleMenuListByRoleId(singleton(roleId)); + } + + /** + * 获得角色们拥有的菜单编号集合 + * + * @param roleIds 角色编号数组 + * @return 菜单编号集合 + */ + Set getRoleMenuListByRoleId(Collection roleIds); + + /** + * 获得拥有指定菜单的角色编号数组,从缓存中获取 + * + * @param menuId 菜单编号 + * @return 角色编号数组 + */ + Set getMenuRoleIdListByMenuIdFromCache(Long menuId); + + // ========== 用户-角色的相关方法 ========== + + /** + * 设置用户角色 + * + * @param userId 角色编号 + * @param roleIds 角色编号集合 + */ + void assignUserRole(Long userId, Set roleIds); + + /** + * 处理用户删除时,删除关联授权数据 + * + * @param userId 用户编号 + */ + void processUserDeleted(Long userId); + + /** + * 获得拥有多个角色的用户编号集合 + * + * @param roleIds 角色编号集合 + * @return 用户编号集合 + */ + Set getUserRoleIdListByRoleId(Collection roleIds); + + /** + * 获得用户拥有的角色编号集合 + * + * @param userId 用户编号 + * @return 角色编号集合 + */ + Set getUserRoleIdListByUserId(Long userId); + + /** + * 获得用户拥有的角色编号集合,从缓存中获取 + * + * @param userId 用户编号 + * @return 角色编号集合 + */ + Set getUserRoleIdListByUserIdFromCache(Long userId); + + // ========== 用户-部门的相关方法 ========== + + /** + * 设置角色的数据权限 + * + * @param roleId 角色编号 + * @param dataScope 数据范围 + * @param dataScopeDeptIds 部门编号数组 + */ + void assignRoleDataScope(Long roleId, Integer dataScope, Set dataScopeDeptIds); + + /** + * 获得登陆用户的部门数据权限 + * + * @param userId 用户编号 + * @return 部门数据权限 + */ + DeptDataPermissionRespDTO getDeptDataPermission(Long userId); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java new file mode 100644 index 0000000..dba2831 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java @@ -0,0 +1,337 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; +import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Suppliers; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.function.Supplier; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 权限 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class PermissionServiceImpl implements PermissionService { + + @Resource + private RoleMenuMapper roleMenuMapper; + @Resource + private UserRoleMapper userRoleMapper; + + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private DeptService deptService; + @Resource + private AdminUserService userService; + + @Override + public boolean hasAnyPermissions(Long userId, String... permissions) { + // 如果为空,说明已经有权限 + if (ArrayUtil.isEmpty(permissions)) { + return true; + } + + // 获得当前登录的角色。如果为空,说明没有权限 + List roles = getEnableUserRoleListByUserIdFromCache(userId); + if (CollUtil.isEmpty(roles)) { + return false; + } + + // 情况一:遍历判断每个权限,如果有一满足,说明有权限 + for (String permission : permissions) { + if (hasAnyPermission(roles, permission)) { + return true; + } + } + + // 情况二:如果是超管,也说明有权限 + return roleService.hasAnySuperAdmin(convertSet(roles, RoleDO::getId)); + } + + /** + * 判断指定角色,是否拥有该 permission 权限 + * + * @param roles 指定角色数组 + * @param permission 权限标识 + * @return 是否拥有 + */ + private boolean hasAnyPermission(List roles, String permission) { + List menuIds = menuService.getMenuIdListByPermissionFromCache(permission); + // 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限 + if (CollUtil.isEmpty(menuIds)) { + return false; + } + + // 判断是否有权限 + Set roleIds = convertSet(roles, RoleDO::getId); + for (Long menuId : menuIds) { + // 获得拥有该菜单的角色编号集合 + Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); + // 如果有交集,说明有权限 + if (CollUtil.containsAny(menuRoleIds, roleIds)) { + return true; + } + } + return false; + } + + @Override + public boolean hasAnyRoles(Long userId, String... roles) { + // 如果为空,说明已经有权限 + if (ArrayUtil.isEmpty(roles)) { + return true; + } + + // 获得当前登录的角色。如果为空,说明没有权限 + List roleList = getEnableUserRoleListByUserIdFromCache(userId); + if (CollUtil.isEmpty(roleList)) { + return false; + } + + // 判断是否有角色 + Set userRoles = convertSet(roleList, RoleDO::getCode); + return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); + } + + // ========== 角色-菜单的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 + public void assignRoleMenu(Long roleId, Set menuIds) { + // 获得角色拥有菜单编号 + Set dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); + // 计算新增和删除的菜单编号 + Set menuIdList = CollUtil.emptyIfNull(menuIds); + Collection createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); + Collection deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); + // 执行新增和删除。对于已经授权的菜单,不用做任何处理 + if (CollUtil.isNotEmpty(createMenuIds)) { + roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { + RoleMenuDO entity = new RoleMenuDO(); + entity.setRoleId(roleId); + entity.setMenuId(menuId); + return entity; + })); + } + if (CollUtil.isNotEmpty(deleteMenuIds)) { + roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + @Caching(evict = { + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, + allEntries = true), // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 menu 缓存们 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, + allEntries = true) // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 user 缓存们 + }) + public void processRoleDeleted(Long roleId) { + // 标记删除 UserRole + userRoleMapper.deleteListByRoleId(roleId); + // 标记删除 RoleMenu + roleMenuMapper.deleteListByRoleId(roleId); + } + + @Override + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") + public void processMenuDeleted(Long menuId) { + roleMenuMapper.deleteListByMenuId(menuId); + } + + @Override + public Set getRoleMenuListByRoleId(Collection roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return Collections.emptySet(); + } + + // 如果是管理员的情况下,获取全部菜单编号 + if (roleService.hasAnySuperAdmin(roleIds)) { + return convertSet(menuService.getMenuList(), MenuDO::getId); + } + // 如果是非管理员的情况下,获得拥有的菜单编号 + return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); + } + + @Override + @Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") + public Set getMenuRoleIdListByMenuIdFromCache(Long menuId) { + return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); + } + + // ========== 用户-角色的相关方法 ========== + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void assignUserRole(Long userId, Set roleIds) { + // 获得角色拥有角色编号 + Set dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), + UserRoleDO::getRoleId); + // 计算新增和删除的角色编号 + Set roleIdList = CollUtil.emptyIfNull(roleIds); + Collection createRoleIds = CollUtil.subtract(roleIdList, dbRoleIds); + Collection deleteMenuIds = CollUtil.subtract(dbRoleIds, roleIdList); + // 执行新增和删除。对于已经授权的角色,不用做任何处理 + if (!CollectionUtil.isEmpty(createRoleIds)) { + userRoleMapper.insertBatch(CollectionUtils.convertList(createRoleIds, roleId -> { + UserRoleDO entity = new UserRoleDO(); + entity.setUserId(userId); + entity.setRoleId(roleId); + return entity; + })); + } + if (!CollectionUtil.isEmpty(deleteMenuIds)) { + userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); + } + } + + @Override + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public void processUserDeleted(Long userId) { + userRoleMapper.deleteListByUserId(userId); + } + + @Override + public Set getUserRoleIdListByUserId(Long userId) { + return convertSet(userRoleMapper.selectListByUserId(userId), UserRoleDO::getRoleId); + } + + @Override + @Cacheable(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") + public Set getUserRoleIdListByUserIdFromCache(Long userId) { + return getUserRoleIdListByUserId(userId); + } + + @Override + public Set getUserRoleIdListByRoleId(Collection roleIds) { + return convertSet(userRoleMapper.selectListByRoleIds(roleIds), UserRoleDO::getUserId); + } + + /** + * 获得用户拥有的角色,并且这些角色是开启状态的 + * + * @param userId 用户编号 + * @return 用户拥有的角色 + */ + @VisibleForTesting + List getEnableUserRoleListByUserIdFromCache(Long userId) { + // 获得用户拥有的角色编号 + Set roleIds = getSelf().getUserRoleIdListByUserIdFromCache(userId); + // 获得角色数组,并移除被禁用的 + List roles = roleService.getRoleListFromCache(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); + return roles; + } + + // ========== 用户-部门的相关方法 ========== + + @Override + public void assignRoleDataScope(Long roleId, Integer dataScope, Set dataScopeDeptIds) { + roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); + } + + @Override + @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题 + public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { + // 获得用户的角色 + List roles = getEnableUserRoleListByUserIdFromCache(userId); + + // 如果角色为空,则只能查看自己 + DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); + if (CollUtil.isEmpty(roles)) { + result.setSelf(true); + return result; + } + + // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询 + Supplier userDeptId = Suppliers.memoize(() -> userService.getUser(userId).getDeptId()); + // 遍历每个角色,计算 + for (RoleDO role : roles) { + // 为空时,跳过 + if (role.getDataScope() == null) { + continue; + } + // 情况一,ALL + if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) { + result.setAll(true); + continue; + } + // 情况二,DEPT_CUSTOM + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) { + CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); + // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。 + // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉 + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况三,DEPT_ONLY + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { + CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况四,DEPT_DEPT_AND_CHILD + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { + CollUtil.addAll(result.getDeptIds(), deptService.getChildDeptIdListFromCache(userDeptId.get())); + // 添加本身部门编号 + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); + continue; + } + // 情况五,SELF + if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) { + result.setSelf(true); + continue; + } + // 未知情况,error log 即可 + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, toJsonString(result)); + } + return result; + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PermissionServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java new file mode 100644 index 0000000..44ec110 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java @@ -0,0 +1,124 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 角色 Service 接口 + * + * @author 芋道源码 + */ +public interface RoleService { + + /** + * 创建角色 + * + * @param createReqVO 创建角色信息 + * @param type 角色类型 + * @return 角色编号 + */ + Long createRole(@Valid RoleSaveReqVO createReqVO, Integer type); + + /** + * 更新角色 + * + * @param updateReqVO 更新角色信息 + */ + void updateRole(@Valid RoleSaveReqVO updateReqVO); + + /** + * 删除角色 + * + * @param id 角色编号 + */ + void deleteRole(Long id); + + /** + * 设置角色的数据权限 + * + * @param id 角色编号 + * @param dataScope 数据范围 + * @param dataScopeDeptIds 部门编号数组 + */ + void updateRoleDataScope(Long id, Integer dataScope, Set dataScopeDeptIds); + + /** + * 获得角色 + * + * @param id 角色编号 + * @return 角色 + */ + RoleDO getRole(Long id); + + /** + * 获得角色,从缓存中 + * + * @param id 角色编号 + * @return 角色 + */ + RoleDO getRoleFromCache(Long id); + + /** + * 获得角色列表 + * + * @param ids 角色编号数组 + * @return 角色列表 + */ + List getRoleList(Collection ids); + + /** + * 获得角色数组,从缓存中 + * + * @param ids 角色编号数组 + * @return 角色数组 + */ + List getRoleListFromCache(Collection ids); + + /** + * 获得角色列表 + * + * @param statuses 筛选的状态 + * @return 角色列表 + */ + List getRoleListByStatus(Collection statuses); + + /** + * 获得所有角色列表 + * + * @return 角色列表 + */ + List getRoleList(); + + /** + * 获得角色分页 + * + * @param reqVO 角色分页查询 + * @return 角色分页结果 + */ + PageResult getRolePage(RolePageReqVO reqVO); + + /** + * 判断角色编号数组中,是否有管理员 + * + * @param ids 角色编号数组 + * @return 是否有管理员 + */ + boolean hasAnySuperAdmin(Collection ids); + + /** + * 校验角色们是否有效。如下情况,视为无效: + * 1. 角色编号不存在 + * 2. 角色被禁用 + * + * @param ids 角色编号数组 + */ + void validateRoleList(Collection ids); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java new file mode 100644 index 0000000..389f28b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java @@ -0,0 +1,261 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import com.google.common.annotations.VisibleForTesting; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*; + +/** + * 角色 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class RoleServiceImpl implements RoleService { + + @Resource + private PermissionService permissionService; + + @Resource + private RoleMapper roleMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}", + success = SYSTEM_ROLE_CREATE_SUCCESS) + public Long createRole(RoleSaveReqVO createReqVO, Integer type) { + // 1. 校验角色 + validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null); + + // 2. 插入到数据库 + RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class) + .setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType())) + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限 + roleMapper.insert(role); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("role", role); + return role.getId(); + } + + @Override + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id") + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = SYSTEM_ROLE_UPDATE_SUCCESS) + public void updateRole(RoleSaveReqVO updateReqVO) { + // 1.1 校验是否可以更新 + RoleDO role = validateRoleForUpdate(updateReqVO.getId()); + // 1.2 校验角色的唯一字段是否重复 + validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId()); + + // 2. 更新到数据库 + RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class); + roleMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("role", role); + } + + @Override + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") + public void updateRoleDataScope(Long id, Integer dataScope, Set dataScopeDeptIds) { + // 校验是否可以更新 + validateRoleForUpdate(id); + + // 更新数据范围 + RoleDO updateObject = new RoleDO(); + updateObject.setId(id); + updateObject.setDataScope(dataScope); + updateObject.setDataScopeDeptIds(dataScopeDeptIds); + roleMapper.updateById(updateObject); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = SYSTEM_ROLE_DELETE_SUCCESS) + public void deleteRole(Long id) { + // 1. 校验是否可以更新 + RoleDO role = validateRoleForUpdate(id); + + // 2.1 标记删除 + roleMapper.deleteById(id); + // 2.2 删除相关数据 + permissionService.processRoleDeleted(id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(role, RoleSaveReqVO.class)); + LogRecordContext.putVariable("role", role); + } + + /** + * 校验角色的唯一字段是否重复 + * + * 1. 是否存在相同名字的角色 + * 2. 是否存在相同编码的角色 + * + * @param name 角色名字 + * @param code 角色额编码 + * @param id 角色编号 + */ + @VisibleForTesting + void validateRoleDuplicate(String name, String code, Long id) { + // 0. 超级管理员,不允许创建 + if (RoleCodeEnum.isSuperAdmin(code)) { + throw exception(ROLE_ADMIN_CODE_ERROR, code); + } + // 1. 该 name 名字被其它角色所使用 + RoleDO role = roleMapper.selectByName(name); + if (role != null && !role.getId().equals(id)) { + throw exception(ROLE_NAME_DUPLICATE, name); + } + // 2. 是否存在相同编码的角色 + if (!StringUtils.hasText(code)) { + return; + } + // 该 code 编码被其它角色所使用 + role = roleMapper.selectByCode(code); + if (role != null && !role.getId().equals(id)) { + throw exception(ROLE_CODE_DUPLICATE, code); + } + } + + /** + * 校验角色是否可以被更新 + * + * @param id 角色编号 + */ + @VisibleForTesting + RoleDO validateRoleForUpdate(Long id) { + RoleDO role = roleMapper.selectById(id); + if (role == null) { + throw exception(ROLE_NOT_EXISTS); + } + // 内置角色,不允许删除 + if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) { + throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); + } + return role; + } + + @Override + public RoleDO getRole(Long id) { + return roleMapper.selectById(id); + } + + @Override + @Cacheable(value = RedisKeyConstants.ROLE, key = "#id", + unless = "#result == null") + public RoleDO getRoleFromCache(Long id) { + return roleMapper.selectById(id); + } + + + @Override + public List getRoleListByStatus(Collection statuses) { + return roleMapper.selectListByStatus(statuses); + } + + @Override + public List getRoleList() { + return roleMapper.selectList(); + } + + @Override + public List getRoleList(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return roleMapper.selectBatchIds(ids); + } + + @Override + public List getRoleListFromCache(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题 + RoleServiceImpl self = getSelf(); + return CollectionUtils.convertList(ids, self::getRoleFromCache); + } + + @Override + public PageResult getRolePage(RolePageReqVO reqVO) { + return roleMapper.selectPage(reqVO); + } + + @Override + public boolean hasAnySuperAdmin(Collection ids) { + if (CollectionUtil.isEmpty(ids)) { + return false; + } + RoleServiceImpl self = getSelf(); + return ids.stream().anyMatch(id -> { + RoleDO role = self.getRoleFromCache(id); + return role != null && RoleCodeEnum.isSuperAdmin(role.getCode()); + }); + } + + @Override + public void validateRoleList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得角色信息 + List roles = roleMapper.selectBatchIds(ids); + Map roleMap = convertMap(roles, RoleDO::getId); + // 校验 + ids.forEach(id -> { + RoleDO role = roleMap.get(id); + if (role == null) { + throw exception(ROLE_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) { + throw exception(ROLE_IS_DISABLE, role.getName()); + } + }); + } + + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private RoleServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java new file mode 100644 index 0000000..5c77fe1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelService.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 短信渠道 Service 接口 + * + * @author zzf + * @since 2021/1/25 9:24 + */ +public interface SmsChannelService { + + /** + * 创建短信渠道 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSmsChannel(@Valid SmsChannelSaveReqVO createReqVO); + + /** + * 更新短信渠道 + * + * @param updateReqVO 更新信息 + */ + void updateSmsChannel(@Valid SmsChannelSaveReqVO updateReqVO); + + /** + * 删除短信渠道 + * + * @param id 编号 + */ + void deleteSmsChannel(Long id); + + /** + * 获得短信渠道 + * + * @param id 编号 + * @return 短信渠道 + */ + SmsChannelDO getSmsChannel(Long id); + + /** + * 获得所有短信渠道列表 + * + * @return 短信渠道列表 + */ + List getSmsChannelList(); + + /** + * 获得短信渠道分页 + * + * @param pageReqVO 分页查询 + * @return 短信渠道分页 + */ + PageResult getSmsChannelPage(SmsChannelPageReqVO pageReqVO); + + /** + * 获得短信客户端 + * + * @param id 编号 + * @return 短信客户端 + */ + SmsClient getSmsClient(Long id); + + /** + * 获得短信客户端 + * + * @param code 编码 + * @return 短信客户端 + */ + SmsClient getSmsClient(String code); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java new file mode 100644 index 0000000..a7455f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java @@ -0,0 +1,166 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; + +/** + * 短信渠道 Service 实现类 + * + * @author zzf + */ +@Service +@Slf4j +public class SmsChannelServiceImpl implements SmsChannelService { + + /** + * {@link SmsClient} 缓存,通过它异步刷新 smsClientFactory + */ + @Getter + private final LoadingCache idClientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public SmsClient load(Long id) { + // 查询,然后尝试刷新 + SmsChannelDO channel = smsChannelMapper.selectById(id); + if (channel != null) { + SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class); + smsClientFactory.createOrUpdateSmsClient(properties); + } + return smsClientFactory.getSmsClient(id); + } + + }); + + /** + * {@link SmsClient} 缓存,通过它异步刷新 smsClientFactory + */ + @Getter + private final LoadingCache codeClientCache = buildAsyncReloadingCache(Duration.ofSeconds(60L), + new CacheLoader() { + + @Override + public SmsClient load(String code) { + // 查询,然后尝试刷新 + SmsChannelDO channel = smsChannelMapper.selectByCode(code); + if (channel != null) { + SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class); + smsClientFactory.createOrUpdateSmsClient(properties); + } + return smsClientFactory.getSmsClient(code); + } + + }); + + @Resource + private SmsClientFactory smsClientFactory; + + @Resource + private SmsChannelMapper smsChannelMapper; + + @Resource + private SmsTemplateService smsTemplateService; + + @Override + public Long createSmsChannel(SmsChannelSaveReqVO createReqVO) { + SmsChannelDO channel = BeanUtils.toBean(createReqVO, SmsChannelDO.class); + smsChannelMapper.insert(channel); + return channel.getId(); + } + + @Override + public void updateSmsChannel(SmsChannelSaveReqVO updateReqVO) { + // 校验存在 + SmsChannelDO channel = validateSmsChannelExists(updateReqVO.getId()); + // 更新 + SmsChannelDO updateObj = BeanUtils.toBean(updateReqVO, SmsChannelDO.class); + smsChannelMapper.updateById(updateObj); + + // 清空缓存 + clearCache(updateReqVO.getId(), channel.getCode()); + } + + @Override + public void deleteSmsChannel(Long id) { + // 校验存在 + SmsChannelDO channel = validateSmsChannelExists(id); + // 校验是否有在使用该账号的模版 + if (smsTemplateService.getSmsTemplateCountByChannelId(id) > 0) { + throw exception(SMS_CHANNEL_HAS_CHILDREN); + } + // 删除 + smsChannelMapper.deleteById(id); + + // 清空缓存 + clearCache(id, channel.getCode()); + } + + /** + * 清空指定渠道编号的缓存 + * + * @param id 渠道编号 + * @param code 渠道编码 + */ + private void clearCache(Long id, String code) { + idClientCache.invalidate(id); + if (StrUtil.isNotEmpty(code)) { + codeClientCache.invalidate(code); + } + } + + private SmsChannelDO validateSmsChannelExists(Long id) { + SmsChannelDO channel = smsChannelMapper.selectById(id); + if (channel == null) { + throw exception(SMS_CHANNEL_NOT_EXISTS); + } + return channel; + } + + @Override + public SmsChannelDO getSmsChannel(Long id) { + return smsChannelMapper.selectById(id); + } + + @Override + public List getSmsChannelList() { + return smsChannelMapper.selectList(); + } + + @Override + public PageResult getSmsChannelPage(SmsChannelPageReqVO pageReqVO) { + return smsChannelMapper.selectPage(pageReqVO); + } + + @Override + public SmsClient getSmsClient(Long id) { + return idClientCache.getUnchecked(id); + } + + @Override + public SmsClient getSmsClient(String code) { + return codeClientCache.getUnchecked(code); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeService.java new file mode 100644 index 0000000..c310949 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeService.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; + +import javax.validation.Valid; + +/** + * 短信验证码 Service 接口 + * + * @author 芋道源码 + */ +public interface SmsCodeService { + + /** + * 创建短信验证码,并进行发送 + * + * @param reqDTO 发送请求 + */ + void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO); + + /** + * 验证短信验证码,并进行使用 + * 如果正确,则将验证码标记成已使用 + * 如果错误,则抛出 {@link ServiceException} 异常 + * + * @param reqDTO 使用请求 + */ + void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO); + + /** + * 检查验证码是否有效 + * + * @param reqDTO 校验请求 + */ + void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImpl.java new file mode 100644 index 0000000..de84605 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImpl.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import cn.iocoder.yudao.module.system.framework.sms.config.SmsCodeProperties; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.randomInt; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.isToday; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 短信验证码 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class SmsCodeServiceImpl implements SmsCodeService { + + @Resource + private SmsCodeProperties smsCodeProperties; + + @Resource + private SmsCodeMapper smsCodeMapper; + + @Resource + private SmsSendService smsSendService; + + @Override + public void sendSmsCode(SmsCodeSendReqDTO reqDTO) { + SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(reqDTO.getScene()); + Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene()); + // 创建验证码 + String code = createSmsCode(reqDTO.getMobile(), reqDTO.getScene(), reqDTO.getCreateIp()); + // 发送验证码 + smsSendService.sendSingleSms(reqDTO.getMobile(), null, null, + sceneEnum.getTemplateCode(), MapUtil.of("code", code)); + } + + private String createSmsCode(String mobile, Integer scene, String ip) { + // 校验是否可以发送验证码,不用筛选场景 + SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null, null); + if (lastSmsCode != null) { + if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 + throw exception(SMS_CODE_SEND_TOO_FAST); + } + if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限 + lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 + throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); + } + // TODO 芋艿:提升,每个 IP 每天可发送数量 + // TODO 芋艿:提升,每个 IP 每小时可发送数量 + } + + // 创建验证码记录 + String code = String.format("%0" + smsCodeProperties.getEndCode().toString().length() + "d", + randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1)); + SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene) + .todayIndex(lastSmsCode != null && isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1) + .createIp(ip).used(false).build(); + smsCodeMapper.insert(newSmsCode); + return code; + } + + @Override + public void useSmsCode(SmsCodeUseReqDTO reqDTO) { + // 检测验证码是否有效 + SmsCodeDO lastSmsCode = validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + // 使用验证码 + smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId()) + .used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build()); + } + + @Override + public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) { + validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + } + + private SmsCodeDO validateSmsCode0(String mobile, String code, Integer scene) { + // 校验验证码 + SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene); + // 若验证码不存在,抛出异常 + if (lastSmsCode == null) { + throw exception(SMS_CODE_NOT_FOUND); + } + // 超过时间 + if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期 + throw exception(SMS_CODE_EXPIRED); + } + // 判断验证码是否已被使用 + if (Boolean.TRUE.equals(lastSmsCode.getUsed())) { + throw exception(SMS_CODE_USED); + } + return lastSmsCode; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogService.java new file mode 100644 index 0000000..0c86c0f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogService.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * 短信日志 Service 接口 + * + * @author zzf + * @date 13:48 2021/3/2 + */ +public interface SmsLogService { + + /** + * 创建短信日志 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param isSend 是否发送 + * @param template 短信模板 + * @param templateContent 短信内容 + * @param templateParams 短信参数 + * @return 发送日志编号 + */ + Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SmsTemplateDO template, String templateContent, Map templateParams); + + /** + * 更新日志的发送结果 + * + * @param id 日志编号 + * @param success 发送是否成功 + * @param apiSendCode 短信 API 发送结果的编码 + * @param apiSendMsg 短信 API 发送失败的提示 + * @param apiRequestId 短信 API 发送返回的唯一请求 ID + * @param apiSerialNo 短信 API 发送返回的序号 + */ + void updateSmsSendResult(Long id, Boolean success, + String apiSendCode, String apiSendMsg, + String apiRequestId, String apiSerialNo); + + /** + * 更新日志的接收结果 + * + * @param id 日志编号 + * @param success 是否接收成功 + * @param receiveTime 用户接收时间 + * @param apiReceiveCode API 接收结果的编码 + * @param apiReceiveMsg API 接收结果的说明 + */ + void updateSmsReceiveResult(Long id, Boolean success, + LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg); + + /** + * 获得短信日志分页 + * + * @param pageReqVO 分页查询 + * @return 短信日志分页 + */ + PageResult getSmsLogPage(SmsLogPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImpl.java new file mode 100644 index 0000000..c79b941 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImpl.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper; +import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +/** + * 短信日志 Service 实现类 + * + * @author zzf + */ +@Slf4j +@Service +public class SmsLogServiceImpl implements SmsLogService { + + @Resource + private SmsLogMapper smsLogMapper; + + @Override + public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SmsTemplateDO template, String templateContent, Map templateParams) { + SmsLogDO.SmsLogDOBuilder logBuilder = SmsLogDO.builder(); + // 根据是否要发送,设置状态 + logBuilder.sendStatus(Objects.equals(isSend, true) ? SmsSendStatusEnum.INIT.getStatus() + : SmsSendStatusEnum.IGNORE.getStatus()); + // 设置手机相关字段 + logBuilder.mobile(mobile).userId(userId).userType(userType); + // 设置模板相关字段 + logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType()); + logBuilder.templateContent(templateContent).templateParams(templateParams) + .apiTemplateId(template.getApiTemplateId()); + // 设置渠道相关字段 + logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode()); + // 设置接收相关字段 + logBuilder.receiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + + // 插入数据库 + SmsLogDO logDO = logBuilder.build(); + smsLogMapper.insert(logDO); + return logDO.getId(); + } + + @Override + public void updateSmsSendResult(Long id, Boolean success, + String apiSendCode, String apiSendMsg, + String apiRequestId, String apiSerialNo) { + SmsSendStatusEnum sendStatus = success ? SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE; + smsLogMapper.updateById(SmsLogDO.builder().id(id) + .sendStatus(sendStatus.getStatus()).sendTime(LocalDateTime.now()) + .apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) + .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build()); + } + + @Override + public void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime, + String apiReceiveCode, String apiReceiveMsg) { + SmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ? + SmsReceiveStatusEnum.SUCCESS : SmsReceiveStatusEnum.FAILURE; + smsLogMapper.updateById(SmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus()) + .receiveTime(receiveTime).apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build()); + } + + @Override + public PageResult getSmsLogPage(SmsLogPageReqVO pageReqVO) { + return smsLogMapper.selectPage(pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendService.java new file mode 100644 index 0000000..3c42cf5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendService.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; + +import java.util.List; +import java.util.Map; + +/** + * 短信发送 Service 接口 + * + * @author 芋道源码 + */ +public interface SmsSendService { + + /** + * 发送单条短信给管理后台的用户 + * + * 在 mobile 为空时,使用 userId 加载对应管理员的手机号 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSmsToAdmin(String mobile, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条短信给用户 APP 的用户 + * + * 在 mobile 为空时,使用 userId 加载对应会员的手机号 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSmsToMember(String mobile, Long userId, + String templateCode, Map templateParams); + + /** + * 发送单条短信给用户 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @return 发送日志编号 + */ + Long sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams); + + default void sendBatchSms(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams) { + throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!"); + } + + /** + * 执行真正的短信发送 + * 注意,该方法仅仅提供给 MQ Consumer 使用 + * + * @param message 短信 + */ + void doSendSms(SmsSendMessage message); + + /** + * 接收短信的接收结果 + * + * @param channelCode 渠道编码 + * @param text 结果内容 + * @throws Throwable 处理失败时,抛出异常 + */ + void receiveSmsStatus(String channelCode, String text) throws Throwable; + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java new file mode 100644 index 0000000..49af0ec --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java @@ -0,0 +1,191 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; +import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 短信发送 Service 发送的实现 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class SmsSendServiceImpl implements SmsSendService { + + @Resource + private AdminUserService adminUserService; + @Resource + private MemberService memberService; + @Resource + private SmsChannelService smsChannelService; + @Resource + private SmsTemplateService smsTemplateService; + @Resource + private SmsLogService smsLogService; + + @Resource + private SmsProducer smsProducer; + + @Override + @DataPermission(enable = false) // 发送短信时,无需考虑数据权限 + public Long sendSingleSmsToAdmin(String mobile, Long userId, String templateCode, Map templateParams) { + // 如果 mobile 为空,则加载用户编号对应的手机号 + if (StrUtil.isEmpty(mobile)) { + AdminUserDO user = adminUserService.getUser(userId); + if (user != null) { + mobile = user.getMobile(); + } + } + // 执行发送 + return sendSingleSms(mobile, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map templateParams) { + // 如果 mobile 为空,则加载用户编号对应的手机号 + if (StrUtil.isEmpty(mobile)) { + mobile = memberService.getMemberUserMobile(userId); + } + // 执行发送 + return sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams); + } + + @Override + public Long sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams) { + // 校验短信模板是否合法 + SmsTemplateDO template = validateSmsTemplate(templateCode); + // 校验短信渠道是否合法 + SmsChannelDO smsChannel = validateSmsChannel(template.getChannelId()); + + // 校验手机号码是否存在 + mobile = validateMobile(mobile); + // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志 + List> newTemplateParams = buildTemplateParams(template, templateParams); + + // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()) + && CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus()); + String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); + Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams); + + // 发送 MQ 消息,异步执行发送短信 + if (isSend) { + smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), + template.getApiTemplateId(), newTemplateParams); + } + return sendLogId; + } + + @VisibleForTesting + SmsChannelDO validateSmsChannel(Long channelId) { + // 获得短信模板。考虑到效率,从缓存中获取 + SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + // 短信模板不存在 + if (channelDO == null) { + throw exception(SMS_CHANNEL_NOT_EXISTS); + } + return channelDO; + } + + @VisibleForTesting + SmsTemplateDO validateSmsTemplate(String templateCode) { + // 获得短信模板。考虑到效率,从缓存中获取 + SmsTemplateDO template = smsTemplateService.getSmsTemplateByCodeFromCache(templateCode); + // 短信模板不存在 + if (template == null) { + throw exception(SMS_SEND_TEMPLATE_NOT_EXISTS); + } + return template; + } + + /** + * 将参数模板,处理成有序的 KeyValue 数组 + *

+ * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说 腾讯云 + * + * @param template 短信模板 + * @param templateParams 原始参数 + * @return 处理后的参数 + */ + @VisibleForTesting + List> buildTemplateParams(SmsTemplateDO template, Map templateParams) { + return template.getParams().stream().map(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key); + } + return new KeyValue<>(key, value); + }).collect(Collectors.toList()); + } + + @VisibleForTesting + public String validateMobile(String mobile) { + if (StrUtil.isEmpty(mobile)) { + throw exception(SMS_SEND_MOBILE_NOT_EXISTS); + } + return mobile; + } + + @Override + public void doSendSms(SmsSendMessage message) { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId()); + Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId()); + // 发送短信 + try { + SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(), + message.getApiTemplateId(), message.getTemplateParams()); + smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(), + sendResponse.getApiCode(), sendResponse.getApiMsg(), + sendResponse.getApiRequestId(), sendResponse.getSerialNo()); + } catch (Throwable ex) { + log.error("[doSendSms][发送短信异常,日志编号({})]", message.getLogId(), ex); + smsLogService.updateSmsSendResult(message.getLogId(), false, + "EXCEPTION", ExceptionUtil.getRootCauseMessage(ex), null, null); + } + } + + @Override + public void receiveSmsStatus(String channelCode, String text) throws Throwable { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsChannelService.getSmsClient(channelCode); + Assert.notNull(smsClient, "短信客户端({}) 不存在", channelCode); + // 解析内容 + List receiveResults = smsClient.parseSmsReceiveStatus(text); + if (CollUtil.isEmpty(receiveResults)) { + return; + } + // 更新短信日志的接收结果. 因为量一般不大,所以先使用 for 循环更新 + receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(result.getLogId(), + result.getSuccess(), result.getReceiveTime(), result.getErrorCode(), result.getErrorMsg())); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java new file mode 100644 index 0000000..9d6ac3a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; + +import javax.validation.Valid; +import java.util.Map; + +/** + * 短信模板 Service 接口 + * + * @author zzf + * @since 2021/1/25 9:24 + */ +public interface SmsTemplateService { + + /** + * 创建短信模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSmsTemplate(@Valid SmsTemplateSaveReqVO createReqVO); + + /** + * 更新短信模板 + * + * @param updateReqVO 更新信息 + */ + void updateSmsTemplate(@Valid SmsTemplateSaveReqVO updateReqVO); + + /** + * 删除短信模板 + * + * @param id 编号 + */ + void deleteSmsTemplate(Long id); + + /** + * 获得短信模板 + * + * @param id 编号 + * @return 短信模板 + */ + SmsTemplateDO getSmsTemplate(Long id); + + /** + * 获得短信模板,从缓存中 + * + * @param code 模板编码 + * @return 短信模板 + */ + SmsTemplateDO getSmsTemplateByCodeFromCache(String code); + + /** + * 获得短信模板分页 + * + * @param pageReqVO 分页查询 + * @return 短信模板分页 + */ + PageResult getSmsTemplatePage(SmsTemplatePageReqVO pageReqVO); + + /** + * 获得指定短信渠道下的短信模板数量 + * + * @param channelId 短信渠道编号 + * @return 数量 + */ + Long getSmsTemplateCountByChannelId(Long channelId); + + /** + * 格式化短信内容 + * + * @param content 短信模板的内容 + * @param params 内容的参数 + * @return 格式化后的内容 + */ + String formatSmsTemplateContent(String content, Map params); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java new file mode 100644 index 0000000..639bec6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java @@ -0,0 +1,199 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Pattern; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 短信模板 Service 实现类 + * + * @author zzf + * @since 2021/1/25 9:25 + */ +@Service +@Slf4j +public class SmsTemplateServiceImpl implements SmsTemplateService { + + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + + @Resource + private SmsTemplateMapper smsTemplateMapper; + + @Resource + private SmsChannelService smsChannelService; + + @Override + public Long createSmsTemplate(SmsTemplateSaveReqVO createReqVO) { + // 校验短信渠道 + SmsChannelDO channelDO = validateSmsChannel(createReqVO.getChannelId()); + // 校验短信编码是否重复 + validateSmsTemplateCodeDuplicate(null, createReqVO.getCode()); + // 校验短信模板 + validateApiTemplate(createReqVO.getChannelId(), createReqVO.getApiTemplateId()); + + // 插入 + SmsTemplateDO template = BeanUtils.toBean(createReqVO, SmsTemplateDO.class); + template.setParams(parseTemplateContentParams(template.getContent())); + template.setChannelCode(channelDO.getCode()); + smsTemplateMapper.insert(template); + // 返回 + return template.getId(); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 + public void updateSmsTemplate(SmsTemplateSaveReqVO updateReqVO) { + // 校验存在 + validateSmsTemplateExists(updateReqVO.getId()); + // 校验短信渠道 + SmsChannelDO channelDO = validateSmsChannel(updateReqVO.getChannelId()); + // 校验短信编码是否重复 + validateSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + // 校验短信模板 + validateApiTemplate(updateReqVO.getChannelId(), updateReqVO.getApiTemplateId()); + + // 更新 + SmsTemplateDO updateObj = BeanUtils.toBean(updateReqVO, SmsTemplateDO.class); + updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); + updateObj.setChannelCode(channelDO.getCode()); + smsTemplateMapper.updateById(updateObj); + } + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 + public void deleteSmsTemplate(Long id) { + // 校验存在 + validateSmsTemplateExists(id); + // 更新 + smsTemplateMapper.deleteById(id); + } + + private void validateSmsTemplateExists(Long id) { + if (smsTemplateMapper.selectById(id) == null) { + throw exception(SMS_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public SmsTemplateDO getSmsTemplate(Long id) { + return smsTemplateMapper.selectById(id); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code", + unless = "#result == null") + public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) { + return smsTemplateMapper.selectByCode(code); + } + + @Override + public PageResult getSmsTemplatePage(SmsTemplatePageReqVO pageReqVO) { + return smsTemplateMapper.selectPage(pageReqVO); + } + + @Override + public Long getSmsTemplateCountByChannelId(Long channelId) { + return smsTemplateMapper.selectCountByChannelId(channelId); + } + + @VisibleForTesting + public SmsChannelDO validateSmsChannel(Long channelId) { + SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + if (channelDO == null) { + throw exception(SMS_CHANNEL_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(channelDO.getStatus())) { + throw exception(SMS_CHANNEL_DISABLE); + } + return channelDO; + } + + @VisibleForTesting + public void validateSmsTemplateCodeDuplicate(Long id, String code) { + SmsTemplateDO template = smsTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(SMS_TEMPLATE_CODE_DUPLICATE, code); + } + if (!template.getId().equals(id)) { + throw exception(SMS_TEMPLATE_CODE_DUPLICATE, code); + } + } + + /** + * 校验 API 短信平台的模板是否有效 + * + * @param channelId 渠道编号 + * @param apiTemplateId API 模板编号 + */ + @VisibleForTesting + void validateApiTemplate(Long channelId, String apiTemplateId) { + // 获得短信模板 + SmsClient smsClient = smsChannelService.getSmsClient(channelId); + Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); + SmsTemplateRespDTO template; + try { + template = smsClient.getSmsTemplate(apiTemplateId); + } catch (Throwable ex) { + throw exception(SMS_TEMPLATE_API_ERROR, ExceptionUtil.getRootCauseMessage(ex)); + } + // 校验短信模版 + if (template == null) { + throw exception(SMS_TEMPLATE_API_NOT_FOUND); + } + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) { + throw exception(SMS_TEMPLATE_API_AUDIT_CHECKING); + } + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) { + throw exception(SMS_TEMPLATE_API_AUDIT_FAIL, template.getAuditReason()); + } + Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus())); + } + + @Override + public String formatSmsTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + + @VisibleForTesting + List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java new file mode 100644 index 0000000..dba86c6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.model.AuthUser; +import me.chanjar.weixin.common.bean.WxJsapiSignature; + +import javax.validation.Valid; + +/** + * 社交应用 Service 接口 + * + * @author 芋道源码 + */ +public interface SocialClientService { + + /** + * 获得社交平台的授权 URL + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param redirectUri 重定向 URL + * @return 社交平台的授权 URL + */ + String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri); + + /** + * 请求社交平台,获得授权的用户 + * + * @param socialType 社交平台的类型 + * @param userType 用户类型 + * @param code 授权码 + * @param state 授权 state + * @return 授权的用户 + */ + AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state); + + // =================== 微信公众号独有 =================== + + /** + * 创建微信公众号的 JS SDK 初始化所需的签名 + * + * @param userType 用户类型 + * @param url 访问的 URL 地址 + * @return 签名 + */ + WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url); + + // =================== 微信小程序独有 =================== + + /** + * 获得微信小程序的手机信息 + * + * @param userType 用户类型 + * @param phoneCode 手机授权码 + * @return 手机信息 + */ + WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode); + + // =================== 客户端管理 =================== + + /** + * 创建社交客户端 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSocialClient(@Valid SocialClientSaveReqVO createReqVO); + + /** + * 更新社交客户端 + * + * @param updateReqVO 更新信息 + */ + void updateSocialClient(@Valid SocialClientSaveReqVO updateReqVO); + + /** + * 删除社交客户端 + * + * @param id 编号 + */ + void deleteSocialClient(Long id); + + /** + * 获得社交客户端 + * + * @param id 编号 + * @return 社交客户端 + */ + SocialClientDO getSocialClient(Long id); + + /** + * 获得社交客户端分页 + * + * @param pageReqVO 分页查询 + * @return 社交客户端分页 + */ + PageResult getSocialClientPage(SocialClientPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java new file mode 100644 index 0000000..23b3cea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java @@ -0,0 +1,339 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.xingyuv.jushauth.config.AuthConfig; +import com.xingyuv.jushauth.model.AuthCallback; +import com.xingyuv.jushauth.model.AuthResponse; +import com.xingyuv.jushauth.model.AuthUser; +import com.xingyuv.jushauth.request.AuthRequest; +import com.xingyuv.jushauth.utils.AuthStateUtils; +import com.xingyuv.justauth.AuthRequestFactory; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 社交应用 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +public class SocialClientServiceImpl implements SocialClientService { + + @Resource + private AuthRequestFactory authRequestFactory; + + @Resource + private WxMpService wxMpService; + @Resource + private WxMpProperties wxMpProperties; + @Resource + private StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它 + /** + * 缓存 WxMpService 对象 + * + * key:使用微信公众号的 appId + secret 拼接,即 {@link SocialClientDO} 的 clientId 和 clientSecret 属性。 + * 为什么 key 使用这种格式?因为 {@link SocialClientDO} 在管理后台可以变更,通过这个 key 存储它的单例。 + * + * 为什么要做 WxMpService 缓存?因为 WxMpService 构建成本比较大,所以尽量保证它是单例。 + */ + private final LoadingCache wxMpServiceCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public WxMpService load(String key) { + String[] keys = key.split(":"); + return buildWxMpService(keys[0], keys[1]); + } + + }); + + @Resource + private WxMaService wxMaService; + @Resource + private WxMaProperties wxMaProperties; + /** + * 缓存 WxMaService 对象 + * + * 说明同 {@link #wxMpServiceCache} 变量 + */ + private final LoadingCache wxMaServiceCache = CacheUtils.buildAsyncReloadingCache( + Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public WxMaService load(String key) { + String[] keys = key.split(":"); + return buildWxMaService(keys[0], keys[1]); + } + + }); + + @Resource + private SocialClientMapper socialClientMapper; + + @Override + public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { + // 获得对应的 AuthRequest 实现 + AuthRequest authRequest = buildAuthRequest(socialType, userType); + // 生成跳转地址 + String authorizeUri = authRequest.authorize(AuthStateUtils.createState()); + return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri); + } + + @Override + public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) { + // 构建请求 + AuthRequest authRequest = buildAuthRequest(socialType, userType); + AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); + // 执行请求 + AuthResponse authResponse = authRequest.login(authCallback); + log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, + toJsonString(authCallback), toJsonString(authResponse)); + if (!authResponse.ok()) { + throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); + } + return (AuthUser) authResponse.getData(); + } + + /** + * 构建 AuthRequest 对象,支持多租户配置 + * + * @param socialType 社交类型 + * @param userType 用户类型 + * @return AuthRequest 对象 + */ + @VisibleForTesting + AuthRequest buildAuthRequest(Integer socialType, Integer userType) { + // 1. 先查找默认的配置项,从 application-*.yaml 中读取 + AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource()); + Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType)); + // 2. 查询 DB 的配置项,如果存在则进行覆盖 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(socialType, userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + // 2.1 构造新的 AuthConfig 对象 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(request, "config"); + AuthConfig newAuthConfig = ReflectUtil.newInstance(authConfig.getClass()); + BeanUtil.copyProperties(authConfig, newAuthConfig); + // 2.2 修改对应的 clientId + clientSecret 密钥 + newAuthConfig.setClientId(client.getClientId()); + newAuthConfig.setClientSecret(client.getClientSecret()); + if (client.getAgentId() != null) { // 如果有 agentId 则修改 agentId + newAuthConfig.setAgentId(client.getAgentId()); + } + // 2.3 设置会 request 里,进行后续使用 + ReflectUtil.setFieldValue(request, "config", newAuthConfig); + } + return request; + } + + // =================== 微信公众号独有 =================== + + @Override + @SneakyThrows + public WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url) { + WxMpService service = getWxMpService(userType); + return service.createJsapiSignature(url); + } + + /** + * 获得 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param userType 用户类型 + * @return WxMpService 对象 + */ + @VisibleForTesting + WxMpService getWxMpService(Integer userType) { + // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + SocialTypeEnum.WECHAT_MP.getType(), userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + return wxMpServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); + } + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMpService 对象 + return wxMpService; + } + + /** + * 创建 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param clientId 微信公众号 appId + * @param clientSecret 微信公众号 secret + * @return WxMpService 对象 + */ + public WxMpService buildWxMpService(String clientId, String clientSecret) { + // 第一步,创建 WxMpRedisConfigImpl 对象 + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( + new RedisTemplateWxRedisOps(stringRedisTemplate), + wxMpProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppId(clientId); + configStorage.setSecret(clientSecret); + + // 第二步,创建 WxMpService 对象 + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + return service; + } + + // =================== 微信小程序独有 =================== + + @Override + public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode) { + WxMaService service = getWxMaService(userType); + try { + return service.getUserService().getPhoneNoInfo(phoneCode); + } catch (WxErrorException e) { + log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e); + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR); + } + } + + /** + * 获得 clientId + clientSecret 对应的 WxMpService 对象 + * + * @param userType 用户类型 + * @return WxMpService 对象 + */ + @VisibleForTesting + WxMaService getWxMaService(Integer userType) { + // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象 + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + SocialTypeEnum.WECHAT_MINI_APP.getType(), userType); + if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + return wxMaServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret()); + } + // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMaService 对象 + return wxMaService; + } + + /** + * 创建 clientId + clientSecret 对应的 WxMaService 对象 + * + * @param clientId 微信小程序 appId + * @param clientSecret 微信小程序 secret + * @return WxMaService 对象 + */ + private WxMaService buildWxMaService(String clientId, String clientSecret) { + // 第一步,创建 WxMaRedisBetterConfigImpl 对象 + WxMaRedisBetterConfigImpl configStorage = new WxMaRedisBetterConfigImpl( + new RedisTemplateWxRedisOps(stringRedisTemplate), + wxMaProperties.getConfigStorage().getKeyPrefix()); + configStorage.setAppid(clientId); + configStorage.setSecret(clientSecret); + + // 第二步,创建 WxMpService 对象 + WxMaService service = new WxMaServiceImpl(); + service.setWxMaConfig(configStorage); + return service; + } + + // =================== 客户端管理 =================== + + @Override + public Long createSocialClient(SocialClientSaveReqVO createReqVO) { + // 校验重复 + validateSocialClientUnique(null, createReqVO.getUserType(), createReqVO.getSocialType()); + + // 插入 + SocialClientDO client = BeanUtils.toBean(createReqVO, SocialClientDO.class); + socialClientMapper.insert(client); + return client.getId(); + } + + @Override + public void updateSocialClient(SocialClientSaveReqVO updateReqVO) { + // 校验存在 + validateSocialClientExists(updateReqVO.getId()); + // 校验重复 + validateSocialClientUnique(updateReqVO.getId(), updateReqVO.getUserType(), updateReqVO.getSocialType()); + + // 更新 + SocialClientDO updateObj = BeanUtils.toBean(updateReqVO, SocialClientDO.class); + socialClientMapper.updateById(updateObj); + } + + @Override + public void deleteSocialClient(Long id) { + // 校验存在 + validateSocialClientExists(id); + // 删除 + socialClientMapper.deleteById(id); + } + + private void validateSocialClientExists(Long id) { + if (socialClientMapper.selectById(id) == null) { + throw exception(SOCIAL_CLIENT_NOT_EXISTS); + } + } + + /** + * 校验社交应用是否重复,需要保证 userType + socialType 唯一 + * + * 原因是,不同端(userType)选择某个社交登录(socialType)时,需要通过 {@link #buildAuthRequest(Integer, Integer)} 构建对应的请求 + * + * @param id 编号 + * @param userType 用户类型 + * @param socialType 社交类型 + */ + private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) { + SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( + socialType, userType); + if (client == null) { + return; + } + if (id == null // 新增时,说明重复 + || ObjUtil.notEqual(id, client.getId())) { // 更新时,如果 id 不一致,说明重复 + throw exception(SOCIAL_CLIENT_UNIQUE); + } + } + + @Override + public SocialClientDO getSocialClient(Long id) { + return socialClientMapper.selectById(id); + } + + @Override + public PageResult getSocialClientPage(SocialClientPageReqVO pageReqVO) { + return socialClientMapper.selectPage(pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java new file mode 100644 index 0000000..b8fa3f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java @@ -0,0 +1,89 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; + +import javax.validation.Valid; +import java.util.List; + +/** + * 社交用户 Service 接口,例如说社交平台的授权登录 + * + * @author 芋道源码 + */ +public interface SocialUserService { + + /** + * 获得指定用户的社交用户列表 + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 社交用户列表 + */ + List getSocialUserList(Long userId, Integer userType); + + /** + * 绑定社交用户 + * + * @param reqDTO 绑定信息 + * @return 社交用户 openid + */ + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); + + /** + * 取消绑定社交用户 + * + * @param userId 用户编号 + * @param userType 全局用户类型 + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param openid 社交平台的 openid + */ + void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid); + + /** + * 获得社交用户,基于 userId + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param socialType 社交平台的类型 + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType); + + /** + * 获得社交用户 + * + * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 + * + * @param userType 用户类型 + * @param socialType 社交平台的类型 + * @param code 授权码 + * @param state state + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state); + + // ==================== 社交用户 CRUD ==================== + + /** + * 获得社交用户 + * + * @param id 编号 + * @return 社交用户 + */ + SocialUserDO getSocialUser(Long id); + + /** + * 获得社交用户分页 + * + * @param pageReqVO 分页查询 + * @return 社交用户分页 + */ + PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java new file mode 100644 index 0000000..7458d9c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java @@ -0,0 +1,173 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.model.AuthUser; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; + +/** + * 社交用户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class SocialUserServiceImpl implements SocialUserService { + + @Resource + private SocialUserBindMapper socialUserBindMapper; + @Resource + private SocialUserMapper socialUserMapper; + + @Resource + private SocialClientService socialClientService; + + @Override + public List getSocialUserList(Long userId, Integer userType) { + // 获得绑定 + List socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType); + if (CollUtil.isEmpty(socialUserBinds)) { + return Collections.emptyList(); + } + // 获得社交用户 + return socialUserMapper.selectBatchIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), + reqDTO.getCode(), reqDTO.getState()); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 社交用户可能之前绑定过别的用户,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId()); + + // 用户可能之前已经绑定过该社交类型,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(), + socialUser.getType()); + + // 绑定当前登录的社交用户 + SocialUserBindDO socialUserBind = SocialUserBindDO.builder() + .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) + .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); + socialUserBindMapper.insert(socialUserBind); + return socialUser.getOpenid(); + } + + @Override + public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) { + // 获得 openid 对应的 SocialUserDO 社交用户 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid); + if (socialUser == null) { + throw exception(SOCIAL_USER_NOT_FOUND); + } + + // 获得对应的社交绑定关系 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType()); + } + + @Override + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType); + if (socialUserBind == null) { + return null; + } + // 获得社交用户 + SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId()); + Assert.notNull(socialUser, "社交用户不能为空"); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind.getUserId()); + } + + @Override + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, + socialUser.getId()); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind != null ? socialUserBind.getUserId() : null); + } + + /** + * 授权获得对应的社交用户 + * 如果授权失败,则会抛出 {@link ServiceException} 异常 + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param code 授权码 + * @param state state + * @return 授权用户 + */ + @NotNull + public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) { + // 优先从 DB 中获取,因为 code 有且可以使用一次。 + // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state); + if (socialUser != null) { + return socialUser; + } + + // 请求获取 + AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state); + Assert.notNull(authUser, "三方用户不能为空"); + + // 保存到 DB 中 + socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid()); + if (socialUser == null) { + socialUser = new SocialUserDO(); + } + socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 + .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) + .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); + if (socialUser.getId() == null) { + socialUserMapper.insert(socialUser); + } else { + socialUserMapper.updateById(socialUser); + } + return socialUser; + } + + // ==================== 社交用户 CRUD ==================== + + @Override + public SocialUserDO getSocialUser(Long id) { + return socialUserMapper.selectById(id); + } + + @Override + public PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO) { + return socialUserMapper.selectPage(pageReqVO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java new file mode 100644 index 0000000..1abe4fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 租户套餐 Service 接口 + * + * @author 芋道源码 + */ +public interface TenantPackageService { + + /** + * 创建租户套餐 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenantPackage(@Valid TenantPackageSaveReqVO createReqVO); + + /** + * 更新租户套餐 + * + * @param updateReqVO 更新信息 + */ + void updateTenantPackage(@Valid TenantPackageSaveReqVO updateReqVO); + + /** + * 删除租户套餐 + * + * @param id 编号 + */ + void deleteTenantPackage(Long id); + + /** + * 获得租户套餐 + * + * @param id 编号 + * @return 租户套餐 + */ + TenantPackageDO getTenantPackage(Long id); + + /** + * 获得租户套餐分页 + * + * @param pageReqVO 分页查询 + * @return 租户套餐分页 + */ + PageResult getTenantPackagePage(TenantPackagePageReqVO pageReqVO); + + /** + * 校验租户套餐 + * + * @param id 编号 + * @return 租户套餐 + */ + TenantPackageDO validTenantPackage(Long id); + + /** + * 获得指定状态的租户套餐列表 + * + * @param status 状态 + * @return 租户套餐 + */ + List getTenantPackageListByStatus(Integer status); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java new file mode 100644 index 0000000..3fd76a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 租户套餐 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class TenantPackageServiceImpl implements TenantPackageService { + + @Resource + private TenantPackageMapper tenantPackageMapper; + + @Resource + @Lazy // 避免循环依赖的报错 + private TenantService tenantService; + + @Override + public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) { + // 插入 + TenantPackageDO tenantPackage = BeanUtils.toBean(createReqVO, TenantPackageDO.class); + tenantPackageMapper.insert(tenantPackage); + // 返回 + return tenantPackage.getId(); + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public void updateTenantPackage(TenantPackageSaveReqVO updateReqVO) { + // 校验存在 + TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId()); + // 更新 + TenantPackageDO updateObj = BeanUtils.toBean(updateReqVO, TenantPackageDO.class); + tenantPackageMapper.updateById(updateObj); + // 如果菜单发生变化,则修改每个租户的菜单 + if (!CollUtil.isEqualList(tenantPackage.getMenuIds(), updateReqVO.getMenuIds())) { + List tenants = tenantService.getTenantListByPackageId(tenantPackage.getId()); + tenants.forEach(tenant -> tenantService.updateTenantRoleMenu(tenant.getId(), updateReqVO.getMenuIds())); + } + } + + @Override + public void deleteTenantPackage(Long id) { + // 校验存在 + validateTenantPackageExists(id); + // 校验正在使用 + validateTenantUsed(id); + // 删除 + tenantPackageMapper.deleteById(id); + } + + private TenantPackageDO validateTenantPackageExists(Long id) { + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id); + if (tenantPackage == null) { + throw exception(TENANT_PACKAGE_NOT_EXISTS); + } + return tenantPackage; + } + + private void validateTenantUsed(Long id) { + if (tenantService.getTenantCountByPackageId(id) > 0) { + throw exception(TENANT_PACKAGE_USED); + } + } + + @Override + public TenantPackageDO getTenantPackage(Long id) { + return tenantPackageMapper.selectById(id); + } + + @Override + public PageResult getTenantPackagePage(TenantPackagePageReqVO pageReqVO) { + return tenantPackageMapper.selectPage(pageReqVO); + } + + @Override + public TenantPackageDO validTenantPackage(Long id) { + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id); + if (tenantPackage == null) { + throw exception(TENANT_PACKAGE_NOT_EXISTS); + } + if (tenantPackage.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(TENANT_PACKAGE_DISABLE, tenantPackage.getName()); + } + return tenantPackage; + } + + @Override + public List getTenantPackageListByStatus(Integer status) { + return tenantPackageMapper.selectListByStatus(status); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java new file mode 100644 index 0000000..c7e879b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; + +import javax.validation.Valid; +import java.util.List; +import java.util.Set; + +/** + * 租户 Service 接口 + * + * @author 芋道源码 + */ +public interface TenantService { + + /** + * 创建租户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createTenant(@Valid TenantSaveReqVO createReqVO); + + /** + * 更新租户 + * + * @param updateReqVO 更新信息 + */ + void updateTenant(@Valid TenantSaveReqVO updateReqVO); + + /** + * 更新租户的角色菜单 + * + * @param tenantId 租户编号 + * @param menuIds 菜单编号数组 + */ + void updateTenantRoleMenu(Long tenantId, Set menuIds); + + /** + * 删除租户 + * + * @param id 编号 + */ + void deleteTenant(Long id); + + /** + * 获得租户 + * + * @param id 编号 + * @return 租户 + */ + TenantDO getTenant(Long id); + + /** + * 获得租户分页 + * + * @param pageReqVO 分页查询 + * @return 租户分页 + */ + PageResult getTenantPage(TenantPageReqVO pageReqVO); + + /** + * 获得名字对应的租户 + * + * @param name 租户名 + * @return 租户 + */ + TenantDO getTenantByName(String name); + + /** + * 获得域名对应的租户 + * + * @param website 域名 + * @return 租户 + */ + TenantDO getTenantByWebsite(String website); + + /** + * 获得使用指定套餐的租户数量 + * + * @param packageId 租户套餐编号 + * @return 租户数量 + */ + Long getTenantCountByPackageId(Long packageId); + + /** + * 获得使用指定套餐的租户数组 + * + * @param packageId 租户套餐编号 + * @return 租户数组 + */ + List getTenantListByPackageId(Long packageId); + + /** + * 进行租户的信息处理逻辑 + * 其中,租户编号从 {@link TenantContextHolder} 上下文中获取 + * + * @param handler 处理器 + */ + void handleTenantInfo(TenantInfoHandler handler); + + /** + * 进行租户的菜单处理逻辑 + * 其中,租户编号从 {@link TenantContextHolder} 上下文中获取 + * + * @param handler 处理器 + */ + void handleTenantMenu(TenantMenuHandler handler); + + /** + * 获得所有租户 + * + * @return 租户编号数组 + */ + List getTenantIdList(); + + /** + * 校验租户是否合法 + * + * @param id 租户编号 + */ + void validTenant(Long id); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java new file mode 100644 index 0000000..b4bdf10 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -0,0 +1,306 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import cn.iocoder.yudao.module.system.service.permission.MenuService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; + +/** + * 租户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class TenantServiceImpl implements TenantService { + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入 + private TenantProperties tenantProperties; + + @Resource + private TenantMapper tenantMapper; + + @Resource + private TenantPackageService tenantPackageService; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private AdminUserService userService; + @Resource + private RoleService roleService; + @Resource + private MenuService menuService; + @Resource + private PermissionService permissionService; + + @Override + public List getTenantIdList() { + List tenants = tenantMapper.selectList(); + return CollectionUtils.convertList(tenants, TenantDO::getId); + } + + @Override + public void validTenant(Long id) { + TenantDO tenant = getTenant(id); + if (tenant == null) { + throw exception(TENANT_NOT_EXISTS); + } + if (tenant.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { + throw exception(TENANT_DISABLE, tenant.getName()); + } + if (DateUtils.isExpired(tenant.getExpireTime())) { + throw exception(TENANT_EXPIRE, tenant.getName()); + } + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public Long createTenant(TenantSaveReqVO createReqVO) { + // 校验租户名称是否重复 + validTenantNameDuplicate(createReqVO.getName(), null); + // 校验租户域名是否重复 + validTenantWebsiteDuplicate(createReqVO.getWebsite(), null); + // 校验套餐被禁用 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); + + // 创建租户 + TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class); + tenantMapper.insert(tenant); + // 创建租户的管理员 + TenantUtils.execute(tenant.getId(), () -> { + // 创建角色 + Long roleId = createRole(tenantPackage); + // 创建用户,并分配角色 + Long userId = createUser(roleId, createReqVO); + // 修改租户的管理员 + tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); + }); + return tenant.getId(); + } + + private Long createUser(Long roleId, TenantSaveReqVO createReqVO) { + // 创建用户 + Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO)); + // 分配角色 + permissionService.assignUserRole(userId, singleton(roleId)); + return userId; + } + + private Long createRole(TenantPackageDO tenantPackage) { + // 创建角色 + RoleSaveReqVO reqVO = new RoleSaveReqVO(); + reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode()) + .setSort(0).setRemark("系统自动生成"); + Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); + // 分配权限 + permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds()); + return roleId; + } + + @Override + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + public void updateTenant(TenantSaveReqVO updateReqVO) { + // 校验存在 + TenantDO tenant = validateUpdateTenant(updateReqVO.getId()); + // 校验租户名称是否重复 + validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId()); + // 校验租户域名是否重复 + validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId()); + // 校验套餐被禁用 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); + + // 更新租户 + TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class); + tenantMapper.updateById(updateObj); + // 如果套餐发生变化,则修改其角色的权限 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { + updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + } + } + + private void validTenantNameDuplicate(String name, Long id) { + TenantDO tenant = tenantMapper.selectByName(name); + if (tenant == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同名字的租户 + if (id == null) { + throw exception(TENANT_NAME_DUPLICATE, name); + } + if (!tenant.getId().equals(id)) { + throw exception(TENANT_NAME_DUPLICATE, name); + } + } + + private void validTenantWebsiteDuplicate(String website, Long id) { + if (StrUtil.isEmpty(website)) { + return; + } + TenantDO tenant = tenantMapper.selectByWebsite(website); + if (tenant == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同名字的租户 + if (id == null) { + throw exception(TENANT_WEBSITE_DUPLICATE, website); + } + if (!tenant.getId().equals(id)) { + throw exception(TENANT_WEBSITE_DUPLICATE, website); + } + } + + @Override + @DSTransactional + public void updateTenantRoleMenu(Long tenantId, Set menuIds) { + TenantUtils.execute(tenantId, () -> { + // 获得所有角色 + List roles = roleService.getRoleList(); + roles.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配", + role.getId(), role.getTenantId(), tenantId)); // 兜底校验 + // 重新分配每个角色的权限 + roles.forEach(role -> { + // 如果是租户管理员,重新分配其权限为租户套餐的权限 + if (Objects.equals(role.getCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) { + permissionService.assignRoleMenu(role.getId(), menuIds); + log.info("[updateTenantRoleMenu][租户管理员({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), menuIds); + return; + } + // 如果是其他角色,则去掉超过套餐的权限 + Set roleMenuIds = permissionService.getRoleMenuListByRoleId(role.getId()); + roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds); + permissionService.assignRoleMenu(role.getId(), roleMenuIds); + log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds); + }); + }); + } + + @Override + public void deleteTenant(Long id) { + // 校验存在 + validateUpdateTenant(id); + // 删除 + tenantMapper.deleteById(id); + } + + private TenantDO validateUpdateTenant(Long id) { + TenantDO tenant = tenantMapper.selectById(id); + if (tenant == null) { + throw exception(TENANT_NOT_EXISTS); + } + // 内置租户,不允许删除 + if (isSystemTenant(tenant)) { + throw exception(TENANT_CAN_NOT_UPDATE_SYSTEM); + } + return tenant; + } + + @Override + public TenantDO getTenant(Long id) { + return tenantMapper.selectById(id); + } + + @Override + public PageResult getTenantPage(TenantPageReqVO pageReqVO) { + return tenantMapper.selectPage(pageReqVO); + } + + @Override + public TenantDO getTenantByName(String name) { + return tenantMapper.selectByName(name); + } + + @Override + public TenantDO getTenantByWebsite(String website) { + return tenantMapper.selectByWebsite(website); + } + + @Override + public Long getTenantCountByPackageId(Long packageId) { + return tenantMapper.selectCountByPackageId(packageId); + } + + @Override + public List getTenantListByPackageId(Long packageId) { + return tenantMapper.selectListByPackageId(packageId); + } + + @Override + public void handleTenantInfo(TenantInfoHandler handler) { + // 如果禁用,则不执行逻辑 + if (isTenantDisable()) { + return; + } + // 获得租户 + TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId()); + // 执行处理器 + handler.handle(tenant); + } + + @Override + public void handleTenantMenu(TenantMenuHandler handler) { + // 如果禁用,则不执行逻辑 + if (isTenantDisable()) { + return; + } + // 获得租户,然后获得菜单 + TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId()); + Set menuIds; + if (isSystemTenant(tenant)) { // 系统租户,菜单是全量的 + menuIds = CollectionUtils.convertSet(menuService.getMenuList(), MenuDO::getId); + } else { + menuIds = tenantPackageService.getTenantPackage(tenant.getPackageId()).getMenuIds(); + } + // 执行处理器 + handler.handle(menuIds); + } + + private static boolean isSystemTenant(TenantDO tenant) { + return Objects.equals(tenant.getPackageId(), TenantDO.PACKAGE_ID_SYSTEM); + } + + private boolean isTenantDisable() { + return tenantProperties == null || Boolean.FALSE.equals(tenantProperties.getEnable()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantInfoHandler.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantInfoHandler.java new file mode 100644 index 0000000..5b5b9fe --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantInfoHandler.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.service.tenant.handler; + +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; + +/** + * 租户信息处理 + * 目的:尽量减少租户逻辑耦合到系统中 + * + * @author 芋道源码 + */ +public interface TenantInfoHandler { + + /** + * 基于传入的租户信息,进行相关逻辑的执行 + * 例如说,创建用户时,超过最大账户配额 + * + * @param tenant 租户信息 + */ + void handle(TenantDO tenant); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantMenuHandler.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantMenuHandler.java new file mode 100644 index 0000000..2e1be43 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/handler/TenantMenuHandler.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.service.tenant.handler; + +import java.util.Set; + +/** + * 租户菜单处理 + * 目的:尽量减少租户逻辑耦合到系统中 + * + * @author 芋道源码 + */ +public interface TenantMenuHandler { + + /** + * 基于传入的租户菜单【全】列表,进行相关逻辑的执行 + * 例如说,返回可分配菜单的时候,可以移除多余的 + * + * @param menuIds 菜单列表 + */ + void handle(Set menuIds); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java new file mode 100644 index 0000000..e715a69 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -0,0 +1,204 @@ +package cn.iocoder.yudao.module.system.service.user; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; + +import javax.validation.Valid; +import java.io.InputStream; +import java.util.*; + +/** + * 后台用户 Service 接口 + * + * @author 芋道源码 + */ +public interface AdminUserService { + + /** + * 创建用户 + * + * @param createReqVO 用户信息 + * @return 用户编号 + */ + Long createUser(@Valid UserSaveReqVO createReqVO); + + /** + * 修改用户 + * + * @param updateReqVO 用户信息 + */ + void updateUser(@Valid UserSaveReqVO updateReqVO); + + /** + * 更新用户的最后登陆信息 + * + * @param id 用户编号 + * @param loginIp 登陆 IP + */ + void updateUserLogin(Long id, String loginIp); + + /** + * 修改用户个人信息 + * + * @param id 用户编号 + * @param reqVO 用户个人信息 + */ + void updateUserProfile(Long id, @Valid UserProfileUpdateReqVO reqVO); + + /** + * 修改用户个人密码 + * + * @param id 用户编号 + * @param reqVO 更新用户个人密码 + */ + void updateUserPassword(Long id, @Valid UserProfileUpdatePasswordReqVO reqVO); + + /** + * 更新用户头像 + * + * @param id 用户 id + * @param avatarFile 头像文件 + */ + String updateUserAvatar(Long id, InputStream avatarFile) throws Exception; + + /** + * 修改密码 + * + * @param id 用户编号 + * @param password 密码 + */ + void updateUserPassword(Long id, String password); + + /** + * 修改状态 + * + * @param id 用户编号 + * @param status 状态 + */ + void updateUserStatus(Long id, Integer status); + + /** + * 删除用户 + * + * @param id 用户编号 + */ + void deleteUser(Long id); + + /** + * 通过用户名查询用户 + * + * @param username 用户名 + * @return 用户对象信息 + */ + AdminUserDO getUserByUsername(String username); + + /** + * 通过手机号获取用户 + * + * @param mobile 手机号 + * @return 用户对象信息 + */ + AdminUserDO getUserByMobile(String mobile); + + /** + * 获得用户分页列表 + * + * @param reqVO 分页条件 + * @return 分页列表 + */ + PageResult getUserPage(UserPageReqVO reqVO); + + /** + * 通过用户 ID 查询用户 + * + * @param id 用户ID + * @return 用户对象信息 + */ + AdminUserDO getUser(Long id); + + /** + * 获得指定部门的用户数组 + * + * @param deptIds 部门数组 + * @return 用户数组 + */ + List getUserListByDeptIds(Collection deptIds); + + /** + * 获得指定岗位的用户数组 + * + * @param postIds 岗位数组 + * @return 用户数组 + */ + List getUserListByPostIds(Collection postIds); + + /** + * 获得用户列表 + * + * @param ids 用户编号数组 + * @return 用户列表 + */ + List getUserList(Collection ids); + + /** + * 校验用户们是否有效。如下情况,视为无效: + * 1. 用户编号不存在 + * 2. 用户被禁用 + * + * @param ids 用户编号数组 + */ + void validateUserList(Collection ids); + + /** + * 获得用户 Map + * + * @param ids 用户编号数组 + * @return 用户 Map + */ + default Map getUserMap(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return new HashMap<>(); + } + return CollectionUtils.convertMap(getUserList(ids), AdminUserDO::getId); + } + + /** + * 获得用户列表,基于昵称模糊匹配 + * + * @param nickname 昵称 + * @return 用户列表 + */ + List getUserListByNickname(String nickname); + + /** + * 批量导入用户 + * + * @param importUsers 导入用户列表 + * @param isUpdateSupport 是否支持更新 + * @return 导入结果 + */ + UserImportRespVO importUserList(List importUsers, boolean isUpdateSupport); + + /** + * 获得指定状态的用户们 + * + * @param status 状态 + * @return 用户们 + */ + List getUserListByStatus(Integer status); + + /** + * 判断密码是否匹配 + * + * @param rawPassword 未加密的密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + boolean isPasswordMatch(String rawPassword, String encodedPassword); + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java new file mode 100644 index 0000000..d37e093 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -0,0 +1,486 @@ +package cn.iocoder.yudao.module.system.service.user; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRespVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper; +import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import com.google.common.annotations.VisibleForTesting; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.impl.DiffParseFunction; +import com.mzt.logapi.starter.annotation.LogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.InputStream; +import java.time.LocalDateTime; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*; + +/** + * 后台用户 Service 实现类 + * + * @author 芋道源码 + */ +@Service("adminUserService") +@Slf4j +public class AdminUserServiceImpl implements AdminUserService { + + @Value("${sys.user.init-password:yudaoyuanma}") + private String userInitPassword; + + @Resource + private AdminUserMapper userMapper; + + @Resource + private DeptService deptService; + @Resource + private PostService postService; + @Resource + private PermissionService permissionService; + @Resource + private PasswordEncoder passwordEncoder; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantService tenantService; + + @Resource + private UserPostMapper userPostMapper; + + @Resource + private FileApi fileApi; + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", + success = SYSTEM_USER_CREATE_SUCCESS) + public Long createUser(UserSaveReqVO createReqVO) { + // 1.1 校验账户配合 + tenantService.handleTenantInfo(tenant -> { + long count = userMapper.selectCount(); + if (count >= tenant.getAccountCount()) { + throw exception(USER_COUNT_MAX, tenant.getAccountCount()); + } + }); + // 1.2 校验正确性 + validateUserForCreateOrUpdate(null, createReqVO.getUsername(), + createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds()); + // 2.1 插入用户 + AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 + user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码 + userMapper.insert(user); + // 2.2 插入关联岗位 + if (CollectionUtil.isNotEmpty(user.getPostIds())) { + userPostMapper.insertBatch(convertList(user.getPostIds(), + postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId))); + } + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + return user.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = SYSTEM_USER_UPDATE_SUCCESS) + public void updateUser(UserSaveReqVO updateReqVO) { + updateReqVO.setPassword(null); // 特殊:此处不更新密码 + // 1. 校验正确性 + AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(), + updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds()); + + // 2.1 更新用户 + AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class); + userMapper.updateById(updateObj); + // 2.2 更新岗位 + updateUserPost(updateReqVO, updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class)); + LogRecordContext.putVariable("user", oldUser); + } + + private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) { + Long userId = reqVO.getId(); + Set dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId); + // 计算新增和删除的岗位编号 + Set postIds = CollUtil.emptyIfNull(updateObj.getPostIds()); + Collection createPostIds = CollUtil.subtract(postIds, dbPostIds); + Collection deletePostIds = CollUtil.subtract(dbPostIds, postIds); + // 执行新增和删除。对于已经授权的岗位,不用做任何处理 + if (!CollectionUtil.isEmpty(createPostIds)) { + userPostMapper.insertBatch(convertList(createPostIds, + postId -> new UserPostDO().setUserId(userId).setPostId(postId))); + } + if (!CollectionUtil.isEmpty(deletePostIds)) { + userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds); + } + } + + @Override + public void updateUserLogin(Long id, String loginIp) { + userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now())); + } + + @Override + public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) { + // 校验正确性 + validateUserExists(id); + validateEmailUnique(id, reqVO.getEmail()); + validateMobileUnique(id, reqVO.getMobile()); + // 执行更新 + userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id)); + } + + @Override + public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) { + // 校验旧密码密码 + validateOldPassword(id, reqVO.getOldPassword()); + // 执行更新 + AdminUserDO updateObj = new AdminUserDO().setId(id); + updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码 + userMapper.updateById(updateObj); + } + + @Override + public String updateUserAvatar(Long id, InputStream avatarFile) { + validateUserExists(id); + // 存储文件 + String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile)); + // 更新路径 + AdminUserDO sysUserDO = new AdminUserDO(); + sysUserDO.setId(id); + sysUserDO.setAvatar(avatar); + userMapper.updateById(sysUserDO); + return avatar; + } + + @Override + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}", + success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS) + public void updateUserPassword(Long id, String password) { + // 1. 校验用户存在 + AdminUserDO user = validateUserExists(id); + + // 2. 更新密码 + AdminUserDO updateObj = new AdminUserDO(); + updateObj.setId(id); + updateObj.setPassword(encodePassword(password)); // 加密密码 + userMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + LogRecordContext.putVariable("newPassword", updateObj.getPassword()); + } + + @Override + public void updateUserStatus(Long id, Integer status) { + // 校验用户存在 + validateUserExists(id); + // 更新状态 + AdminUserDO updateObj = new AdminUserDO(); + updateObj.setId(id); + updateObj.setStatus(status); + userMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = SYSTEM_USER_DELETE_SUCCESS) + public void deleteUser(Long id) { + // 1. 校验用户存在 + AdminUserDO user = validateUserExists(id); + + // 2.1 删除用户 + userMapper.deleteById(id); + // 2.2 删除用户关联数据 + permissionService.processUserDeleted(id); + // 2.2 删除用户岗位 + userPostMapper.deleteByUserId(id); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable("user", user); + } + + @Override + public AdminUserDO getUserByUsername(String username) { + return userMapper.selectByUsername(username); + } + + @Override + public AdminUserDO getUserByMobile(String mobile) { + return userMapper.selectByMobile(mobile); + } + + @Override + public PageResult getUserPage(UserPageReqVO reqVO) { + return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId())); + } + + @Override + public AdminUserDO getUser(Long id) { + return userMapper.selectById(id); + } + + @Override + public List getUserListByDeptIds(Collection deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return Collections.emptyList(); + } + return userMapper.selectListByDeptIds(deptIds); + } + + @Override + public List getUserListByPostIds(Collection postIds) { + if (CollUtil.isEmpty(postIds)) { + return Collections.emptyList(); + } + Set userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + return userMapper.selectBatchIds(userIds); + } + + @Override + public List getUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return userMapper.selectBatchIds(ids); + } + + @Override + public void validateUserList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得岗位信息 + List users = userMapper.selectBatchIds(ids); + Map userMap = CollectionUtils.convertMap(users, AdminUserDO::getId); + // 校验 + ids.forEach(id -> { + AdminUserDO user = userMap.get(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) { + throw exception(USER_IS_DISABLE, user.getNickname()); + } + }); + } + + @Override + public List getUserListByNickname(String nickname) { + return userMapper.selectListByNickname(nickname); + } + + /** + * 获得部门条件:查询指定部门的子部门编号们,包括自身 + * @param deptId 部门编号 + * @return 部门编号集合 + */ + private Set getDeptCondition(Long deptId) { + if (deptId == null) { + return Collections.emptySet(); + } + Set deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId); + deptIds.add(deptId); // 包括自身 + return deptIds; + } + + private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, + Long deptId, Set postIds) { + // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 + return DataPermissionUtils.executeIgnore(() -> { + // 校验用户存在 + AdminUserDO user = validateUserExists(id); + // 校验用户名唯一 + validateUsernameUnique(id, username); + // 校验手机号唯一 + validateMobileUnique(id, mobile); + // 校验邮箱唯一 + validateEmailUnique(id, email); + // 校验部门处于开启状态 + deptService.validateDeptList(CollectionUtils.singleton(deptId)); + // 校验岗位处于开启状态 + postService.validatePostList(postIds); + return user; + }); + } + + @VisibleForTesting + AdminUserDO validateUserExists(Long id) { + if (id == null) { + return null; + } + AdminUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + return user; + } + + @VisibleForTesting + void validateUsernameUnique(Long id, String username) { + if (StrUtil.isBlank(username)) { + return; + } + AdminUserDO user = userMapper.selectByUsername(username); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(USER_USERNAME_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(USER_USERNAME_EXISTS); + } + } + + @VisibleForTesting + void validateEmailUnique(Long id, String email) { + if (StrUtil.isBlank(email)) { + return; + } + AdminUserDO user = userMapper.selectByEmail(email); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(USER_EMAIL_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(USER_EMAIL_EXISTS); + } + } + + @VisibleForTesting + void validateMobileUnique(Long id, String mobile) { + if (StrUtil.isBlank(mobile)) { + return; + } + AdminUserDO user = userMapper.selectByMobile(mobile); + if (user == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的用户 + if (id == null) { + throw exception(USER_MOBILE_EXISTS); + } + if (!user.getId().equals(id)) { + throw exception(USER_MOBILE_EXISTS); + } + } + + /** + * 校验旧密码 + * @param id 用户 id + * @param oldPassword 旧密码 + */ + @VisibleForTesting + void validateOldPassword(Long id, String oldPassword) { + AdminUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + if (!isPasswordMatch(oldPassword, user.getPassword())) { + throw exception(USER_PASSWORD_FAILED); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 + public UserImportRespVO importUserList(List importUsers, boolean isUpdateSupport) { + if (CollUtil.isEmpty(importUsers)) { + throw exception(USER_IMPORT_LIST_IS_EMPTY); + } + UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()) + .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build(); + importUsers.forEach(importUser -> { + // 校验,判断是否有不符合的原因 + try { + validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), + importUser.getDeptId(), null); + } catch (ServiceException ex) { + respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); + return; + } + // 判断如果不存在,在进行插入 + AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername()); + if (existUser == null) { + userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class) + .setPassword(encodePassword(userInitPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组 + respVO.getCreateUsernames().add(importUser.getUsername()); + return; + } + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg()); + return; + } + AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class); + updateUser.setId(existUser.getId()); + userMapper.updateById(updateUser); + respVO.getUpdateUsernames().add(importUser.getUsername()); + }); + return respVO; + } + + @Override + public List getUserListByStatus(Integer status) { + return userMapper.selectListByStatus(status); + } + + @Override + public boolean isPasswordMatch(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 对密码进行加密 + * + * @param password 密码 + * @return 加密后的密码 + */ + private String encodePassword(String password) { + return passwordEncoder.encode(password); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java new file mode 100644 index 0000000..2a6a46f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.system.util.oauth2; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.*; + +/** + * OAuth2 相关的工具类 + * + * @author 芋道源码 + */ +public class OAuth2Utils { + + /** + * 构建授权码模式下,重定向的 URI + * + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 getSuccessfulRedirect 方法 + * + * @param redirectUri 重定向 URI + * @param authorizationCode 授权码 + * @param state 状态 + * @return 授权码模式下的重定向 URI + */ + public static String buildAuthorizationCodeRedirectUri(String redirectUri, String authorizationCode, String state) { + Map query = new LinkedHashMap<>(); + query.put("code", authorizationCode); + if (state != null) { + query.put("state", state); + } + return HttpUtils.append(redirectUri, query, null, false); + } + + /** + * 构建简化模式下,重定向的 URI + * + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 appendAccessToken 方法 + * + * @param redirectUri 重定向 URI + * @param accessToken 访问令牌 + * @param state 状态 + * @param expireTime 过期时间 + * @param scopes 授权范围 + * @param additionalInformation 附加信息 + * @return 简化授权模式下的重定向 URI + */ + public static String buildImplicitRedirectUri(String redirectUri, String accessToken, String state, LocalDateTime expireTime, + Collection scopes, Map additionalInformation) { + Map vars = new LinkedHashMap(); + Map keys = new HashMap(); + vars.put("access_token", accessToken); + vars.put("token_type", SecurityFrameworkUtils.AUTHORIZATION_BEARER.toLowerCase()); + if (state != null) { + vars.put("state", state); + } + if (expireTime != null) { + vars.put("expires_in", getExpiresIn(expireTime)); + } + if (CollUtil.isNotEmpty(scopes)) { + vars.put("scope", buildScopeStr(scopes)); + } + if (CollUtil.isNotEmpty(additionalInformation)) { + for (String key : additionalInformation.keySet()) { + Object value = additionalInformation.get(key); + if (value != null) { + keys.put("extra_" + key, key); + vars.put("extra_" + key, value); + } + } + } + // Do not include the refresh token (even if there is one) + return HttpUtils.append(redirectUri, vars, keys, true); + } + + public static String buildUnsuccessfulRedirect(String redirectUri, String responseType, String state, + String error, String description) { + Map query = new LinkedHashMap(); + query.put("error", error); + query.put("error_description", description); + if (state != null) { + query.put("state", state); + } + return HttpUtils.append(redirectUri, query, null, !responseType.contains("code")); + } + + public static long getExpiresIn(LocalDateTime expireTime) { + return LocalDateTimeUtil.between(LocalDateTime.now(), expireTime, ChronoUnit.SECONDS); + } + + public static String buildScopeStr(Collection scopes) { + return CollUtil.join(scopes, " "); + } + + public static List buildScopes(String scope) { + return StrUtil.split(scope, ' '); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/package-info.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/package-info.java new file mode 100644 index 0000000..97ca1f1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/package-info.java @@ -0,0 +1,4 @@ +/** + * 每个模块的 util 包,放专属当前模块的 Utils 工具类 + */ +package cn.iocoder.yudao.module.system.util; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService new file mode 100644 index 0000000..946ee59 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService @@ -0,0 +1 @@ +cn.iocoder.yudao.module.system.framework.captcha.core.RedisCaptchaServiceImpl diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png new file mode 100644 index 0000000..c481457 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg1.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png new file mode 100644 index 0000000..bf8fb38 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg2.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png new file mode 100644 index 0000000..f871d3d Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg3.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png new file mode 100644 index 0000000..2e3d871 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg4.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png new file mode 100644 index 0000000..fe383b7 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg5.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png new file mode 100644 index 0000000..5024ceb Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg6.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png new file mode 100644 index 0000000..efe76f8 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg7.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png new file mode 100644 index 0000000..2727aa3 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg8.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png new file mode 100644 index 0000000..4463aa2 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/original/bg9.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png new file mode 100644 index 0000000..ef11324 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/1.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png new file mode 100644 index 0000000..297e44c Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/10.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png new file mode 100644 index 0000000..d9b1da8 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/11.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png new file mode 100644 index 0000000..07e7313 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/12.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png new file mode 100644 index 0000000..82c3dd9 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/13.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png new file mode 100644 index 0000000..0b9a866 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/14.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png new file mode 100644 index 0000000..86b0d1c Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/15.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png new file mode 100644 index 0000000..e90a6e2 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/16.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png new file mode 100644 index 0000000..a82cbc7 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/17.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png new file mode 100644 index 0000000..d3f3cfd Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/18.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png new file mode 100644 index 0000000..eb2855b Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/19.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png new file mode 100644 index 0000000..3cb5ce1 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/8.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png new file mode 100644 index 0000000..384d354 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/11/9.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png new file mode 100644 index 0000000..baf3f06 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/2.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png new file mode 100644 index 0000000..ccaf617 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/3.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png new file mode 100644 index 0000000..7dab162 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/jigsaw/slidingBlock/4.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg1.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg1.png new file mode 100644 index 0000000..14e7345 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg1.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg10.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg10.png new file mode 100644 index 0000000..1ea1d6d Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg10.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg2.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg2.png new file mode 100644 index 0000000..0edb329 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg2.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg3.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg3.png new file mode 100644 index 0000000..9167996 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg3.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg4.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg4.png new file mode 100644 index 0000000..e8e8e6c Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg4.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg5.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg5.png new file mode 100644 index 0000000..66a3181 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg5.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg6.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg6.png new file mode 100644 index 0000000..9b0f5d8 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg6.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg7.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg7.png new file mode 100644 index 0000000..db41c74 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg7.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg8.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg8.png new file mode 100644 index 0000000..3496813 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg8.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg9.png b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg9.png new file mode 100644 index 0000000..4e7b477 Binary files /dev/null and b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/main/resources/images/pic-click/bg9.png differ diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java new file mode 100644 index 0000000..128e759 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java @@ -0,0 +1,337 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * {@link OAuth2OpenController} 的单元测试 + * + * @author 芋道源码 + */ +public class OAuth2OpenControllerTest extends BaseMockitoUnitTest { + + @InjectMocks + private OAuth2OpenController oauth2OpenController; + + @Mock + private OAuth2GrantService oauth2GrantService; + @Mock + private OAuth2ClientService oauth2ClientService; + @Mock + private OAuth2ApproveService oauth2ApproveService; + @Mock + private OAuth2TokenService oauth2TokenService; + + @Test + public void testPostAccessToken_authorizationCode() { + // 准备参数 + String granType = OAuth2GrantTypeEnum.AUTHORIZATION_CODE.getGrantType(); + String code = randomString(); + String redirectUri = randomString(); + String state = randomString(); + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), eq(granType), eq(new ArrayList<>()), eq(redirectUri))).thenReturn(client); + + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); + when(oauth2GrantService.grantAuthorizationCodeForAccessToken(eq("test_client_id"), + eq(code), eq(redirectUri), eq(state))).thenReturn(accessTokenDO); + + // 调用 + CommonResult result = oauth2OpenController.postAccessToken(request, granType, + code, redirectUri, state, null, null, null, null); + // 断言 + assertEquals(0, result.getCode()); + assertPojoEquals(accessTokenDO, result.getData()); + assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 + } + + @Test + public void testPostAccessToken_password() { + // 准备参数 + String granType = OAuth2GrantTypeEnum.PASSWORD.getGrantType(); + String username = randomString(); + String password = randomString(); + String scope = "write read"; + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), + eq(granType), eq(Lists.newArrayList("write", "read")), isNull())).thenReturn(client); + + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); + when(oauth2GrantService.grantPassword(eq(username), eq(password), eq("test_client_id"), + eq(Lists.newArrayList("write", "read")))).thenReturn(accessTokenDO); + + // 调用 + CommonResult result = oauth2OpenController.postAccessToken(request, granType, + null, null, null, username, password, scope, null); + // 断言 + assertEquals(0, result.getCode()); + assertPojoEquals(accessTokenDO, result.getData()); + assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 + } + + @Test + public void testPostAccessToken_refreshToken() { + // 准备参数 + String granType = OAuth2GrantTypeEnum.REFRESH_TOKEN.getGrantType(); + String refreshToken = randomString(); + String password = randomString(); + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), + eq(granType), eq(Lists.newArrayList()), isNull())).thenReturn(client); + + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); + when(oauth2GrantService.grantRefreshToken(eq(refreshToken), eq("test_client_id"))).thenReturn(accessTokenDO); + + // 调用 + CommonResult result = oauth2OpenController.postAccessToken(request, granType, + null, null, null, null, password, null, refreshToken); + // 断言 + assertEquals(0, result.getCode()); + assertPojoEquals(accessTokenDO, result.getData()); + assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 + } + + @Test + public void testPostAccessToken_implicit() { + // 调用,并断言 + assertServiceException(() -> oauth2OpenController.postAccessToken(null, + OAuth2GrantTypeEnum.IMPLICIT.getGrantType(), null, null, null, + null, null, null, null), + new ErrorCode(400, "Token 接口不支持 implicit 授权模式")); + } + + @Test + public void testRevokeToken() { + // 准备参数 + HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); + String token = randomString(); + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id"); + when(oauth2ClientService.validOAuthClientFromCache(eq("demo_client_id"), + eq("demo_client_secret"), isNull(), isNull(), isNull())).thenReturn(client); + // mock 方法(移除) + when(oauth2GrantService.revokeToken(eq("demo_client_id"), eq(token))).thenReturn(true); + + // 调用 + CommonResult result = oauth2OpenController.revokeToken(request, token); + // 断言 + assertEquals(0, result.getCode()); + assertTrue(result.getData()); + } + + @Test + public void testCheckToken() { + // 准备参数 + HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); + String token = randomString(); + // mock 方法 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setUserType(UserTypeEnum.ADMIN.getValue()).setExpiresTime(LocalDateTimeUtil.of(1653485731195L)); + when(oauth2TokenService.checkAccessToken(eq(token))).thenReturn(accessTokenDO); + + // 调用 + CommonResult result = oauth2OpenController.checkToken(request, token); + // 断言 + assertEquals(0, result.getCode()); + assertPojoEquals(accessTokenDO, result.getData()); + assertEquals(1653485731L, result.getData().getExp()); // 执行过程会过去几毫秒 + } + + @Test + public void testAuthorize() { + // 准备参数 + String clientId = randomString(); + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id").setScopes(ListUtil.toList("read", "write", "all")); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(client); + // mock 方法(approve) + List approves = asList( + randomPojo(OAuth2ApproveDO.class).setScope("read").setApproved(true), + randomPojo(OAuth2ApproveDO.class).setScope("write").setApproved(false)); + when(oauth2ApproveService.getApproveList(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId))).thenReturn(approves); + + // 调用 + CommonResult result = oauth2OpenController.authorize(clientId); + // 断言 + assertEquals(0, result.getCode()); + assertPojoEquals(client, result.getData().getClient()); + assertEquals(new KeyValue<>("read", true), result.getData().getScopes().get(0)); + assertEquals(new KeyValue<>("write", false), result.getData().getScopes().get(1)); + assertEquals(new KeyValue<>("all", false), result.getData().getScopes().get(2)); + } + + @Test + public void testApproveOrDeny_grantTypeError() { + // 调用,并断言 + assertServiceException(() -> oauth2OpenController.approveOrDeny(randomString(), null, + null, null, null, null), + new ErrorCode(400, "response_type 参数值只允许 code 和 token")); + } + + @Test // autoApprove = true,但是不通过 + public void testApproveOrDeny_autoApproveNo() { + // 准备参数 + String responseType = "code"; + String clientId = randomString(); + String scope = "{\"read\": true, \"write\": false}"; + String redirectUri = randomString(); + String state = randomString(); + // mock 方法 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); + + // 调用 + CommonResult result = oauth2OpenController.approveOrDeny(responseType, clientId, + scope, redirectUri, true, state); + // 断言 + assertEquals(0, result.getCode()); + assertNull(result.getData()); + } + + @Test // autoApprove = false,但是不通过 + public void testApproveOrDeny_ApproveNo() { + // 准备参数 + String responseType = "token"; + String clientId = randomString(); + String scope = "{\"read\": true, \"write\": false}"; + String redirectUri = "https://www.iocoder.cn"; + String state = "test"; + // mock 方法 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); + + // 调用 + CommonResult result = oauth2OpenController.approveOrDeny(responseType, clientId, + scope, redirectUri, false, state); + // 断言 + assertEquals(0, result.getCode()); + assertEquals("https://www.iocoder.cn#error=access_denied&error_description=User%20denied%20access&state=test", result.getData()); + } + + @Test // autoApprove = true,通过 + token + public void testApproveOrDeny_autoApproveWithToken() { + // 准备参数 + String responseType = "token"; + String clientId = randomString(); + String scope = "{\"read\": true, \"write\": false}"; + String redirectUri = "https://www.iocoder.cn"; + String state = "test"; + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); + // mock 方法(场景一) + when(oauth2ApproveService.checkForPreApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), + eq(clientId), eq(SetUtils.asSet("read", "write")))).thenReturn(true); + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setAccessToken("test_access_token").setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30010L, ChronoUnit.MILLIS)); + when(oauth2GrantService.grantImplicit(isNull(), eq(UserTypeEnum.ADMIN.getValue()), + eq(clientId), eq(ListUtil.toList("read")))).thenReturn(accessTokenDO); + + // 调用 + CommonResult result = oauth2OpenController.approveOrDeny(responseType, clientId, + scope, redirectUri, true, state); + // 断言 + assertEquals(0, result.getCode()); + assertThat(result.getData(), anyOf( // 29 和 30 都有一定概率,主要是时间计算 + is("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=29&scope=read"), + is("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read") + )); + } + + @Test // autoApprove = false,通过 + code + public void testApproveOrDeny_approveWithCode() { + // 准备参数 + String responseType = "code"; + String clientId = randomString(); + String scope = "{\"read\": true, \"write\": false}"; + String redirectUri = "https://www.iocoder.cn"; + String state = "test"; + // mock 方法(client) + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); + // mock 方法(场景二) + when(oauth2ApproveService.updateAfterApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId), + eq(MapUtil.builder(new LinkedHashMap()).put("read", true).put("write", false).build()))) + .thenReturn(true); + // mock 方法(访问令牌) + String authorizationCode = "test_code"; + when(oauth2GrantService.grantAuthorizationCodeForCode(isNull(), eq(UserTypeEnum.ADMIN.getValue()), + eq(clientId), eq(ListUtil.toList("read")), eq(redirectUri), eq(state))).thenReturn(authorizationCode); + + // 调用 + CommonResult result = oauth2OpenController.approveOrDeny(responseType, clientId, + scope, redirectUri, false, state); + // 断言 + assertEquals(0, result.getCode()); + assertEquals("https://www.iocoder.cn?code=test_code&state=test", result.getData()); + } + + private HttpServletRequest mockRequest(String clientId, String secret) { + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getParameter(eq("client_id"))).thenReturn(clientId); + when(request.getParameter(eq("client_secret"))).thenReturn(secret); + return request; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClientTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClientTest.java new file mode 100644 index 0000000..ac26d13 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClientTest.java @@ -0,0 +1,187 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * {@link AliyunSmsClient} 的单元测试 + * + * @author 芋道源码 + */ +public class AliyunSmsClientTest extends BaseMockitoUnitTest { + + private final SmsChannelProperties properties = new SmsChannelProperties() + .setApiKey(randomString()) // 随机一个 apiKey,避免构建报错 + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 + .setSignature("芋道源码"); + + @InjectMocks + private final AliyunSmsClient smsClient = new AliyunSmsClient(properties); + + @Mock + private IAcsClient client; + + @Test + public void testDoInit() { + // 准备参数 + // mock 方法 + + // 调用 + smsClient.doInit(); + // 断言 + assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "acsClient")); + } + + @Test + public void tesSendSms_success() throws Throwable { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); + // mock 方法 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("OK")); + when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { + assertEquals(mobile, acsRequest.getPhoneNumbers()); + assertEquals(properties.getSignature(), acsRequest.getSignName()); + assertEquals(apiTemplateId, acsRequest.getTemplateCode()); + assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam()); + assertEquals(sendLogId.toString(), acsRequest.getOutId()); + return true; + }))).thenReturn(response); + + // 调用 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, + apiTemplateId, templateParams); + // 断言 + assertTrue(result.getSuccess()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + assertEquals(response.getCode(), result.getApiCode()); + assertEquals(response.getMessage(), result.getApiMsg()); + assertEquals(response.getBizId(), result.getSerialNo()); + } + + @Test + public void tesSendSms_fail() throws Throwable { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); + // mock 方法 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("ERROR")); + when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { + assertEquals(mobile, acsRequest.getPhoneNumbers()); + assertEquals(properties.getSignature(), acsRequest.getSignName()); + assertEquals(apiTemplateId, acsRequest.getTemplateCode()); + assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam()); + assertEquals(sendLogId.toString(), acsRequest.getOutId()); + return true; + }))).thenReturn(response); + + // 调用 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams); + // 断言 + assertFalse(result.getSuccess()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + assertEquals(response.getCode(), result.getApiCode()); + assertEquals(response.getMessage(), result.getApiMsg()); + assertEquals(response.getBizId(), result.getSerialNo()); + } + + @Test + public void testParseSmsReceiveStatus() { + // 准备参数 + String text = "[\n" + + " {\n" + + " \"phone_number\" : \"13900000001\",\n" + + " \"send_time\" : \"2017-01-01 11:12:13\",\n" + + " \"report_time\" : \"2017-02-02 22:23:24\",\n" + + " \"success\" : true,\n" + + " \"err_code\" : \"DELIVERED\",\n" + + " \"err_msg\" : \"用户接收成功\",\n" + + " \"sms_size\" : \"1\",\n" + + " \"biz_id\" : \"12345\",\n" + + " \"out_id\" : \"67890\"\n" + + " }\n" + + "]"; + // mock 方法 + + // 调用 + List statuses = smsClient.parseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("DELIVERED", statuses.get(0).getErrorCode()); + assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); + assertEquals("13900000001", statuses.get(0).getMobile()); + assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24), + statuses.get(0).getReceiveTime()); + assertEquals("12345", statuses.get(0).getSerialNo()); + assertEquals(67890L, statuses.get(0).getLogId()); + } + + @Test + public void testGetSmsTemplate() throws Throwable { + // 准备参数 + String apiTemplateId = randomString(); + // mock 方法 + QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> { + o.setCode("OK"); + o.setTemplateStatus(1); // 设置模板通过 + }); + when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { + assertEquals(apiTemplateId, acsRequest.getTemplateCode()); + return true; + }))).thenReturn(response); + + // 调用 + SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId); + // 断言 + assertEquals(response.getTemplateCode(), result.getId()); + assertEquals(response.getTemplateContent(), result.getContent()); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus()); + assertEquals(response.getReason(), result.getAuditReason()); + } + + @Test + public void testConvertSmsTemplateAuditStatus() { + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), + smsClient.convertSmsTemplateAuditStatus(0)); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + smsClient.convertSmsTemplateAuditStatus(1)); + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), + smsClient.convertSmsTemplateAuditStatus(2)); + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3), + "未知审核状态(3)"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClientTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClientTest.java new file mode 100644 index 0000000..e93435f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClientTest.java @@ -0,0 +1,230 @@ +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import com.google.common.collect.Lists; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.DescribeSmsTemplateListResponse; +import com.tencentcloudapi.sms.v20210111.models.DescribeTemplateListStatus; +import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; +import com.tencentcloudapi.sms.v20210111.models.SendStatus; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * {@link TencentSmsClient} 的单元测试 + * + * @author shiwp + */ +public class TencentSmsClientTest extends BaseMockitoUnitTest { + + private final SmsChannelProperties properties = new SmsChannelProperties() + .setApiKey(randomString() + " " + randomString()) // 随机一个 apiKey,避免构建报错 + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 + .setSignature("芋道源码"); + + @InjectMocks + private TencentSmsClient smsClient = new TencentSmsClient(properties); + + @Mock + private SmsClient client; + + @Test + public void testDoInit() { + // 准备参数 + // mock 方法 + + // 调用 + smsClient.doInit(); + // 断言 + assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "client")); + } + + @Test + public void testRefresh() { + // 准备参数 + SmsChannelProperties p = new SmsChannelProperties() + .setApiKey(randomString() + " " + randomString()) // 随机一个 apiKey,避免构建报错 + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 + .setSignature("芋道源码"); + // 调用 + smsClient.refresh(p); + // 断言 + assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "client")); + } + + @Test + public void testDoSendSms_success() throws Throwable { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("1", 1234), new KeyValue<>("2", "login")); + String requestId = randomString(); + String serialNo = randomString(); + // mock 方法 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> { + o.setRequestId(requestId); + SendStatus[] sendStatuses = new SendStatus[1]; + o.setSendStatusSet(sendStatuses); + SendStatus sendStatus = new SendStatus(); + sendStatuses[0] = sendStatus; + sendStatus.setCode(TencentSmsClient.API_CODE_SUCCESS); + sendStatus.setMessage("send success"); + sendStatus.setSerialNo(serialNo); + }); + when(client.SendSms(argThat(request -> { + assertEquals(mobile, request.getPhoneNumberSet()[0]); + assertEquals(properties.getSignature(), request.getSignName()); + assertEquals(apiTemplateId, request.getTemplateId()); + assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)), + toJsonString(request.getTemplateParamSet())); + assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId")); + return true; + }))).thenReturn(response); + + // 调用 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams); + // 断言 + assertTrue(result.getSuccess()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode()); + assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg()); + assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo()); + } + + @Test + public void testDoSendSms_fail() throws Throwable { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("1", 1234), new KeyValue<>("2", "login")); + String requestId = randomString(); + String serialNo = randomString(); + // mock 方法 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> { + o.setRequestId(requestId); + SendStatus[] sendStatuses = new SendStatus[1]; + o.setSendStatusSet(sendStatuses); + SendStatus sendStatus = new SendStatus(); + sendStatuses[0] = sendStatus; + sendStatus.setCode("ERROR"); + sendStatus.setMessage("send success"); + sendStatus.setSerialNo(serialNo); + }); + when(client.SendSms(argThat(request -> { + assertEquals(mobile, request.getPhoneNumberSet()[0]); + assertEquals(properties.getSignature(), request.getSignName()); + assertEquals(apiTemplateId, request.getTemplateId()); + assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)), + toJsonString(request.getTemplateParamSet())); + assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId")); + return true; + }))).thenReturn(response); + + // 调用 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams); + // 断言 + assertFalse(result.getSuccess()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode()); + assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg()); + assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo()); + } + + @Test + public void testParseSmsReceiveStatus() { + // 准备参数 + String text = "[\n" + + " {\n" + + " \"user_receive_time\": \"2015-10-17 08:03:04\",\n" + + " \"nationcode\": \"86\",\n" + + " \"mobile\": \"13900000001\",\n" + + " \"report_status\": \"SUCCESS\",\n" + + " \"errmsg\": \"DELIVRD\",\n" + + " \"description\": \"用户短信送达成功\",\n" + + " \"sid\": \"12345\",\n" + + " \"ext\": {\"logId\":\"67890\"}\n" + + " }\n" + + "]"; + // mock 方法 + + // 调用 + List statuses = smsClient.parseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("DELIVRD", statuses.get(0).getErrorCode()); + assertEquals("用户短信送达成功", statuses.get(0).getErrorMsg()); + assertEquals("13900000001", statuses.get(0).getMobile()); + assertEquals(LocalDateTime.of(2015, 10, 17, 8, 3, 4), statuses.get(0).getReceiveTime()); + assertEquals("12345", statuses.get(0).getSerialNo()); + assertEquals(67890L, statuses.get(0).getLogId()); + } + + @Test + public void testGetSmsTemplate() throws Throwable { + // 准备参数 + Long apiTemplateId = randomLongId(); + String requestId = randomString(); + + // mock 方法 + DescribeSmsTemplateListResponse response = randomPojo(DescribeSmsTemplateListResponse.class, o -> { + DescribeTemplateListStatus[] describeTemplateListStatuses = new DescribeTemplateListStatus[1]; + DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus(); + templateStatus.setTemplateId(apiTemplateId); + templateStatus.setStatusCode(0L);// 设置模板通过 + describeTemplateListStatuses[0] = templateStatus; + o.setDescribeTemplateStatusSet(describeTemplateListStatuses); + o.setRequestId(requestId); + }); + when(client.DescribeSmsTemplateList(argThat(request -> { + assertEquals(apiTemplateId, request.getTemplateIdSet()[0]); + return true; + }))).thenReturn(response); + + // 调用 + SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId.toString()); + // 断言 + assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getId()); + assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getContent()); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus()); + assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getAuditReason()); + } + + @Test + public void testConvertSmsTemplateAuditStatus() { + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + smsClient.convertSmsTemplateAuditStatus(0)); + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), + smsClient.convertSmsTemplateAuditStatus(1)); + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), + smsClient.convertSmsTemplateAuditStatus(-1)); + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3), + "未知审核状态(3)"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java new file mode 100644 index 0000000..9ade60a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java @@ -0,0 +1,372 @@ +package cn.iocoder.yudao.module.system.service.auth; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; +import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import cn.iocoder.yudao.module.system.service.logger.LoginLogService; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.service.CaptchaService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@Import(AdminAuthServiceImpl.class) +public class AdminAuthServiceImplTest extends BaseDbUnitTest { + + @Resource + private AdminAuthServiceImpl authService; + + @MockBean + private AdminUserService userService; + @MockBean + private CaptchaService captchaService; + @MockBean + private LoginLogService loginLogService; + @MockBean + private SocialUserService socialUserService; + @MockBean + private SmsCodeApi smsCodeApi; + @MockBean + private OAuth2TokenService oauth2TokenService; + @MockBean + private MemberService memberService; + @MockBean + private Validator validator; + + @BeforeEach + public void setUp() { + ReflectUtil.setFieldValue(authService, "captchaEnable", true); + // 注入一个 Validator 对象 + ReflectUtil.setFieldValue(authService, "validator", + Validation.buildDefaultValidatorFactory().getValidator()); + } + + @Test + public void testAuthenticate_success() { + // 准备参数 + String username = randomString(); + String password = randomString(); + // mock user 数据 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) + .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(userService.getUserByUsername(eq(username))).thenReturn(user); + // mock password 匹配 + when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true); + + // 调用 + AdminUserDO loginUser = authService.authenticate(username, password); + // 校验 + assertPojoEquals(user, loginUser); + } + + @Test + public void testAuthenticate_userNotFound() { + // 准备参数 + String username = randomString(); + String password = randomString(); + + // 调用, 并断言异常 + assertServiceException(() -> authService.authenticate(username, password), + AUTH_LOGIN_BAD_CREDENTIALS); + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) + && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult()) + && o.getUserId() == null) + ); + } + + @Test + public void testAuthenticate_badCredentials() { + // 准备参数 + String username = randomString(); + String password = randomString(); + // mock user 数据 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) + .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(userService.getUserByUsername(eq(username))).thenReturn(user); + + // 调用, 并断言异常 + assertServiceException(() -> authService.authenticate(username, password), + AUTH_LOGIN_BAD_CREDENTIALS); + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) + && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult()) + && o.getUserId().equals(user.getId())) + ); + } + + @Test + public void testAuthenticate_userDisabled() { + // 准备参数 + String username = randomString(); + String password = randomString(); + // mock user 数据 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) + .setPassword(password).setStatus(CommonStatusEnum.DISABLE.getStatus())); + when(userService.getUserByUsername(eq(username))).thenReturn(user); + // mock password 匹配 + when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true); + + // 调用, 并断言异常 + assertServiceException(() -> authService.authenticate(username, password), + AUTH_LOGIN_USER_DISABLED); + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) + && o.getResult().equals(LoginResultEnum.USER_DISABLED.getResult()) + && o.getUserId().equals(user.getId())) + ); + } + + @Test + public void testLogin_success() { + // 准备参数 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class, o -> + o.setUsername("test_username").setPassword("test_password") + .setSocialType(randomEle(SocialTypeEnum.values()).getType())); + + // mock 验证码正确 + ReflectUtil.setFieldValue(authService, "captchaEnable", false); + // mock user 数据 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(1L).setUsername("test_username") + .setPassword("test_password").setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(userService.getUserByUsername(eq("test_username"))).thenReturn(user); + // mock password 匹配 + when(userService.isPasswordMatch(eq("test_password"), eq(user.getPassword()))).thenReturn(true); + // mock 缓存登录用户到 Redis + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) + .thenReturn(accessTokenDO); + + // 调用,并校验 + AuthLoginRespVO loginRespVO = authService.login(reqVO); + assertPojoEquals(accessTokenDO, loginRespVO); + // 校验调用参数 + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) + && o.getUserId().equals(user.getId())) + ); + verify(socialUserService).bindSocialUser(eq(new SocialUserBindReqDTO( + user.getId(), UserTypeEnum.ADMIN.getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()))); + } + + @Test + public void testSendSmsCode() { + // 准备参数 + String mobile = randomString(); + Integer scene = randomEle(SmsSceneEnum.values()).getScene(); + AuthSmsSendReqVO reqVO = new AuthSmsSendReqVO(mobile, scene); + // mock 方法(用户信息) + AdminUserDO user = randomPojo(AdminUserDO.class); + when(userService.getUserByMobile(eq(mobile))).thenReturn(user); + + // 调用 + authService.sendSmsCode(reqVO); + // 断言 + verify(smsCodeApi).sendSmsCode(argThat(sendReqDTO -> { + assertEquals(mobile, sendReqDTO.getMobile()); + assertEquals(scene, sendReqDTO.getScene()); + return true; + })); + } + + @Test + public void testSmsLogin_success() { + // 准备参数 + String mobile = randomString(); + String code = randomString(); + AuthSmsLoginReqVO reqVO = new AuthSmsLoginReqVO(mobile, code); + // mock 方法(用户信息) + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(1L)); + when(userService.getUserByMobile(eq(mobile))).thenReturn(user); + // mock 缓存登录用户到 Redis + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) + .thenReturn(accessTokenDO); + + // 调用,并断言 + AuthLoginRespVO loginRespVO = authService.smsLogin(reqVO); + assertPojoEquals(accessTokenDO, loginRespVO); + // 断言调用 + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_MOBILE.getType()) + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) + && o.getUserId().equals(user.getId())) + ); + } + + @Test + public void testSocialLogin_success() { + // 准备参数 + AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); + // mock 方法(绑定的用户编号) + Long userId = 1L; + when(socialUserService.getSocialUserByCode(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), + eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), randomString(), randomString(), userId)); + // mock(用户) + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); + when(userService.getUser(eq(userId))).thenReturn(user); + // mock 缓存登录用户到 Redis + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) + .thenReturn(accessTokenDO); + + // 调用,并断言 + AuthLoginRespVO loginRespVO = authService.socialLogin(reqVO); + assertPojoEquals(accessTokenDO, loginRespVO); + // 断言调用 + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_SOCIAL.getType()) + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) + && o.getUserId().equals(user.getId())) + ); + } + + @Test + public void testValidateCaptcha_successWithEnable() { + // 准备参数 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); + + // mock 验证码打开 + ReflectUtil.setFieldValue(authService, "captchaEnable", true); + // mock 验证通过 + when(captchaService.verification(argThat(captchaVO -> { + assertEquals(reqVO.getCaptchaVerification(), captchaVO.getCaptchaVerification()); + return true; + }))).thenReturn(ResponseModel.success()); + + // 调用,无需断言 + authService.validateCaptcha(reqVO); + } + + @Test + public void testValidateCaptcha_successWithDisable() { + // 准备参数 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); + + // mock 验证码关闭 + ReflectUtil.setFieldValue(authService, "captchaEnable", false); + + // 调用,无需断言 + authService.validateCaptcha(reqVO); + } + + @Test + public void testValidateCaptcha_constraintViolationException() { + // 准备参数 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class).setCaptchaVerification(null); + + // mock 验证码打开 + ReflectUtil.setFieldValue(authService, "captchaEnable", true); + + // 调用,并断言异常 + assertThrows(ConstraintViolationException.class, () -> authService.validateCaptcha(reqVO), + "验证码不能为空"); + } + + + @Test + public void testCaptcha_fail() { + // 准备参数 + AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); + + // mock 验证码打开 + ReflectUtil.setFieldValue(authService, "captchaEnable", true); + // mock 验证通过 + when(captchaService.verification(argThat(captchaVO -> { + assertEquals(reqVO.getCaptchaVerification(), captchaVO.getCaptchaVerification()); + return true; + }))).thenReturn(ResponseModel.errorMsg("就是不对")); + + // 调用, 并断言异常 + assertServiceException(() -> authService.validateCaptcha(reqVO), AUTH_LOGIN_CAPTCHA_CODE_ERROR, "就是不对"); + // 校验调用参数 + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) + && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult())) + ); + } + + @Test + public void testRefreshToken() { + // 准备参数 + String refreshToken = randomString(); + // mock 方法 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.refreshAccessToken(eq(refreshToken), eq("default"))) + .thenReturn(accessTokenDO); + + // 调用 + AuthLoginRespVO loginRespVO = authService.refreshToken(refreshToken); + // 断言 + assertPojoEquals(accessTokenDO, loginRespVO); + } + + @Test + public void testLogout_success() { + // 准备参数 + String token = randomString(); + // mock + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + when(oauth2TokenService.removeAccessToken(eq(token))).thenReturn(accessTokenDO); + + // 调用 + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); + // 校验调用参数 + verify(loginLogService).createLoginLog( + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) + ); + // 调用,并校验 + + } + + @Test + public void testLogout_fail() { + // 准备参数 + String token = randomString(); + + // 调用 + authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); + // 校验调用参数 + verify(loginLogService, never()).createLoginLog(any()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java new file mode 100644 index 0000000..abfa225 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java @@ -0,0 +1,296 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link DeptServiceImpl} 的单元测试类 + * + * @author niudehua + */ +@Import(DeptServiceImpl.class) +public class DeptServiceImplTest extends BaseDbUnitTest { + + @Resource + private DeptServiceImpl deptService; + @Resource + private DeptMapper deptMapper; + + @Test + public void testCreateDept() { + // 准备参数 + DeptSaveReqVO reqVO = randomPojo(DeptSaveReqVO.class, o -> { + o.setId(null); // 防止 id 被设置 + o.setParentId(DeptDO.PARENT_ID_ROOT); + o.setStatus(randomCommonStatus()); + }); + + // 调用 + Long deptId = deptService.createDept(reqVO); + // 断言 + assertNotNull(deptId); + // 校验记录的属性是否正确 + DeptDO deptDO = deptMapper.selectById(deptId); + assertPojoEquals(reqVO, deptDO, "id"); + } + + @Test + public void testUpdateDept() { + // mock 数据 + DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())); + deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DeptSaveReqVO reqVO = randomPojo(DeptSaveReqVO.class, o -> { + // 设置更新的 ID + o.setParentId(DeptDO.PARENT_ID_ROOT); + o.setId(dbDeptDO.getId()); + o.setStatus(randomCommonStatus()); + }); + + // 调用 + deptService.updateDept(reqVO); + // 校验是否更新正确 + DeptDO deptDO = deptMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, deptDO); + } + + @Test + public void testDeleteDept_success() { + // mock 数据 + DeptDO dbDeptDO = randomPojo(DeptDO.class); + deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDeptDO.getId(); + + // 调用 + deptService.deleteDept(id); + // 校验数据不存在了 + assertNull(deptMapper.selectById(id)); + } + + @Test + public void testDeleteDept_exitsChildren() { + // mock 数据 + DeptDO parentDept = randomPojo(DeptDO.class); + deptMapper.insert(parentDept);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DeptDO childrenDeptDO = randomPojo(DeptDO.class, o -> { + o.setParentId(parentDept.getId()); + o.setStatus(randomCommonStatus()); + }); + // 插入子部门 + deptMapper.insert(childrenDeptDO); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.deleteDept(parentDept.getId()), DEPT_EXITS_CHILDREN); + } + + @Test + public void testValidateDeptExists_notFound() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateDeptExists(id), DEPT_NOT_FOUND); + } + + @Test + public void testValidateParentDept_parentError() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateParentDept(id, id), + DEPT_PARENT_ERROR); + } + + @Test + public void testValidateParentDept_parentIsChild() { + // mock 数据(父节点) + DeptDO parentDept = randomPojo(DeptDO.class); + deptMapper.insert(parentDept); + // mock 数据(子节点) + DeptDO childDept = randomPojo(DeptDO.class, o -> { + o.setParentId(parentDept.getId()); + }); + deptMapper.insert(childDept); + + // 准备参数 + Long id = parentDept.getId(); + Long parentId = childDept.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateParentDept(id, parentId), DEPT_PARENT_IS_CHILD); + } + + @Test + public void testValidateNameUnique_duplicate() { + // mock 数据 + DeptDO deptDO = randomPojo(DeptDO.class); + deptMapper.insert(deptDO); + + // 准备参数 + Long id = randomLongId(); + Long parentId = deptDO.getParentId(); + String name = deptDO.getName(); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateDeptNameUnique(id, parentId, name), + DEPT_NAME_DUPLICATE); + } + + @Test + public void testGetDept() { + // mock 数据 + DeptDO deptDO = randomPojo(DeptDO.class); + deptMapper.insert(deptDO); + // 准备参数 + Long id = deptDO.getId(); + + // 调用 + DeptDO dbDept = deptService.getDept(id); + // 断言 + assertEquals(deptDO, dbDept); + } + + @Test + public void testGetDeptList_ids() { + // mock 数据 + DeptDO deptDO01 = randomPojo(DeptDO.class); + deptMapper.insert(deptDO01); + DeptDO deptDO02 = randomPojo(DeptDO.class); + deptMapper.insert(deptDO02); + // 准备参数 + List ids = Arrays.asList(deptDO01.getId(), deptDO02.getId()); + + // 调用 + List deptDOList = deptService.getDeptList(ids); + // 断言 + assertEquals(2, deptDOList.size()); + assertEquals(deptDO01, deptDOList.get(0)); + assertEquals(deptDO02, deptDOList.get(1)); + } + + @Test + public void testGetDeptList_reqVO() { + // mock 数据 + DeptDO dept = randomPojo(DeptDO.class, o -> { // 等会查询到 + o.setName("开发部"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + deptMapper.insert(dept); + // 测试 name 不匹配 + deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setName("发"))); + // 测试 status 不匹配 + deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + DeptListReqVO reqVO = new DeptListReqVO(); + reqVO.setName("开"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + List sysDeptDOS = deptService.getDeptList(reqVO); + // 断言 + assertEquals(1, sysDeptDOS.size()); + assertPojoEquals(dept, sysDeptDOS.get(0)); + } + + @Test + public void testGetChildDeptList() { + // mock 数据(1 级别子节点) + DeptDO dept1 = randomPojo(DeptDO.class, o -> o.setName("1")); + deptMapper.insert(dept1); + DeptDO dept2 = randomPojo(DeptDO.class, o -> o.setName("2")); + deptMapper.insert(dept2); + // mock 数据(2 级子节点) + DeptDO dept1a = randomPojo(DeptDO.class, o -> o.setName("1-a").setParentId(dept1.getId())); + deptMapper.insert(dept1a); + DeptDO dept2a = randomPojo(DeptDO.class, o -> o.setName("2-a").setParentId(dept2.getId())); + deptMapper.insert(dept2a); + // 准备参数 + Long id = dept1.getParentId(); + + // 调用 + List result = deptService.getChildDeptList(id); + // 断言 + assertEquals(result.size(), 2); + assertPojoEquals(dept1, result.get(0)); + assertPojoEquals(dept1a, result.get(1)); + } + + @Test + public void testGetChildDeptListFromCache() { + // mock 数据(1 级别子节点) + DeptDO dept1 = randomPojo(DeptDO.class, o -> o.setName("1")); + deptMapper.insert(dept1); + DeptDO dept2 = randomPojo(DeptDO.class, o -> o.setName("2")); + deptMapper.insert(dept2); + // mock 数据(2 级子节点) + DeptDO dept1a = randomPojo(DeptDO.class, o -> o.setName("1-a").setParentId(dept1.getId())); + deptMapper.insert(dept1a); + DeptDO dept2a = randomPojo(DeptDO.class, o -> o.setName("2-a").setParentId(dept2.getId())); + deptMapper.insert(dept2a); + // 准备参数 + Long id = dept1.getParentId(); + + // 调用 + Set result = deptService.getChildDeptIdListFromCache(id); + // 断言 + assertEquals(result.size(), 2); + assertTrue(result.contains(dept1.getId())); + assertTrue(result.contains(dept1a.getId())); + } + + @Test + public void testValidateDeptList_success() { + // mock 数据 + DeptDO deptDO = randomPojo(DeptDO.class).setStatus(CommonStatusEnum.ENABLE.getStatus()); + deptMapper.insert(deptDO); + // 准备参数 + List ids = singletonList(deptDO.getId()); + + // 调用,无需断言 + deptService.validateDeptList(ids); + } + + @Test + public void testValidateDeptList_notFound() { + // 准备参数 + List ids = singletonList(randomLongId()); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateDeptList(ids), DEPT_NOT_FOUND); + } + + @Test + public void testValidateDeptList_notEnable() { + // mock 数据 + DeptDO deptDO = randomPojo(DeptDO.class).setStatus(CommonStatusEnum.DISABLE.getStatus()); + deptMapper.insert(deptDO); + // 准备参数 + List ids = singletonList(deptDO.getId()); + + // 调用, 并断言异常 + assertServiceException(() -> deptService.validateDeptList(ids), DEPT_NOT_ENABLE, deptDO.getName()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java new file mode 100644 index 0000000..a641227 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java @@ -0,0 +1,248 @@ +package cn.iocoder.yudao.module.system.service.dept; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link PostServiceImpl} 的单元测试类 + * + * @author niudehua + */ +@Import(PostServiceImpl.class) +public class PostServiceImplTest extends BaseDbUnitTest { + + @Resource + private PostServiceImpl postService; + + @Resource + private PostMapper postMapper; + + @Test + public void testCreatePost_success() { + // 准备参数 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, + o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus())) + .setId(null); // 防止 id 被设置 + // 调用 + Long postId = postService.createPost(reqVO); + + // 断言 + assertNotNull(postId); + // 校验记录的属性是否正确 + PostDO post = postMapper.selectById(postId); + assertPojoEquals(reqVO, post, "id"); + } + + @Test + public void testUpdatePost_success() { + // mock 数据 + PostDO postDO = randomPostDO(); + postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, o -> { + // 设置更新的 ID + o.setId(postDO.getId()); + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); + }); + + // 调用 + postService.updatePost(reqVO); + // 校验是否更新正确 + PostDO post = postMapper.selectById(reqVO.getId()); + assertPojoEquals(reqVO, post); + } + + @Test + public void testDeletePost_success() { + // mock 数据 + PostDO postDO = randomPostDO(); + postMapper.insert(postDO); + // 准备参数 + Long id = postDO.getId(); + + // 调用 + postService.deletePost(id); + assertNull(postMapper.selectById(id)); + } + + @Test + public void testValidatePost_notFoundForDelete() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> postService.deletePost(id), POST_NOT_FOUND); + } + + @Test + public void testValidatePost_nameDuplicateForCreate() { + // mock 数据 + PostDO postDO = randomPostDO(); + postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, + // 模拟 name 重复 + o -> o.setName(postDO.getName())); + assertServiceException(() -> postService.createPost(reqVO), POST_NAME_DUPLICATE); + } + + @Test + public void testValidatePost_codeDuplicateForUpdate() { + // mock 数据 + PostDO postDO = randomPostDO(); + postMapper.insert(postDO); + // mock 数据:稍后模拟重复它的 code + PostDO codePostDO = randomPostDO(); + postMapper.insert(codePostDO); + // 准备参数 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, o -> { + // 设置更新的 ID + o.setId(postDO.getId()); + // 模拟 code 重复 + o.setCode(codePostDO.getCode()); + }); + + // 调用, 并断言异常 + assertServiceException(() -> postService.updatePost(reqVO), POST_CODE_DUPLICATE); + } + + @Test + public void testGetPostPage() { + // mock 数据 + PostDO postDO = randomPojo(PostDO.class, o -> { + o.setName("码仔"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + postMapper.insert(postDO); + // 测试 name 不匹配 + postMapper.insert(cloneIgnoreId(postDO, o -> o.setName("程序员"))); + // 测试 status 不匹配 + postMapper.insert(cloneIgnoreId(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + PostPageReqVO reqVO = new PostPageReqVO(); + reqVO.setName("码"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + PageResult pageResult = postService.getPostPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(postDO, pageResult.getList().get(0)); + } + + @Test + public void testGetPostList() { + // mock 数据 + PostDO postDO01 = randomPojo(PostDO.class); + postMapper.insert(postDO01); + // 测试 id 不匹配 + PostDO postDO02 = randomPojo(PostDO.class); + postMapper.insert(postDO02); + // 准备参数 + List ids = singletonList(postDO01.getId()); + + // 调用 + List list = postService.getPostList(ids); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(postDO01, list.get(0)); + } + + @Test + public void testGetPostList_idsAndStatus() { + // mock 数据 + PostDO postDO01 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + postMapper.insert(postDO01); + // 测试 status 不匹配 + PostDO postDO02 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + postMapper.insert(postDO02); + // 准备参数 + List ids = Arrays.asList(postDO01.getId(), postDO02.getId()); + + // 调用 + List list = postService.getPostList(ids, singletonList(CommonStatusEnum.ENABLE.getStatus())); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(postDO01, list.get(0)); + } + + @Test + public void testGetPost() { + // mock 数据 + PostDO dbPostDO = randomPostDO(); + postMapper.insert(dbPostDO); + // 准备参数 + Long id = dbPostDO.getId(); + // 调用 + PostDO post = postService.getPost(id); + // 断言 + assertNotNull(post); + assertPojoEquals(dbPostDO, post); + } + + @Test + public void testValidatePostList_success() { + // mock 数据 + PostDO postDO = randomPostDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); + postMapper.insert(postDO); + // 准备参数 + List ids = singletonList(postDO.getId()); + + // 调用,无需断言 + postService.validatePostList(ids); + } + + @Test + public void testValidatePostList_notFound() { + // 准备参数 + List ids = singletonList(randomLongId()); + + // 调用, 并断言异常 + assertServiceException(() -> postService.validatePostList(ids), POST_NOT_FOUND); + } + + @Test + public void testValidatePostList_notEnable() { + // mock 数据 + PostDO postDO = randomPostDO().setStatus(CommonStatusEnum.DISABLE.getStatus()); + postMapper.insert(postDO); + // 准备参数 + List ids = singletonList(postDO.getId()); + + // 调用, 并断言异常 + assertServiceException(() -> postService.validatePostList(ids), POST_NOT_ENABLE, + postDO.getName()); + } + + @SafeVarargs + private static PostDO randomPostDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomCommonStatus()); // 保证 status 的范围 + }; + return randomPojo(PostDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImplTest.java new file mode 100644 index 0000000..68edd73 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImplTest.java @@ -0,0 +1,352 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.dict.DictDataMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.function.Consumer; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@Import(DictDataServiceImpl.class) +public class DictDataServiceImplTest extends BaseDbUnitTest { + + @Resource + private DictDataServiceImpl dictDataService; + + @Resource + private DictDataMapper dictDataMapper; + @MockBean + private DictTypeService dictTypeService; + + @Test + public void testGetDictDataList() { + // mock 数据 + DictDataDO dictDataDO01 = randomDictDataDO().setDictType("yunai").setSort(2) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + dictDataMapper.insert(dictDataDO01); + DictDataDO dictDataDO02 = randomDictDataDO().setDictType("yunai").setSort(1) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + dictDataMapper.insert(dictDataDO02); + DictDataDO dictDataDO03 = randomDictDataDO().setDictType("yunai").setSort(3) + .setStatus(CommonStatusEnum.DISABLE.getStatus()); + dictDataMapper.insert(dictDataDO03); + DictDataDO dictDataDO04 = randomDictDataDO().setDictType("yunai2").setSort(3) + .setStatus(CommonStatusEnum.DISABLE.getStatus()); + dictDataMapper.insert(dictDataDO04); + // 准备参数 + Integer status = CommonStatusEnum.ENABLE.getStatus(); + String dictType = "yunai"; + + // 调用 + List dictDataDOList = dictDataService.getDictDataList(status, dictType); + // 断言 + assertEquals(2, dictDataDOList.size()); + assertPojoEquals(dictDataDO02, dictDataDOList.get(0)); + assertPojoEquals(dictDataDO01, dictDataDOList.get(1)); + } + + @Test + public void testGetDictDataPage() { + // mock 数据 + DictDataDO dbDictData = randomPojo(DictDataDO.class, o -> { // 等会查询到 + o.setLabel("芋艿"); + o.setDictType("yunai"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + dictDataMapper.insert(dbDictData); + // 测试 label 不匹配 + dictDataMapper.insert(cloneIgnoreId(dbDictData, o -> o.setLabel("艿"))); + // 测试 dictType 不匹配 + dictDataMapper.insert(cloneIgnoreId(dbDictData, o -> o.setDictType("nai"))); + // 测试 status 不匹配 + dictDataMapper.insert(cloneIgnoreId(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + DictDataPageReqVO reqVO = new DictDataPageReqVO(); + reqVO.setLabel("芋"); + reqVO.setDictType("yunai"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + PageResult pageResult = dictDataService.getDictDataPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDictData, pageResult.getList().get(0)); + } + + @Test + public void testGetDictData() { + // mock 数据 + DictDataDO dbDictData = randomDictDataDO(); + dictDataMapper.insert(dbDictData); + // 准备参数 + Long id = dbDictData.getId(); + + // 调用 + DictDataDO dictData = dictDataService.getDictData(id); + // 断言 + assertPojoEquals(dbDictData, dictData); + } + + @Test + public void testCreateDictData_success() { + // 准备参数 + DictDataSaveReqVO reqVO = randomPojo(DictDataSaveReqVO.class, + o -> o.setStatus(randomCommonStatus())) + .setId(null); // 防止 id 被赋值 + // mock 方法 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType())); + + // 调用 + Long dictDataId = dictDataService.createDictData(reqVO); + // 断言 + assertNotNull(dictDataId); + // 校验记录的属性是否正确 + DictDataDO dictData = dictDataMapper.selectById(dictDataId); + assertPojoEquals(reqVO, dictData, "id"); + } + + @Test + public void testUpdateDictData_success() { + // mock 数据 + DictDataDO dbDictData = randomDictDataDO(); + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DictDataSaveReqVO reqVO = randomPojo(DictDataSaveReqVO.class, o -> { + o.setId(dbDictData.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + // mock 方法,字典类型 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType())); + + // 调用 + dictDataService.updateDictData(reqVO); + // 校验是否更新正确 + DictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, dictData); + } + + @Test + public void testDeleteDictData_success() { + // mock 数据 + DictDataDO dbDictData = randomDictDataDO(); + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDictData.getId(); + + // 调用 + dictDataService.deleteDictData(id); + // 校验数据不存在了 + assertNull(dictDataMapper.selectById(id)); + } + + @Test + public void testValidateDictDataExists_success() { + // mock 数据 + DictDataDO dbDictData = randomDictDataDO(); + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据 + + // 调用成功 + dictDataService.validateDictDataExists(dbDictData.getId()); + } + + @Test + public void testValidateDictDataExists_notExists() { + assertServiceException(() -> dictDataService.validateDictDataExists(randomLongId()), DICT_DATA_NOT_EXISTS); + } + + @Test + public void testValidateDictTypeExists_success() { + // mock 方法,数据类型被禁用 + String type = randomString(); + when(dictTypeService.getDictType(eq(type))).thenReturn(randomDictTypeDO(type)); + + // 调用, 成功 + dictDataService.validateDictTypeExists(type); + } + + @Test + public void testValidateDictTypeExists_notExists() { + assertServiceException(() -> dictDataService.validateDictTypeExists(randomString()), DICT_TYPE_NOT_EXISTS); + } + + @Test + public void testValidateDictTypeExists_notEnable() { + // mock 方法,数据类型被禁用 + String dictType = randomString(); + when(dictTypeService.getDictType(eq(dictType))).thenReturn( + randomPojo(DictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.validateDictTypeExists(dictType), DICT_TYPE_NOT_ENABLE); + } + + @Test + public void testValidateDictDataValueUnique_success() { + // 调用,成功 + dictDataService.validateDictDataValueUnique(randomLongId(), randomString(), randomString()); + } + + @Test + public void testValidateDictDataValueUnique_valueDuplicateForCreate() { + // 准备参数 + String dictType = randomString(); + String value = randomString(); + // mock 数据 + dictDataMapper.insert(randomDictDataDO(o -> { + o.setDictType(dictType); + o.setValue(value); + })); + + // 调用,校验异常 + assertServiceException(() -> dictDataService.validateDictDataValueUnique(null, dictType, value), + DICT_DATA_VALUE_DUPLICATE); + } + + @Test + public void testValidateDictDataValueUnique_valueDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String dictType = randomString(); + String value = randomString(); + // mock 数据 + dictDataMapper.insert(randomDictDataDO(o -> { + o.setDictType(dictType); + o.setValue(value); + })); + + // 调用,校验异常 + assertServiceException(() -> dictDataService.validateDictDataValueUnique(id, dictType, value), + DICT_DATA_VALUE_DUPLICATE); + } + + @Test + public void testGetDictDataCountByDictType() { + // mock 数据 + dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("yunai"))); + dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("tudou"))); + dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("yunai"))); + // 准备参数 + String dictType = "yunai"; + + // 调用 + long count = dictDataService.getDictDataCountByDictType(dictType); + // 校验 + assertEquals(2L, count); + } + + @Test + public void testValidateDictDataList_success() { + // mock 数据 + DictDataDO dictDataDO = randomDictDataDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); + dictDataMapper.insert(dictDataDO); + // 准备参数 + String dictType = dictDataDO.getDictType(); + List values = singletonList(dictDataDO.getValue()); + + // 调用,无需断言 + dictDataService.validateDictDataList(dictType, values); + } + + @Test + public void testValidateDictDataList_notFound() { + // 准备参数 + String dictType = randomString(); + List values = singletonList(randomString()); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.validateDictDataList(dictType, values), DICT_DATA_NOT_EXISTS); + } + + @Test + public void testValidateDictDataList_notEnable() { + // mock 数据 + DictDataDO dictDataDO = randomDictDataDO().setStatus(CommonStatusEnum.DISABLE.getStatus()); + dictDataMapper.insert(dictDataDO); + // 准备参数 + String dictType = dictDataDO.getDictType(); + List values = singletonList(dictDataDO.getValue()); + + // 调用, 并断言异常 + assertServiceException(() -> dictDataService.validateDictDataList(dictType, values), + DICT_DATA_NOT_ENABLE, dictDataDO.getLabel()); + } + + @Test + public void testGetDictData_dictType() { + // mock 数据 + DictDataDO dictDataDO = randomDictDataDO().setDictType("yunai").setValue("1"); + dictDataMapper.insert(dictDataDO); + DictDataDO dictDataDO02 = randomDictDataDO().setDictType("yunai").setValue("2"); + dictDataMapper.insert(dictDataDO02); + // 准备参数 + String dictType = "yunai"; + String value = "1"; + + // 调用 + DictDataDO dbDictData = dictDataService.getDictData(dictType, value); + // 断言 + assertEquals(dictDataDO, dbDictData); + } + + @Test + public void testParseDictData() { + // mock 数据 + DictDataDO dictDataDO = randomDictDataDO().setDictType("yunai").setLabel("1"); + dictDataMapper.insert(dictDataDO); + DictDataDO dictDataDO02 = randomDictDataDO().setDictType("yunai").setLabel("2"); + dictDataMapper.insert(dictDataDO02); + // 准备参数 + String dictType = "yunai"; + String label = "1"; + + // 调用 + DictDataDO dbDictData = dictDataService.parseDictData(dictType, label); + // 断言 + assertEquals(dictDataDO, dbDictData); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static DictDataDO randomDictDataDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomCommonStatus()); // 保证 status 的范围 + }; + return randomPojo(DictDataDO.class, ArrayUtils.append(consumer, consumers)); + } + + /** + * 生成一个有效的字典类型 + * + * @param type 字典类型 + * @return DictTypeDO 对象 + */ + private static DictTypeDO randomDictTypeDO(String type) { + return randomPojo(DictTypeDO.class, o -> { + o.setType(type); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 是开启 + }); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImplTest.java new file mode 100644 index 0000000..82b4b2f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImplTest.java @@ -0,0 +1,271 @@ +package cn.iocoder.yudao.module.system.service.dict; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.dict.DictTypeMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@Import(DictTypeServiceImpl.class) +public class DictTypeServiceImplTest extends BaseDbUnitTest { + + @Resource + private DictTypeServiceImpl dictTypeService; + + @Resource + private DictTypeMapper dictTypeMapper; + @MockBean + private DictDataService dictDataService; + + @Test + public void testGetDictTypePage() { + // mock 数据 + DictTypeDO dbDictType = randomPojo(DictTypeDO.class, o -> { // 等会查询到 + o.setName("yunai"); + o.setType("芋艿"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2021, 1, 15)); + }); + dictTypeMapper.insert(dbDictType); + // 测试 name 不匹配 + dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setName("tudou"))); + // 测试 type 不匹配 + dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setType("土豆"))); + // 测试 status 不匹配 + dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1)))); + // 准备参数 + DictTypePageReqVO reqVO = new DictTypePageReqVO(); + reqVO.setName("nai"); + reqVO.setType("艿"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2021, 1, 10, 2021, 1, 20)); + + // 调用 + PageResult pageResult = dictTypeService.getDictTypePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDictType, pageResult.getList().get(0)); + } + + @Test + public void testGetDictType_id() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType); + // 准备参数 + Long id = dbDictType.getId(); + + // 调用 + DictTypeDO dictType = dictTypeService.getDictType(id); + // 断言 + assertNotNull(dictType); + assertPojoEquals(dbDictType, dictType); + } + + @Test + public void testGetDictType_type() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType); + // 准备参数 + String type = dbDictType.getType(); + + // 调用 + DictTypeDO dictType = dictTypeService.getDictType(type); + // 断言 + assertNotNull(dictType); + assertPojoEquals(dbDictType, dictType); + } + + @Test + public void testCreateDictType_success() { + // 准备参数 + DictTypeSaveReqVO reqVO = randomPojo(DictTypeSaveReqVO.class, + o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus())) + .setId(null); // 避免 id 被赋值 + + // 调用 + Long dictTypeId = dictTypeService.createDictType(reqVO); + // 断言 + assertNotNull(dictTypeId); + // 校验记录的属性是否正确 + DictTypeDO dictType = dictTypeMapper.selectById(dictTypeId); + assertPojoEquals(reqVO, dictType, "id"); + } + + @Test + public void testUpdateDictType_success() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DictTypeSaveReqVO reqVO = randomPojo(DictTypeSaveReqVO.class, o -> { + o.setId(dbDictType.getId()); // 设置更新的 ID + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); + }); + + // 调用 + dictTypeService.updateDictType(reqVO); + // 校验是否更新正确 + DictTypeDO dictType = dictTypeMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, dictType); + } + + @Test + public void testDeleteDictType_success() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDictType.getId(); + + // 调用 + dictTypeService.deleteDictType(id); + // 校验数据不存在了 + assertNull(dictTypeMapper.selectById(id)); + } + + @Test + public void testDeleteDictType_hasChildren() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDictType.getId(); + // mock 方法 + when(dictDataService.getDictDataCountByDictType(eq(dbDictType.getType()))).thenReturn(1L); + + // 调用, 并断言异常 + assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN); + } + + @Test + public void testGetDictTypeList() { + // 准备参数 + DictTypeDO dictTypeDO01 = randomDictTypeDO(); + dictTypeMapper.insert(dictTypeDO01); + DictTypeDO dictTypeDO02 = randomDictTypeDO(); + dictTypeMapper.insert(dictTypeDO02); + // mock 方法 + + // 调用 + List dictTypeDOList = dictTypeService.getDictTypeList(); + // 断言 + assertEquals(2, dictTypeDOList.size()); + assertPojoEquals(dictTypeDO01, dictTypeDOList.get(0)); + assertPojoEquals(dictTypeDO02, dictTypeDOList.get(1)); + } + + @Test + public void testValidateDictDataExists_success() { + // mock 数据 + DictTypeDO dbDictType = randomDictTypeDO(); + dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 + + // 调用成功 + dictTypeService.validateDictTypeExists(dbDictType.getId()); + } + + @Test + public void testValidateDictDataExists_notExists() { + assertServiceException(() -> dictTypeService.validateDictTypeExists(randomLongId()), DICT_TYPE_NOT_EXISTS); + } + + @Test + public void testValidateDictTypeUnique_success() { + // 调用,成功 + dictTypeService.validateDictTypeUnique(randomLongId(), randomString()); + } + + @Test + public void testValidateDictTypeUnique_valueDuplicateForCreate() { + // 准备参数 + String type = randomString(); + // mock 数据 + dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type))); + + // 调用,校验异常 + assertServiceException(() -> dictTypeService.validateDictTypeUnique(null, type), + DICT_TYPE_TYPE_DUPLICATE); + } + + @Test + public void testValidateDictTypeUnique_valueDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String type = randomString(); + // mock 数据 + dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type))); + + // 调用,校验异常 + assertServiceException(() -> dictTypeService.validateDictTypeUnique(id, type), + DICT_TYPE_TYPE_DUPLICATE); + } + + @Test + public void testValidateDictTypNameUnique_success() { + // 调用,成功 + dictTypeService.validateDictTypeNameUnique(randomLongId(), randomString()); + } + + @Test + public void testValidateDictTypeNameUnique_nameDuplicateForCreate() { + // 准备参数 + String name = randomString(); + // mock 数据 + dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name))); + + // 调用,校验异常 + assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(null, name), + DICT_TYPE_NAME_DUPLICATE); + } + + @Test + public void testValidateDictTypeNameUnique_nameDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String name = randomString(); + // mock 数据 + dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name))); + + // 调用,校验异常 + assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(id, name), + DICT_TYPE_NAME_DUPLICATE); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static DictTypeDO randomDictTypeDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + }; + return randomPojo(DictTypeDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java new file mode 100644 index 0000000..530c274 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; +import cn.iocoder.yudao.module.system.dal.mysql.logger.LoginLogMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum.CAPTCHA_CODE_ERROR; +import static cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum.SUCCESS; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Import(LoginLogServiceImpl.class) +public class LoginLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private LoginLogServiceImpl loginLogService; + + @Resource + private LoginLogMapper loginLogMapper; + + @Test + public void testGetLoginLogPage() { + // mock 数据 + LoginLogDO loginLogDO = randomPojo(LoginLogDO.class, o -> { + o.setUserIp("192.168.199.16"); + o.setUsername("wang"); + o.setResult(SUCCESS.getResult()); + o.setCreateTime(buildTime(2021, 3, 6)); + }); + loginLogMapper.insert(loginLogDO); + // 测试 status 不匹配 + loginLogMapper.insert(cloneIgnoreId(loginLogDO, o -> o.setResult(CAPTCHA_CODE_ERROR.getResult()))); + // 测试 ip 不匹配 + loginLogMapper.insert(cloneIgnoreId(loginLogDO, o -> o.setUserIp("192.168.128.18"))); + // 测试 username 不匹配 + loginLogMapper.insert(cloneIgnoreId(loginLogDO, o -> o.setUsername("yunai"))); + // 测试 createTime 不匹配 + loginLogMapper.insert(cloneIgnoreId(loginLogDO, o -> o.setCreateTime(buildTime(2021, 2, 6)))); + // 构造调用参数 + LoginLogPageReqVO reqVO = new LoginLogPageReqVO(); + reqVO.setUsername("wang"); + reqVO.setUserIp("192.168.199"); + reqVO.setStatus(true); + reqVO.setCreateTime(buildBetweenTime(2021, 3, 5, 2021, 3, 7)); + + // 调用 + PageResult pageResult = loginLogService.getLoginLogPage(reqVO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(loginLogDO, pageResult.getList().get(0)); + } + + @Test + public void testCreateLoginLog() { + LoginLogCreateReqDTO reqDTO = randomPojo(LoginLogCreateReqDTO.class); + + // 调用 + loginLogService.createLoginLog(reqDTO); + // 断言 + LoginLogDO loginLogDO = loginLogMapper.selectOne(null); + assertPojoEquals(reqDTO, loginLogDO); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java new file mode 100644 index 0000000..f41d39c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.system.service.logger; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO; +import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; +import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Import({OperateLogServiceImpl.class}) +public class OperateLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private OperateLogService operateLogServiceImpl; + + @Resource + private OperateLogMapper operateLogMapper; + + @Test + public void testCreateOperateLog() { + OperateLogCreateReqDTO reqVO = RandomUtils.randomPojo(OperateLogCreateReqDTO.class); + + // 调研 + operateLogServiceImpl.createOperateLog(reqVO); + // 断言 + OperateLogDO operateLogDO = operateLogMapper.selectOne(null); + assertPojoEquals(reqVO, operateLogDO); + } + + @Test + public void testGetOperateLogPage_vo() { + // 构造操作日志 + OperateLogDO operateLogDO = RandomUtils.randomPojo(OperateLogDO.class, o -> { + o.setUserId(2048L); + o.setBizId(999L); + o.setType("订单"); + o.setSubType("创建订单"); + o.setAction("修改编号为 1 的用户信息"); + o.setCreateTime(buildTime(2021, 3, 6)); + }); + operateLogMapper.insert(operateLogDO); + // 测试 userId 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setUserId(1024L))); + // 测试 bizId 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setBizId(888L))); + // 测试 type 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setType("退款"))); + // 测试 subType 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setSubType("创建退款"))); + // 测试 action 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setAction("修改编号为 1 退款信息"))); + // 测试 createTime 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setCreateTime(buildTime(2021, 2, 6)))); + + // 构造调用参数 + OperateLogPageReqVO reqVO = new OperateLogPageReqVO(); + reqVO.setUserId(2048L); + reqVO.setBizId(999L); + reqVO.setType("订"); + reqVO.setSubType("订单"); + reqVO.setAction("用户信息"); + reqVO.setCreateTime(buildBetweenTime(2021, 3, 5, 2021, 3, 7)); + + // 调用 + PageResult pageResult = operateLogServiceImpl.getOperateLogPage(reqVO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(operateLogDO, pageResult.getList().get(0)); + } + + @Test + public void testGetOperateLogPage_dto() { + // 构造操作日志 + OperateLogDO operateLogDO = RandomUtils.randomPojo(OperateLogDO.class, o -> { + o.setUserId(2048L); + o.setBizId(999L); + o.setType("订单"); + }); + operateLogMapper.insert(operateLogDO); + // 测试 userId 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setUserId(1024L))); + // 测试 bizId 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setBizId(888L))); + // 测试 type 不匹配 + operateLogMapper.insert(cloneIgnoreId(operateLogDO, o -> o.setType("退款"))); + + // 构造调用参数 + OperateLogPageReqDTO reqDTO = new OperateLogPageReqDTO(); + reqDTO.setUserId(2048L); + reqDTO.setBizId(999L); + reqDTO.setType("订单"); + + // 调用 + PageResult pageResult = operateLogServiceImpl.getOperateLogPage(reqDTO); + // 断言,只查到了一条符合条件的 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(operateLogDO, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java new file mode 100644 index 0000000..6e1bf0d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java @@ -0,0 +1,179 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link MailAccountServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(MailAccountServiceImpl.class) +public class MailAccountServiceImplTest extends BaseDbUnitTest { + + @Resource + private MailAccountServiceImpl mailAccountService; + + @Resource + private MailAccountMapper mailAccountMapper; + + @MockBean + private MailTemplateService mailTemplateService; + + @Test + public void testCreateMailAccount_success() { + // 准备参数 + MailAccountSaveReqVO reqVO = randomPojo(MailAccountSaveReqVO.class, o -> o.setMail(randomEmail())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long mailAccountId = mailAccountService.createMailAccount(reqVO); + // 断言 + assertNotNull(mailAccountId); + // 校验记录的属性是否正确 + MailAccountDO mailAccount = mailAccountMapper.selectById(mailAccountId); + assertPojoEquals(reqVO, mailAccount, "id"); + } + + @Test + public void testUpdateMailAccount_success() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MailAccountSaveReqVO reqVO = randomPojo(MailAccountSaveReqVO.class, o -> { + o.setId(dbMailAccount.getId()); // 设置更新的 ID + o.setMail(randomEmail()); + }); + + // 调用 + mailAccountService.updateMailAccount(reqVO); + // 校验是否更新正确 + MailAccountDO mailAccount = mailAccountMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, mailAccount); + } + + @Test + public void testUpdateMailAccount_notExists() { + // 准备参数 + MailAccountSaveReqVO reqVO = randomPojo(MailAccountSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> mailAccountService.updateMailAccount(reqVO), MAIL_ACCOUNT_NOT_EXISTS); + } + + @Test + public void testDeleteMailAccount_success() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbMailAccount.getId(); + // mock 方法(无关联模版) + when(mailTemplateService.getMailTemplateCountByAccountId(eq(id))).thenReturn(0L); + + // 调用 + mailAccountService.deleteMailAccount(id); + // 校验数据不存在了 + assertNull(mailAccountMapper.selectById(id)); + } + + @Test + public void testGetMailAccountFromCache() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbMailAccount.getId(); + + // 调用 + MailAccountDO mailAccount = mailAccountService.getMailAccountFromCache(id); + // 断言 + assertPojoEquals(dbMailAccount, mailAccount); + } + + @Test + public void testDeleteMailAccount_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> mailAccountService.deleteMailAccount(id), MAIL_ACCOUNT_NOT_EXISTS); + } + + @Test + public void testGetMailAccountPage() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class, o -> { // 等会查询到 + o.setMail("768@qq.com"); + o.setUsername("yunai"); + }); + mailAccountMapper.insert(dbMailAccount); + // 测试 mail 不匹配 + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setMail("788@qq.com"))); + // 测试 username 不匹配 + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setUsername("tudou"))); + // 准备参数 + MailAccountPageReqVO reqVO = new MailAccountPageReqVO(); + reqVO.setMail("768"); + reqVO.setUsername("yu"); + + // 调用 + PageResult pageResult = mailAccountService.getMailAccountPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbMailAccount, pageResult.getList().get(0)); + } + + @Test + public void testGetMailAccount() { + // mock 数据 + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbMailAccount.getId(); + + // 调用 + MailAccountDO mailAccount = mailAccountService.getMailAccount(id); + // 断言 + assertPojoEquals(dbMailAccount, mailAccount); + } + + @Test + public void testGetMailAccountList() { + // mock 数据 + MailAccountDO dbMailAccount01 = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount01); + MailAccountDO dbMailAccount02 = randomPojo(MailAccountDO.class); + mailAccountMapper.insert(dbMailAccount02); + // 准备参数 + + // 调用 + List list = mailAccountService.getMailAccountList(); + // 断言 + assertEquals(2, list.size()); + assertPojoEquals(dbMailAccount01, list.get(0)); + assertPojoEquals(dbMailAccount02, list.get(1)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java new file mode 100644 index 0000000..152c6d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper; +import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link MailLogServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(MailLogServiceImpl.class) +public class MailLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private MailLogServiceImpl mailLogService; + + @Resource + private MailLogMapper mailLogMapper; + + @Test + public void testCreateMailLog() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String toMail = randomEmail(); + MailAccountDO account = randomPojo(MailAccountDO.class); + MailTemplateDO template = randomPojo(MailTemplateDO.class); + String templateContent = randomString(); + Map templateParams = randomTemplateParams(); + Boolean isSend = true; + // mock 方法 + + // 调用 + Long logId = mailLogService.createMailLog(userId, userType, toMail, account, template, templateContent, templateParams, isSend); + // 断言 + MailLogDO log = mailLogMapper.selectById(logId); + assertNotNull(log); + assertEquals(MailSendStatusEnum.INIT.getStatus(), log.getSendStatus()); + assertEquals(userId, log.getUserId()); + assertEquals(userType, log.getUserType()); + assertEquals(toMail, log.getToMail()); + assertEquals(account.getId(), log.getAccountId()); + assertEquals(account.getMail(), log.getFromMail()); + assertEquals(template.getId(), log.getTemplateId()); + assertEquals(template.getCode(), log.getTemplateCode()); + assertEquals(template.getNickname(), log.getTemplateNickname()); + assertEquals(template.getTitle(), log.getTemplateTitle()); + assertEquals(templateContent, log.getTemplateContent()); + assertEquals(templateParams, log.getTemplateParams()); + } + + @Test + public void testUpdateMailSendResult_success() { + // mock 数据 + MailLogDO log = randomPojo(MailLogDO.class, o -> { + o.setSendStatus(MailSendStatusEnum.INIT.getStatus()); + o.setSendTime(null).setSendMessageId(null).setSendException(null) + .setTemplateParams(randomTemplateParams()); + }); + mailLogMapper.insert(log); + // 准备参数 + Long logId = log.getId(); + String messageId = randomString(); + + // 调用 + mailLogService.updateMailSendResult(logId, messageId, null); + // 断言 + MailLogDO dbLog = mailLogMapper.selectById(logId); + assertEquals(MailSendStatusEnum.SUCCESS.getStatus(), dbLog.getSendStatus()); + assertNotNull(dbLog.getSendTime()); + assertEquals(messageId, dbLog.getSendMessageId()); + assertNull(dbLog.getSendException()); + } + + @Test + public void testUpdateMailSendResult_exception() { + // mock 数据 + MailLogDO log = randomPojo(MailLogDO.class, o -> { + o.setSendStatus(MailSendStatusEnum.INIT.getStatus()); + o.setSendTime(null).setSendMessageId(null).setSendException(null) + .setTemplateParams(randomTemplateParams()); + }); + mailLogMapper.insert(log); + // 准备参数 + Long logId = log.getId(); + Exception exception = new NullPointerException("测试异常"); + + // 调用 + mailLogService.updateMailSendResult(logId, null, exception); + // 断言 + MailLogDO dbLog = mailLogMapper.selectById(logId); + assertEquals(MailSendStatusEnum.FAILURE.getStatus(), dbLog.getSendStatus()); + assertNotNull(dbLog.getSendTime()); + assertNull(dbLog.getSendMessageId()); + assertEquals("NullPointerException: 测试异常", dbLog.getSendException()); + } + + @Test + public void testGetMailLog() { + // mock 数据 + MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> o.setTemplateParams(randomTemplateParams())); + mailLogMapper.insert(dbMailLog); + // 准备参数 + Long id = dbMailLog.getId(); + + // 调用 + MailLogDO mailLog = mailLogService.getMailLog(id); + // 断言 + assertPojoEquals(dbMailLog, mailLog); + } + + @Test + public void testGetMailLogPage() { + // mock 数据 + MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setToMail("768@qq.com"); + o.setAccountId(10L); + o.setTemplateId(100L); + o.setSendStatus(MailSendStatusEnum.INIT.getStatus()); + o.setSendTime(buildTime(2023, 2, 10)); + o.setTemplateParams(randomTemplateParams()); + }); + mailLogMapper.insert(dbMailLog); + // 测试 userId 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 toMail 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMail("788@.qq.com"))); + // 测试 accountId 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setAccountId(11L))); + // 测试 templateId 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setTemplateId(101L))); + // 测试 sendStatus 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setSendStatus(MailSendStatusEnum.SUCCESS.getStatus()))); + // 测试 sendTime 不匹配 + mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setSendTime(buildTime(2023, 3, 10)))); + // 准备参数 + MailLogPageReqVO reqVO = new MailLogPageReqVO(); + reqVO.setUserId(1L); + reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); + reqVO.setToMail("768"); + reqVO.setAccountId(10L); + reqVO.setTemplateId(100L); + reqVO.setSendStatus(MailSendStatusEnum.INIT.getStatus()); + reqVO.setSendTime((buildBetweenTime(2023, 2, 1, 2023, 2, 15))); + + // 调用 + PageResult pageResult = mailLogService.getMailLogPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbMailLog, pageResult.getList().get(0)); + } + + private static Map randomTemplateParams() { + return MapUtil.builder().put(randomString(), randomString()) + .put(randomString(), randomString()).build(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java new file mode 100644 index 0000000..b873152 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java @@ -0,0 +1,329 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.extra.mail.*; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; + +import java.util.HashMap; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class MailSendServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private MailSendServiceImpl mailSendService; + + @Mock + private AdminUserService adminUserService; + @Mock + private MemberService memberService; + @Mock + private MailAccountService mailAccountService; + @Mock + private MailTemplateService mailTemplateService; + @Mock + private MailLogService mailLogService; + @Mock + private MailProducer mailProducer; + + /** + * 用于快速测试你的邮箱账号是否正常 + */ + @Test + @Disabled + public void testDemo() { + MailAccount mailAccount = new MailAccount() +// .setFrom("奥特曼 ") + .setFrom("ydym_test@163.com") // 邮箱地址 + .setHost("smtp.163.com").setPort(465).setSslEnable(true) // SMTP 服务器 + .setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE"); // 登录账号密码 + String messageId = MailUtil.send(mailAccount, "7685413@qq.com", "主题", "内容", false); + System.out.println("发送结果:" + messageId); + } + + @Test + public void testSendSingleMailToAdmin() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = RandomUtils.randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock adminUserService 的方法 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300")); + when(adminUserService.getUser(eq(userId))).thenReturn(user); + + // mock MailTemplateService 的方法 + MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String title = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams))) + .thenReturn(title); + String content = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock MailAccountService 的方法 + MailAccountDO account = randomPojo(MailAccountDO.class); + when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); + // mock MailLogService 的方法 + Long mailLogId = randomLongId(); + when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(user.getEmail()), + eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); + + // 调用 + Long resultMailLogId = mailSendService.sendSingleMailToAdmin(null, userId, templateCode, templateParams); + // 断言 + assertEquals(mailLogId, resultMailLogId); + // 断言调用 + verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(user.getEmail()), + eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); + } + + @Test + public void testSendSingleMailToMember() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = RandomUtils.randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock memberService 的方法 + String mail = randomEmail(); + when(memberService.getMemberUserEmail(eq(userId))).thenReturn(mail); + + // mock MailTemplateService 的方法 + MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String title = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams))) + .thenReturn(title); + String content = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock MailAccountService 的方法 + MailAccountDO account = randomPojo(MailAccountDO.class); + when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); + // mock MailLogService 的方法 + Long mailLogId = randomLongId(); + when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(mail), + eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); + + // 调用 + Long resultMailLogId = mailSendService.sendSingleMailToMember(null, userId, templateCode, templateParams); + // 断言 + assertEquals(mailLogId, resultMailLogId); + // 断言调用 + verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail), + eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); + } + + /** + * 发送成功,当短信模板开启时 + */ + @Test + public void testSendSingleMail_successWhenMailTemplateEnable() { + // 准备参数 + String mail = randomEmail(); + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = RandomUtils.randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock MailTemplateService 的方法 + MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String title = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams))) + .thenReturn(title); + String content = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock MailAccountService 的方法 + MailAccountDO account = randomPojo(MailAccountDO.class); + when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); + // mock MailLogService 的方法 + Long mailLogId = randomLongId(); + when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail), + eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); + + // 调用 + Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams); + // 断言 + assertEquals(mailLogId, resultMailLogId); + // 断言调用 + verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail), + eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); + } + + /** + * 发送成功,当短信模板关闭时 + */ + @Test + public void testSendSingleMail_successWhenSmsTemplateDisable() { + // 准备参数 + String mail = randomEmail(); + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = RandomUtils.randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock MailTemplateService 的方法 + MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String title = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams))) + .thenReturn(title); + String content = RandomUtils.randomString(); + when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock MailAccountService 的方法 + MailAccountDO account = randomPojo(MailAccountDO.class); + when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account); + // mock MailLogService 的方法 + Long mailLogId = randomLongId(); + when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail), + eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId); + + // 调用 + Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams); + // 断言 + assertEquals(mailLogId, resultMailLogId); + // 断言调用 + verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), anyString(), + anyLong(), anyString(), anyString(), anyString()); + } + + @Test + public void testValidateMailTemplateValid_notExists() { + // 准备参数 + String templateCode = RandomUtils.randomString(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> mailSendService.validateMailTemplate(templateCode), + MAIL_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testValidateTemplateParams_paramMiss() { + // 准备参数 + MailTemplateDO template = randomPojo(MailTemplateDO.class, + o -> o.setParams(Lists.newArrayList("code"))); + Map templateParams = new HashMap<>(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> mailSendService.validateTemplateParams(template, templateParams), + MAIL_SEND_TEMPLATE_PARAM_MISS, "code"); + } + + @Test + public void testValidateMail_notExists() { + // 准备参数 + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> mailSendService.validateMail(null), + MAIL_SEND_MAIL_NOT_EXISTS); + } + + @Test + public void testDoSendMail_success() { + try (final MockedStatic mailUtilMock = mockStatic(MailUtil.class)) { + // 准备参数 + MailSendMessage message = randomPojo(MailSendMessage.class, o -> o.setNickname("芋艿")); + // mock 方法(获得邮箱账号) + MailAccountDO account = randomPojo(MailAccountDO.class, o -> o.setMail("7685@qq.com")); + when(mailAccountService.getMailAccountFromCache(eq(message.getAccountId()))) + .thenReturn(account); + + // mock 方法(发送邮件) + String messageId = randomString(); + mailUtilMock.when(() -> MailUtil.send( + argThat(mailAccount -> { + assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); + assertTrue(mailAccount.isAuth()); + assertEquals(account.getUsername(), mailAccount.getUser()); + assertEquals(account.getPassword(), mailAccount.getPass()); + assertEquals(account.getHost(), mailAccount.getHost()); + assertEquals(account.getPort(), mailAccount.getPort()); + assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); + return true; + }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))) + .thenReturn(messageId); + + // 调用 + mailSendService.doSendMail(message); + // 断言 + verify(mailLogService).updateMailSendResult(eq(message.getLogId()), eq(messageId), isNull()); + } + } + + @Test + public void testDoSendMail_exception() { + try (MockedStatic mailUtilMock = mockStatic(MailUtil.class)) { + // 准备参数 + MailSendMessage message = randomPojo(MailSendMessage.class, o -> o.setNickname("芋艿")); + // mock 方法(获得邮箱账号) + MailAccountDO account = randomPojo(MailAccountDO.class, o -> o.setMail("7685@qq.com")); + when(mailAccountService.getMailAccountFromCache(eq(message.getAccountId()))) + .thenReturn(account); + + // mock 方法(发送邮件) + Exception e = new NullPointerException("啦啦啦"); + mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> { + assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); + assertTrue(mailAccount.isAuth()); + assertEquals(account.getUsername(), mailAccount.getUser()); + assertEquals(account.getPassword(), mailAccount.getPass()); + assertEquals(account.getHost(), mailAccount.getHost()); + assertEquals(account.getPort(), mailAccount.getPort()); + assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); + return true; + }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e); + + // 调用 + mailSendService.doSendMail(message); + // 断言 + verify(mailLogService).updateMailSendResult(eq(message.getLogId()), isNull(), same(e)); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java new file mode 100644 index 0000000..7f76570 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java @@ -0,0 +1,215 @@ +package cn.iocoder.yudao.module.system.service.mail; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link MailTemplateServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(MailTemplateServiceImpl.class) +public class MailTemplateServiceImplTest extends BaseDbUnitTest { + + @Resource + private MailTemplateServiceImpl mailTemplateService; + + @Resource + private MailTemplateMapper mailTemplateMapper; + + @Test + public void testCreateMailTemplate_success() { + // 准备参数 + MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long mailTemplateId = mailTemplateService.createMailTemplate(reqVO); + // 断言 + assertNotNull(mailTemplateId); + // 校验记录的属性是否正确 + MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId); + assertPojoEquals(reqVO, mailTemplate, "id"); + } + + @Test + public void testUpdateMailTemplate_success() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class, o -> { + o.setId(dbMailTemplate.getId()); // 设置更新的 ID + }); + + // 调用 + mailTemplateService.updateMailTemplate(reqVO); + // 校验是否更新正确 + MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, mailTemplate); + } + + @Test + public void testUpdateMailTemplate_notExists() { + // 准备参数 + MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> mailTemplateService.updateMailTemplate(reqVO), MAIL_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteMailTemplate_success() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbMailTemplate.getId(); + + // 调用 + mailTemplateService.deleteMailTemplate(id); + // 校验数据不存在了 + assertNull(mailTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteMailTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> mailTemplateService.deleteMailTemplate(id), MAIL_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testGetMailTemplatePage() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class, o -> { // 等会查询到 + o.setName("源码"); + o.setCode("test_01"); + o.setAccountId(1L); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2023, 2, 3)); + }); + mailTemplateMapper.insert(dbMailTemplate); + // 测试 name 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setName("芋道"))); + // 测试 code 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCode("test_02"))); + // 测试 accountId 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L))); + // 测试 status 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCreateTime(buildTime(2023, 1, 5)))); + // 准备参数 + MailTemplatePageReqVO reqVO = new MailTemplatePageReqVO(); + reqVO.setName("源"); + reqVO.setCode("est_01"); + reqVO.setAccountId(1L); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 5)); + + // 调用 + PageResult pageResult = mailTemplateService.getMailTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbMailTemplate, pageResult.getList().get(0)); + } + + @Test + public void testGetMailTemplateList() { + // mock 数据 + MailTemplateDO dbMailTemplate01 = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate01); + MailTemplateDO dbMailTemplate02 = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate02); + + // 调用 + List list = mailTemplateService.getMailTemplateList(); + // 断言 + assertEquals(2, list.size()); + assertEquals(dbMailTemplate01, list.get(0)); + assertEquals(dbMailTemplate02, list.get(1)); + } + + @Test + public void testGetMailTemplate() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate); + // 准备参数 + Long id = dbMailTemplate.getId(); + + // 调用 + MailTemplateDO mailTemplate = mailTemplateService.getMailTemplate(id); + // 断言 + assertPojoEquals(dbMailTemplate, mailTemplate); + } + + @Test + public void testGetMailTemplateByCodeFromCache() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate); + // 准备参数 + String code = dbMailTemplate.getCode(); + + // 调用 + MailTemplateDO mailTemplate = mailTemplateService.getMailTemplateByCodeFromCache(code); + // 断言 + assertPojoEquals(dbMailTemplate, mailTemplate); + } + + @Test + public void testFormatMailTemplateContent() { + // 准备参数 + Map params = new HashMap<>(); + params.put("name", "小红"); + params.put("what", "饭"); + + // 调用,并断言 + assertEquals("小红,你好,饭吃了吗?", + mailTemplateService.formatMailTemplateContent("{name},你好,{what}吃了吗?", params)); + } + + @Test + public void testCountByAccountId() { + // mock 数据 + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); + mailTemplateMapper.insert(dbMailTemplate); + // 测试 accountId 不匹配 + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L))); + // 准备参数 + Long accountId = dbMailTemplate.getAccountId(); + + // 调用 + long count = mailTemplateService.getMailTemplateCountByAccountId(accountId); + // 断言 + assertEquals(1, count); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImplTest.java new file mode 100644 index 0000000..dfde835 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notice/NoticeServiceImplTest.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.module.system.service.notice; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notice.vo.NoticeSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notice.NoticeDO; +import cn.iocoder.yudao.module.system.dal.mysql.notice.NoticeMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND; +import static org.junit.jupiter.api.Assertions.*; + +@Import(NoticeServiceImpl.class) +class NoticeServiceImplTest extends BaseDbUnitTest { + + @Resource + private NoticeServiceImpl noticeService; + + @Resource + private NoticeMapper noticeMapper; + + @Test + public void testGetNoticePage_success() { + // 插入前置数据 + NoticeDO dbNotice = randomPojo(NoticeDO.class, o -> { + o.setTitle("尼古拉斯赵四来啦!"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + noticeMapper.insert(dbNotice); + // 测试 title 不匹配 + noticeMapper.insert(cloneIgnoreId(dbNotice, o -> o.setTitle("尼古拉斯凯奇也来啦!"))); + // 测试 status 不匹配 + noticeMapper.insert(cloneIgnoreId(dbNotice, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + NoticePageReqVO reqVO = new NoticePageReqVO(); + reqVO.setTitle("尼古拉斯赵四来啦!"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + PageResult pageResult = noticeService.getNoticePage(reqVO); + // 验证查询结果经过筛选 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbNotice, pageResult.getList().get(0)); + } + + @Test + public void testGetNotice_success() { + // 插入前置数据 + NoticeDO dbNotice = randomPojo(NoticeDO.class); + noticeMapper.insert(dbNotice); + + // 查询 + NoticeDO notice = noticeService.getNotice(dbNotice.getId()); + + // 验证插入与读取对象是否一致 + assertNotNull(notice); + assertPojoEquals(dbNotice, notice); + } + + @Test + public void testCreateNotice_success() { + // 准备参数 + NoticeSaveReqVO reqVO = randomPojo(NoticeSaveReqVO.class) + .setId(null); // 避免 id 被赋值 + + // 调用 + Long noticeId = noticeService.createNotice(reqVO); + // 校验插入属性是否正确 + assertNotNull(noticeId); + NoticeDO notice = noticeMapper.selectById(noticeId); + assertPojoEquals(reqVO, notice, "id"); + } + + @Test + public void testUpdateNotice_success() { + // 插入前置数据 + NoticeDO dbNoticeDO = randomPojo(NoticeDO.class); + noticeMapper.insert(dbNoticeDO); + + // 准备更新参数 + NoticeSaveReqVO reqVO = randomPojo(NoticeSaveReqVO.class, o -> o.setId(dbNoticeDO.getId())); + + // 更新 + noticeService.updateNotice(reqVO); + // 检验是否更新成功 + NoticeDO notice = noticeMapper.selectById(reqVO.getId()); + assertPojoEquals(reqVO, notice); + } + + @Test + public void testDeleteNotice_success() { + // 插入前置数据 + NoticeDO dbNotice = randomPojo(NoticeDO.class); + noticeMapper.insert(dbNotice); + + // 删除 + noticeService.deleteNotice(dbNotice.getId()); + + // 检查是否删除成功 + assertNull(noticeMapper.selectById(dbNotice.getId())); + } + + @Test + public void testValidateNoticeExists_success() { + // 插入前置数据 + NoticeDO dbNotice = randomPojo(NoticeDO.class); + noticeMapper.insert(dbNotice); + + // 成功调用 + noticeService.validateNoticeExists(dbNotice.getId()); + } + + @Test + public void testValidateNoticeExists_noExists() { + assertServiceException(() -> + noticeService.validateNoticeExists(randomLongId()), NOTICE_NOT_FOUND); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImplTest.java new file mode 100644 index 0000000..9e2158d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyMessageServiceImplTest.java @@ -0,0 +1,280 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyMessageDO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyMessageMapper; +import com.baomidou.mybatisplus.annotation.DbType; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link NotifyMessageServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(NotifyMessageServiceImpl.class) +public class NotifyMessageServiceImplTest extends BaseDbUnitTest { + + @Resource + private NotifyMessageServiceImpl notifyMessageService; + + @Resource + private NotifyMessageMapper notifyMessageMapper; + + @Test + public void testCreateNotifyMessage_success() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class); + String templateContent = randomString(); + Map templateParams = randomTemplateParams(); + // mock 方法 + + // 调用 + Long messageId = notifyMessageService.createNotifyMessage(userId, userType, + template, templateContent, templateParams); + // 断言 + NotifyMessageDO message = notifyMessageMapper.selectById(messageId); + assertNotNull(message); + assertEquals(userId, message.getUserId()); + assertEquals(userType, message.getUserType()); + assertEquals(template.getId(), message.getTemplateId()); + assertEquals(template.getCode(), message.getTemplateCode()); + assertEquals(template.getType(), message.getTemplateType()); + assertEquals(template.getNickname(), message.getTemplateNickname()); + assertEquals(templateContent, message.getTemplateContent()); + assertEquals(templateParams, message.getTemplateParams()); + assertEquals(false, message.getReadStatus()); + assertNull(message.getReadTime()); + } + + @Test + public void testGetNotifyMessagePage() { + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setTemplateCode("test_01"); + o.setTemplateType(10); + o.setCreateTime(buildTime(2022, 1, 2)); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 templateCode 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateCode("test_11"))); + // 测试 templateType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setTemplateType(20))); + // 测试 createTime 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1)))); + // 准备参数 + NotifyMessagePageReqVO reqVO = new NotifyMessagePageReqVO(); + reqVO.setUserId(1L); + reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); + reqVO.setTemplateCode("est_01"); + reqVO.setTemplateType(10); + reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10)); + + // 调用 + PageResult pageResult = notifyMessageService.getNotifyMessagePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0)); + } + + @Test + public void testGetNotifyMessage() { + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, + o -> o.setTemplateParams(randomTemplateParams())); + notifyMessageMapper.insert(dbNotifyMessage); + // 准备参数 + Long id = dbNotifyMessage.getId(); + + // 调用 + NotifyMessageDO notifyMessage = notifyMessageService.getNotifyMessage(id); + assertPojoEquals(dbNotifyMessage, notifyMessage); + } + + @Test + public void testGetMyNotifyMessagePage() { + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setReadStatus(true); + o.setCreateTime(buildTime(2022, 1, 2)); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 readStatus 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(false))); + // 测试 createTime 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setCreateTime(buildTime(2022, 2, 1)))); + // 准备参数 + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + NotifyMessageMyPageReqVO reqVO = new NotifyMessageMyPageReqVO(); + reqVO.setReadStatus(true); + reqVO.setCreateTime(buildBetweenTime(2022, 1, 1, 2022, 1, 10)); + + // 调用 + PageResult pageResult = notifyMessageService.getMyMyNotifyMessagePage(reqVO, userId, userType); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbNotifyMessage, pageResult.getList().get(0)); + } + + @Test + public void testGetUnreadNotifyMessageList() { + SqlConstants.init(DbType.MYSQL); + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setReadStatus(false); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 readStatus 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true))); + // 准备参数 + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + Integer size = 10; + + // 调用 + List list = notifyMessageService.getUnreadNotifyMessageList(userId, userType, size); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbNotifyMessage, list.get(0)); + } + + @Test + public void testGetUnreadNotifyMessageCount() { + SqlConstants.init(DbType.MYSQL); + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setReadStatus(false); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 readStatus 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true))); + // 准备参数 + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + + // 调用,并断言 + assertEquals(1, notifyMessageService.getUnreadNotifyMessageCount(userId, userType)); + } + + @Test + public void testUpdateNotifyMessageRead() { + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setReadStatus(false); + o.setReadTime(null); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 readStatus 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true))); + // 准备参数 + Collection ids = Arrays.asList(dbNotifyMessage.getId(), dbNotifyMessage.getId() + 1, + dbNotifyMessage.getId() + 2, dbNotifyMessage.getId() + 3); + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + + // 调用 + int updateCount = notifyMessageService.updateNotifyMessageRead(ids, userId, userType); + // 断言 + assertEquals(1, updateCount); + NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId()); + assertTrue(notifyMessage.getReadStatus()); + assertNotNull(notifyMessage.getReadTime()); + } + + @Test + public void testUpdateAllNotifyMessageRead() { + // mock 数据 + NotifyMessageDO dbNotifyMessage = randomPojo(NotifyMessageDO.class, o -> { // 等会查询到 + o.setUserId(1L); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setReadStatus(false); + o.setReadTime(null); + o.setTemplateParams(randomTemplateParams()); + }); + notifyMessageMapper.insert(dbNotifyMessage); + // 测试 userId 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserId(2L))); + // 测试 userType 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 readStatus 不匹配 + notifyMessageMapper.insert(cloneIgnoreId(dbNotifyMessage, o -> o.setReadStatus(true))); + // 准备参数 + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + + // 调用 + int updateCount = notifyMessageService.updateAllNotifyMessageRead(userId, userType); + // 断言 + assertEquals(1, updateCount); + NotifyMessageDO notifyMessage = notifyMessageMapper.selectById(dbNotifyMessage.getId()); + assertTrue(notifyMessage.getReadStatus()); + assertNotNull(notifyMessage.getReadTime()); + } + + private static Map randomTemplateParams() { + return MapUtil.builder().put(randomString(), randomString()) + .put(randomString(), randomString()).build(); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java new file mode 100644 index 0000000..9dbdac4 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.HashMap; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTICE_NOT_FOUND; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_SEND_TEMPLATE_PARAM_MISS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +class NotifySendServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private NotifySendServiceImpl notifySendService; + + @Mock + private NotifyTemplateService notifyTemplateService; + @Mock + private NotifyMessageService notifyMessageService; + + @Test + public void testSendSingleNotifyToAdmin() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock NotifyTemplateService 的方法 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock NotifyMessageService 的方法 + Long messageId = randomLongId(); + when(notifyMessageService.createNotifyMessage(eq(userId), eq(UserTypeEnum.ADMIN.getValue()), + eq(template), eq(content), eq(templateParams))).thenReturn(messageId); + + // 调用 + Long resultMessageId = notifySendService.sendSingleNotifyToAdmin(userId, templateCode, templateParams); + // 断言 + assertEquals(messageId, resultMessageId); + } + + @Test + public void testSendSingleNotifyToMember() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock NotifyTemplateService 的方法 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock NotifyMessageService 的方法 + Long messageId = randomLongId(); + when(notifyMessageService.createNotifyMessage(eq(userId), eq(UserTypeEnum.MEMBER.getValue()), + eq(template), eq(content), eq(templateParams))).thenReturn(messageId); + + // 调用 + Long resultMessageId = notifySendService.sendSingleNotifyToMember(userId, templateCode, templateParams); + // 断言 + assertEquals(messageId, resultMessageId); + } + + /** + * 发送成功,当短信模板开启时 + */ + @Test + public void testSendSingleNotify_successWhenMailTemplateEnable() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock NotifyTemplateService 的方法 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(notifyTemplateService.formatNotifyTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock NotifyMessageService 的方法 + Long messageId = randomLongId(); + when(notifyMessageService.createNotifyMessage(eq(userId), eq(userType), + eq(template), eq(content), eq(templateParams))).thenReturn(messageId); + + // 调用 + Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams); + // 断言 + assertEquals(messageId, resultMessageId); + } + + /** + * 发送成功,当短信模板关闭时 + */ + @Test + public void testSendSingleMail_successWhenSmsTemplateDisable() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock NotifyTemplateService 的方法 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(notifyTemplateService.getNotifyTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + + // 调用 + Long resultMessageId = notifySendService.sendSingleNotify(userId, userType, templateCode, templateParams); + // 断言 + assertNull(resultMessageId); + verify(notifyTemplateService, never()).formatNotifyTemplateContent(anyString(), anyMap()); + verify(notifyMessageService, never()).createNotifyMessage(anyLong(), anyInt(), any(), anyString(), anyMap()); + } + + @Test + public void testCheckMailTemplateValid_notExists() { + // 准备参数 + String templateCode = randomString(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> notifySendService.validateNotifyTemplate(templateCode), + NOTICE_NOT_FOUND); + } + + @Test + public void testCheckTemplateParams_paramMiss() { + // 准备参数 + NotifyTemplateDO template = randomPojo(NotifyTemplateDO.class, + o -> o.setParams(Lists.newArrayList("code"))); + Map templateParams = new HashMap<>(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> notifySendService.validateTemplateParams(template, templateParams), + NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code"); + } + + @Test + public void testSendBatchNotify() { + // 准备参数 + // mock 方法 + + // 调用 + UnsupportedOperationException exception = Assertions.assertThrows( + UnsupportedOperationException.class, + () -> notifySendService.sendBatchNotify(null, null, null, null, null) + ); + // 断言 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java new file mode 100644 index 0000000..d49f48c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java @@ -0,0 +1,178 @@ +package cn.iocoder.yudao.module.system.service.notify; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link NotifyTemplateServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(NotifyTemplateServiceImpl.class) +public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { + + @Resource + private NotifyTemplateServiceImpl notifyTemplateService; + + @Resource + private NotifyTemplateMapper notifyTemplateMapper; + + @Test + public void testCreateNotifyTemplate_success() { + // 准备参数 + NotifyTemplateSaveReqVO reqVO = randomPojo(NotifyTemplateSaveReqVO.class, + o -> o.setStatus(randomCommonStatus())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long notifyTemplateId = notifyTemplateService.createNotifyTemplate(reqVO); + // 断言 + assertNotNull(notifyTemplateId); + // 校验记录的属性是否正确 + NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId); + assertPojoEquals(reqVO, notifyTemplate, "id"); + } + + @Test + public void testUpdateNotifyTemplate_success() { + // mock 数据 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); + notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + NotifyTemplateSaveReqVO reqVO = randomPojo(NotifyTemplateSaveReqVO.class, o -> { + o.setId(dbNotifyTemplate.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用 + notifyTemplateService.updateNotifyTemplate(reqVO); + // 校验是否更新正确 + NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, notifyTemplate); + } + + @Test + public void testUpdateNotifyTemplate_notExists() { + // 准备参数 + NotifyTemplateSaveReqVO reqVO = randomPojo(NotifyTemplateSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> notifyTemplateService.updateNotifyTemplate(reqVO), NOTIFY_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteNotifyTemplate_success() { + // mock 数据 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); + notifyTemplateMapper.insert(dbNotifyTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbNotifyTemplate.getId(); + + // 调用 + notifyTemplateService.deleteNotifyTemplate(id); + // 校验数据不存在了 + assertNull(notifyTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteNotifyTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> notifyTemplateService.deleteNotifyTemplate(id), NOTIFY_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testGetNotifyTemplatePage() { + // mock 数据 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到 + o.setName("芋头"); + o.setCode("test_01"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2022, 2, 3)); + }); + notifyTemplateMapper.insert(dbNotifyTemplate); + // 测试 name 不匹配 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("投"))); + // 测试 code 不匹配 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02"))); + // 测试 status 不匹配 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5)))); + // 准备参数 + NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO(); + reqVO.setName("芋"); + reqVO.setCode("est_01"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5)); + + // 调用 + PageResult pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0)); + } + + @Test + public void testGetNotifyTemplate() { + // mock 数据 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); + notifyTemplateMapper.insert(dbNotifyTemplate); + // 准备参数 + Long id = dbNotifyTemplate.getId(); + + // 调用 + NotifyTemplateDO notifyTemplate = notifyTemplateService.getNotifyTemplate(id); + // 断言 + assertPojoEquals(dbNotifyTemplate, notifyTemplate); + } + + @Test + public void testGetNotifyTemplateByCodeFromCache() { + // mock 数据 + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); + notifyTemplateMapper.insert(dbNotifyTemplate); + // 准备参数 + String code = dbNotifyTemplate.getCode(); + + // 调用 + NotifyTemplateDO notifyTemplate = notifyTemplateService.getNotifyTemplateByCodeFromCache(code); + // 断言 + assertPojoEquals(dbNotifyTemplate, notifyTemplate); + } + + @Test + public void testFormatNotifyTemplateContent() { + // 准备参数 + Map params = new HashMap<>(); + params.put("name", "小红"); + params.put("what", "饭"); + + // 调用,并断言 + assertEquals("小红,你好,饭吃了吗?", + notifyTemplateService.formatNotifyTemplateContent("{name},你好,{what}吃了吗?", params)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImplTest.java new file mode 100644 index 0000000..1ca22a9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImplTest.java @@ -0,0 +1,269 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ApproveMapper; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.*; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link OAuth2ApproveServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(OAuth2ApproveServiceImpl.class) +public class OAuth2ApproveServiceImplTest extends BaseDbUnitTest { + + @Resource + private OAuth2ApproveServiceImpl oauth2ApproveService; + + @Resource + private OAuth2ApproveMapper oauth2ApproveMapper; + + @MockBean + private OAuth2ClientService oauth2ClientService; + + @Test + public void checkForPreApproval_clientAutoApprove() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List requestedScopes = Lists.newArrayList("read"); + // mock 方法 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))) + .thenReturn(randomPojo(OAuth2ClientDO.class).setAutoApproveScopes(requestedScopes)); + + // 调用 + boolean success = oauth2ApproveService.checkForPreApproval(userId, userType, + clientId, requestedScopes); + // 断言 + assertTrue(success); + List result = oauth2ApproveMapper.selectList(); + assertEquals(1, result.size()); + assertEquals(userId, result.get(0).getUserId()); + assertEquals(userType, result.get(0).getUserType()); + assertEquals(clientId, result.get(0).getClientId()); + assertEquals("read", result.get(0).getScope()); + assertTrue(result.get(0).getApproved()); + assertFalse(DateUtils.isExpired(result.get(0).getExpiresTime())); + } + + @Test + public void checkForPreApproval_approve() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List requestedScopes = Lists.newArrayList("read"); + // mock 方法 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))) + .thenReturn(randomPojo(OAuth2ClientDO.class).setAutoApproveScopes(null)); + // mock 数据 + OAuth2ApproveDO approve = randomPojo(OAuth2ApproveDO.class).setUserId(userId) + .setUserType(userType).setClientId(clientId).setScope("read") + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 1L, ChronoUnit.DAYS)).setApproved(true); // 同意 + oauth2ApproveMapper.insert(approve); + + // 调用 + boolean success = oauth2ApproveService.checkForPreApproval(userId, userType, + clientId, requestedScopes); + // 断言 + assertTrue(success); + } + + @Test + public void checkForPreApproval_reject() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List requestedScopes = Lists.newArrayList("read"); + // mock 方法 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))) + .thenReturn(randomPojo(OAuth2ClientDO.class).setAutoApproveScopes(null)); + // mock 数据 + OAuth2ApproveDO approve = randomPojo(OAuth2ApproveDO.class).setUserId(userId) + .setUserType(userType).setClientId(clientId).setScope("read") + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 1L, ChronoUnit.DAYS)).setApproved(false); // 拒绝 + oauth2ApproveMapper.insert(approve); + + // 调用 + boolean success = oauth2ApproveService.checkForPreApproval(userId, userType, + clientId, requestedScopes); + // 断言 + assertFalse(success); + } + + @Test + public void testUpdateAfterApproval_none() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + + // 调用 + boolean success = oauth2ApproveService.updateAfterApproval(userId, userType, clientId, + null); + // 断言 + assertTrue(success); + List result = oauth2ApproveMapper.selectList(); + assertEquals(0, result.size()); + } + + @Test + public void testUpdateAfterApproval_approved() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + Map requestedScopes = new LinkedHashMap<>(); // 有序,方便判断 + requestedScopes.put("read", true); + requestedScopes.put("write", false); + // mock 方法 + + // 调用 + boolean success = oauth2ApproveService.updateAfterApproval(userId, userType, clientId, + requestedScopes); + // 断言 + assertTrue(success); + List result = oauth2ApproveMapper.selectList(); + assertEquals(2, result.size()); + // read + assertEquals(userId, result.get(0).getUserId()); + assertEquals(userType, result.get(0).getUserType()); + assertEquals(clientId, result.get(0).getClientId()); + assertEquals("read", result.get(0).getScope()); + assertTrue(result.get(0).getApproved()); + assertFalse(DateUtils.isExpired(result.get(0).getExpiresTime())); + // write + assertEquals(userId, result.get(1).getUserId()); + assertEquals(userType, result.get(1).getUserType()); + assertEquals(clientId, result.get(1).getClientId()); + assertEquals("write", result.get(1).getScope()); + assertFalse(result.get(1).getApproved()); + assertFalse(DateUtils.isExpired(result.get(1).getExpiresTime())); + } + + @Test + public void testUpdateAfterApproval_reject() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + Map requestedScopes = new LinkedHashMap<>(); + requestedScopes.put("write", false); + // mock 方法 + + // 调用 + boolean success = oauth2ApproveService.updateAfterApproval(userId, userType, clientId, + requestedScopes); + // 断言 + assertFalse(success); + List result = oauth2ApproveMapper.selectList(); + assertEquals(1, result.size()); + // write + assertEquals(userId, result.get(0).getUserId()); + assertEquals(userType, result.get(0).getUserType()); + assertEquals(clientId, result.get(0).getClientId()); + assertEquals("write", result.get(0).getScope()); + assertFalse(result.get(0).getApproved()); + assertFalse(DateUtils.isExpired(result.get(0).getExpiresTime())); + } + + @Test + public void testGetApproveList() { + // 准备参数 + Long userId = 10L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + String clientId = randomString(); + // mock 数据 + OAuth2ApproveDO approve = randomPojo(OAuth2ApproveDO.class).setUserId(userId) + .setUserType(userType).setClientId(clientId).setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 1L, ChronoUnit.DAYS)); + oauth2ApproveMapper.insert(approve); // 未过期 + oauth2ApproveMapper.insert(ObjectUtil.clone(approve).setId(null) + .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), -1L, ChronoUnit.DAYS))); // 已过期 + + // 调用 + List result = oauth2ApproveService.getApproveList(userId, userType, clientId); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(approve, result.get(0)); + } + + @Test + public void testSaveApprove_insert() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + String scope = randomString(); + Boolean approved = randomBoolean(); + LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault()); + // mock 方法 + + // 调用 + oauth2ApproveService.saveApprove(userId, userType, clientId, + scope, approved, expireTime); + // 断言 + List result = oauth2ApproveMapper.selectList(); + assertEquals(1, result.size()); + assertEquals(userId, result.get(0).getUserId()); + assertEquals(userType, result.get(0).getUserType()); + assertEquals(clientId, result.get(0).getClientId()); + assertEquals(scope, result.get(0).getScope()); + assertEquals(approved, result.get(0).getApproved()); + assertEquals(expireTime, result.get(0).getExpiresTime()); + } + + @Test + public void testSaveApprove_update() { + // mock 数据 + OAuth2ApproveDO approve = randomPojo(OAuth2ApproveDO.class); + oauth2ApproveMapper.insert(approve); + // 准备参数 + Long userId = approve.getUserId(); + Integer userType = approve.getUserType(); + String clientId = approve.getClientId(); + String scope = approve.getScope(); + Boolean approved = randomBoolean(); + LocalDateTime expireTime = LocalDateTime.ofInstant(randomDay(1, 30).toInstant(), ZoneId.systemDefault()); + // mock 方法 + + // 调用 + oauth2ApproveService.saveApprove(userId, userType, clientId, + scope, approved, expireTime); + // 断言 + List result = oauth2ApproveMapper.selectList(); + assertEquals(1, result.size()); + assertEquals(approve.getId(), result.get(0).getId()); + assertEquals(userId, result.get(0).getUserId()); + assertEquals(userType, result.get(0).getUserType()); + assertEquals(clientId, result.get(0).getClientId()); + assertEquals(scope, result.get(0).getScope()); + assertEquals(approved, result.get(0).getApproved()); + assertEquals(expireTime, result.get(0).getExpiresTime()); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java new file mode 100644 index 0000000..3d4e436 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java @@ -0,0 +1,220 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Collections; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; + +/** + * {@link OAuth2ClientServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(OAuth2ClientServiceImpl.class) +public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { + + @Resource + private OAuth2ClientServiceImpl oauth2ClientService; + + @Resource + private OAuth2ClientMapper oauth2ClientMapper; + + @Test + public void testCreateOAuth2Client_success() { + // 准备参数 + OAuth2ClientSaveReqVO reqVO = randomPojo(OAuth2ClientSaveReqVO.class, + o -> o.setLogo(randomString())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long oauth2ClientId = oauth2ClientService.createOAuth2Client(reqVO); + // 断言 + assertNotNull(oauth2ClientId); + // 校验记录的属性是否正确 + OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(oauth2ClientId); + assertPojoEquals(reqVO, oAuth2Client, "id"); + } + + @Test + public void testUpdateOAuth2Client_success() { + // mock 数据 + OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class); + oauth2ClientMapper.insert(dbOAuth2Client);// @Sql: 先插入出一条存在的数据 + // 准备参数 + OAuth2ClientSaveReqVO reqVO = randomPojo(OAuth2ClientSaveReqVO.class, o -> { + o.setId(dbOAuth2Client.getId()); // 设置更新的 ID + o.setLogo(randomString()); + }); + + // 调用 + oauth2ClientService.updateOAuth2Client(reqVO); + // 校验是否更新正确 + OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, oAuth2Client); + } + + @Test + public void testUpdateOAuth2Client_notExists() { + // 准备参数 + OAuth2ClientSaveReqVO reqVO = randomPojo(OAuth2ClientSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> oauth2ClientService.updateOAuth2Client(reqVO), OAUTH2_CLIENT_NOT_EXISTS); + } + + @Test + public void testDeleteOAuth2Client_success() { + // mock 数据 + OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class); + oauth2ClientMapper.insert(dbOAuth2Client);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbOAuth2Client.getId(); + + // 调用 + oauth2ClientService.deleteOAuth2Client(id); + // 校验数据不存在了 + assertNull(oauth2ClientMapper.selectById(id)); + } + + @Test + public void testDeleteOAuth2Client_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> oauth2ClientService.deleteOAuth2Client(id), OAUTH2_CLIENT_NOT_EXISTS); + } + + @Test + public void testValidateClientIdExists_withId() { + // mock 数据 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("tudou"); + oauth2ClientMapper.insert(client); + // 准备参数 + Long id = randomLongId(); + String clientId = "tudou"; + + // 调用,不会报错 + assertServiceException(() -> oauth2ClientService.validateClientIdExists(id, clientId), OAUTH2_CLIENT_EXISTS); + } + + @Test + public void testValidateClientIdExists_noId() { + // mock 数据 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("tudou"); + oauth2ClientMapper.insert(client); + // 准备参数 + String clientId = "tudou"; + + // 调用,不会报错 + assertServiceException(() -> oauth2ClientService.validateClientIdExists(null, clientId), OAUTH2_CLIENT_EXISTS); + } + + @Test + public void testGetOAuth2Client() { + // mock 数据 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class); + oauth2ClientMapper.insert(clientDO); + // 准备参数 + Long id = clientDO.getId(); + + // 调用,并断言 + OAuth2ClientDO dbClientDO = oauth2ClientService.getOAuth2Client(id); + assertPojoEquals(clientDO, dbClientDO); + } + + @Test + public void testGetOAuth2ClientFromCache() { + // mock 数据 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class); + oauth2ClientMapper.insert(clientDO); + // 准备参数 + String clientId = clientDO.getClientId(); + + // 调用,并断言 + OAuth2ClientDO dbClientDO = oauth2ClientService.getOAuth2ClientFromCache(clientId); + assertPojoEquals(clientDO, dbClientDO); + } + + @Test + public void testGetOAuth2ClientPage() { + // mock 数据 + OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到 + o.setName("潜龙"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + oauth2ClientMapper.insert(dbOAuth2Client); + // 测试 name 不匹配 + oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰"))); + // 测试 status 不匹配 + oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO(); + reqVO.setName("龙"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + PageResult pageResult = oauth2ClientService.getOAuth2ClientPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0)); + } + + @Test + public void testValidOAuthClientFromCache() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(OAuth2ClientServiceImpl.class))) + .thenReturn(oauth2ClientService); + + // mock 方法 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default") + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + oauth2ClientMapper.insert(client); + OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable") + .setStatus(CommonStatusEnum.DISABLE.getStatus()); + oauth2ClientMapper.insert(client02); + + // 调用,并断言 + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(), + null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS); + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable", + null, null, null, null), OAUTH2_CLIENT_DISABLE); + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", + randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR); + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", + null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", + null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER); + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", + null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test"); + // 成功调用(1:参数完整) + OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(), + client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0)); + assertPojoEquals(client, result); + // 成功调用(2:只有 clientId 参数) + result = oauth2ClientService.validOAuthClientFromCache(client.getClientId()); + assertPojoEquals(client, result); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImplTest.java new file mode 100644 index 0000000..2ed9c97 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImplTest.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_EXPIRE; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link OAuth2CodeServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(OAuth2CodeServiceImpl.class) +class OAuth2CodeServiceImplTest extends BaseDbUnitTest { + + @Resource + private OAuth2CodeServiceImpl oauth2CodeService; + + @Resource + private OAuth2CodeMapper oauth2CodeMapper; + + @Test + public void testCreateAuthorizationCode() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = RandomUtil.randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List scopes = Lists.newArrayList("read", "write"); + String redirectUri = randomString(); + String state = randomString(); + + // 调用 + OAuth2CodeDO codeDO = oauth2CodeService.createAuthorizationCode(userId, userType, clientId, + scopes, redirectUri, state); + // 断言 + OAuth2CodeDO dbCodeDO = oauth2CodeMapper.selectByCode(codeDO.getCode()); + assertPojoEquals(codeDO, dbCodeDO, "createTime", "updateTime", "deleted"); + assertEquals(userId, codeDO.getUserId()); + assertEquals(userType, codeDO.getUserType()); + assertEquals(clientId, codeDO.getClientId()); + assertEquals(scopes, codeDO.getScopes()); + assertEquals(redirectUri, codeDO.getRedirectUri()); + assertEquals(state, codeDO.getState()); + assertFalse(DateUtils.isExpired(codeDO.getExpiresTime())); + } + + @Test + public void testConsumeAuthorizationCode_null() { + // 调用,并断言 + assertServiceException(() -> oauth2CodeService.consumeAuthorizationCode(randomString()), + OAUTH2_CODE_NOT_EXISTS); + } + + @Test + public void testConsumeAuthorizationCode_expired() { + // 准备参数 + String code = "test_code"; + // mock 数据 + OAuth2CodeDO codeDO = randomPojo(OAuth2CodeDO.class).setCode(code) + .setExpiresTime(LocalDateTime.now().minusDays(1)); + oauth2CodeMapper.insert(codeDO); + + // 调用,并断言 + assertServiceException(() -> oauth2CodeService.consumeAuthorizationCode(code), + OAUTH2_CODE_EXPIRE); + } + + @Test + public void testConsumeAuthorizationCode_success() { + // 准备参数 + String code = "test_code"; + // mock 数据 + OAuth2CodeDO codeDO = randomPojo(OAuth2CodeDO.class).setCode(code) + .setExpiresTime(LocalDateTime.now().plusDays(1)); + oauth2CodeMapper.insert(codeDO); + + // 调用 + OAuth2CodeDO result = oauth2CodeService.consumeAuthorizationCode(code); + assertPojoEquals(codeDO, result); + assertNull(oauth2CodeMapper.selectByCode(code)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java new file mode 100644 index 0000000..52c7228 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java @@ -0,0 +1,173 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link OAuth2GrantServiceImpl} 的单元测试 + * + * @author 芋道源码 + */ +public class OAuth2GrantServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private OAuth2GrantServiceImpl oauth2GrantService; + + @Mock + private OAuth2TokenService oauth2TokenService; + @Mock + private OAuth2CodeService oauth2CodeService; + @Mock + private AdminAuthService adminAuthService; + + @Test + public void testGrantImplicit() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List scopes = Lists.newArrayList("read", "write"); + // mock 方法 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.createAccessToken(eq(userId), eq(userType), + eq(clientId), eq(scopes))).thenReturn(accessTokenDO); + + // 调用,并断言 + assertPojoEquals(accessTokenDO, oauth2GrantService.grantImplicit( + userId, userType, clientId, scopes)); + } + + @Test + public void testGrantAuthorizationCodeForCode() { + // 准备参数 + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String clientId = randomString(); + List scopes = Lists.newArrayList("read", "write"); + String redirectUri = randomString(); + String state = randomString(); + // mock 方法 + OAuth2CodeDO codeDO = randomPojo(OAuth2CodeDO.class); + when(oauth2CodeService.createAuthorizationCode(eq(userId), eq(userType), + eq(clientId), eq(scopes), eq(redirectUri), eq(state))).thenReturn(codeDO); + + // 调用,并断言 + assertEquals(codeDO.getCode(), oauth2GrantService.grantAuthorizationCodeForCode(userId, userType, + clientId, scopes, redirectUri, state)); + } + + @Test + public void testGrantAuthorizationCodeForAccessToken() { + // 准备参数 + String clientId = randomString(); + String code = randomString(); + List scopes = Lists.newArrayList("read", "write"); + String redirectUri = randomString(); + String state = randomString(); + // mock 方法(code) + OAuth2CodeDO codeDO = randomPojo(OAuth2CodeDO.class, o -> { + o.setClientId(clientId); + o.setRedirectUri(redirectUri); + o.setState(state); + o.setScopes(scopes); + }); + when(oauth2CodeService.consumeAuthorizationCode(eq(code))).thenReturn(codeDO); + // mock 方法(创建令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.createAccessToken(eq(codeDO.getUserId()), eq(codeDO.getUserType()), + eq(codeDO.getClientId()), eq(codeDO.getScopes()))).thenReturn(accessTokenDO); + + // 调用,并断言 + assertPojoEquals(accessTokenDO, oauth2GrantService.grantAuthorizationCodeForAccessToken( + clientId, code, redirectUri, state)); + } + + @Test + public void testGrantPassword() { + // 准备参数 + String username = randomString(); + String password = randomString(); + String clientId = randomString(); + List scopes = Lists.newArrayList("read", "write"); + // mock 方法(认证) + AdminUserDO user = randomPojo(AdminUserDO.class); + when(adminAuthService.authenticate(eq(username), eq(password))).thenReturn(user); + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.createAccessToken(eq(user.getId()), eq(UserTypeEnum.ADMIN.getValue()), + eq(clientId), eq(scopes))).thenReturn(accessTokenDO); + + // 调用,并断言 + assertPojoEquals(accessTokenDO, oauth2GrantService.grantPassword( + username, password, clientId, scopes)); + } + + @Test + public void testGrantRefreshToken() { + // 准备参数 + String refreshToken = randomString(); + String clientId = randomString(); + // mock 方法 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.refreshAccessToken(eq(refreshToken), eq(clientId))) + .thenReturn(accessTokenDO); + + // 调用,并断言 + assertPojoEquals(accessTokenDO, oauth2GrantService.grantRefreshToken( + refreshToken, clientId)); + } + + @Test + public void testGrantClientCredentials() { + assertThrows(UnsupportedOperationException.class, + () -> oauth2GrantService.grantClientCredentials(randomString(), emptyList()), + "暂时不支持 client_credentials 授权模式"); + } + + @Test + public void testRevokeToken_clientIdError() { + // 准备参数 + String clientId = randomString(); + String accessToken = randomString(); + // mock 方法 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); + when(oauth2TokenService.getAccessToken(eq(accessToken))).thenReturn(accessTokenDO); + + // 调用,并断言 + assertFalse(oauth2GrantService.revokeToken(clientId, accessToken)); + } + + @Test + public void testRevokeToken_success() { + // 准备参数 + String clientId = randomString(); + String accessToken = randomString(); + // mock 方法(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setClientId(clientId); + when(oauth2TokenService.getAccessToken(eq(accessToken))).thenReturn(accessTokenDO); + // mock 方法(移除) + when(oauth2TokenService.removeAccessToken(eq(accessToken))).thenReturn(accessTokenDO); + + // 调用,并断言 + assertTrue(oauth2GrantService.revokeToken(clientId, accessToken)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java new file mode 100644 index 0000000..03e4a02 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java @@ -0,0 +1,303 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; +import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link OAuth2TokenServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import({OAuth2TokenServiceImpl.class, OAuth2AccessTokenRedisDAO.class}) +public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest { + + @Resource + private OAuth2TokenServiceImpl oauth2TokenService; + + @Resource + private OAuth2AccessTokenMapper oauth2AccessTokenMapper; + @Resource + private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper; + + @Resource + private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO; + + @MockBean + private OAuth2ClientService oauth2ClientService; + @MockBean + private AdminUserService adminUserService; + + @Test + public void testCreateAccessToken() { + TenantContextHolder.setTenantId(0L); + // 准备参数 + Long userId = randomLongId(); + Integer userType = UserTypeEnum.ADMIN.getValue(); + String clientId = randomString(); + List scopes = Lists.newArrayList("read", "write"); + // mock 方法 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class).setClientId(clientId) + .setAccessTokenValiditySeconds(30).setRefreshTokenValiditySeconds(60); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(clientDO); + // mock 数据(用户) + AdminUserDO user = randomPojo(AdminUserDO.class); + when(adminUserService.getUser(userId)).thenReturn(user); + + // 调用 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, userType, clientId, scopes); + // 断言访问令牌 + OAuth2AccessTokenDO dbAccessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessTokenDO.getAccessToken()); + assertPojoEquals(accessTokenDO, dbAccessTokenDO, "createTime", "updateTime", "deleted"); + assertEquals(userId, accessTokenDO.getUserId()); + assertEquals(userType, accessTokenDO.getUserType()); + assertEquals(2, accessTokenDO.getUserInfo().size()); + assertEquals(user.getNickname(), accessTokenDO.getUserInfo().get("nickname")); + assertEquals(user.getDeptId().toString(), accessTokenDO.getUserInfo().get("deptId")); + assertEquals(clientId, accessTokenDO.getClientId()); + assertEquals(scopes, accessTokenDO.getScopes()); + assertFalse(DateUtils.isExpired(accessTokenDO.getExpiresTime())); + // 断言访问令牌的缓存 + OAuth2AccessTokenDO redisAccessTokenDO = oauth2AccessTokenRedisDAO.get(accessTokenDO.getAccessToken()); + assertPojoEquals(accessTokenDO, redisAccessTokenDO, "createTime", "updateTime", "deleted"); + // 断言刷新令牌 + OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectList().get(0); + assertPojoEquals(accessTokenDO, refreshTokenDO, "id", "expiresTime", "createTime", "updateTime", "deleted"); + assertFalse(DateUtils.isExpired(refreshTokenDO.getExpiresTime())); + } + + @Test + public void testRefreshAccessToken_null() { + // 准备参数 + String refreshToken = randomString(); + String clientId = randomString(); + // mock 方法 + + // 调用,并断言 + assertServiceException(() -> oauth2TokenService.refreshAccessToken(refreshToken, clientId), + new ErrorCode(400, "无效的刷新令牌")); + } + + @Test + public void testRefreshAccessToken_clientIdError() { + // 准备参数 + String refreshToken = randomString(); + String clientId = randomString(); + // mock 方法 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class).setClientId(clientId); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(clientDO); + // mock 数据(访问令牌) + OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class) + .setRefreshToken(refreshToken).setClientId("error"); + oauth2RefreshTokenMapper.insert(refreshTokenDO); + + // 调用,并断言 + assertServiceException(() -> oauth2TokenService.refreshAccessToken(refreshToken, clientId), + new ErrorCode(400, "刷新令牌的客户端编号不正确")); + } + + @Test + public void testRefreshAccessToken_expired() { + // 准备参数 + String refreshToken = randomString(); + String clientId = randomString(); + // mock 方法 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class).setClientId(clientId); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(clientDO); + // mock 数据(访问令牌) + OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class) + .setRefreshToken(refreshToken).setClientId(clientId) + .setExpiresTime(LocalDateTime.now().minusDays(1)); + oauth2RefreshTokenMapper.insert(refreshTokenDO); + + // 调用,并断言 + assertServiceException(() -> oauth2TokenService.refreshAccessToken(refreshToken, clientId), + new ErrorCode(401, "刷新令牌已过期")); + assertEquals(0, oauth2RefreshTokenMapper.selectCount()); + } + + @Test + public void testRefreshAccessToken_success() { + TenantContextHolder.setTenantId(0L); + // 准备参数 + String refreshToken = randomString(); + String clientId = randomString(); + // mock 方法 + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class).setClientId(clientId) + .setAccessTokenValiditySeconds(30); + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(clientDO); + // mock 数据(访问令牌) + OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class) + .setRefreshToken(refreshToken).setClientId(clientId) + .setExpiresTime(LocalDateTime.now().plusDays(1)) + .setUserType(UserTypeEnum.ADMIN.getValue()); + oauth2RefreshTokenMapper.insert(refreshTokenDO); + // mock 数据(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setRefreshToken(refreshToken) + .setUserType(refreshTokenDO.getUserType()); + oauth2AccessTokenMapper.insert(accessTokenDO); + oauth2AccessTokenRedisDAO.set(accessTokenDO); + // mock 数据(用户) + AdminUserDO user = randomPojo(AdminUserDO.class); + when(adminUserService.getUser(refreshTokenDO.getUserId())).thenReturn(user); + + // 调用 + OAuth2AccessTokenDO newAccessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId); + // 断言,老的访问令牌被删除 + assertNull(oauth2AccessTokenMapper.selectByAccessToken(accessTokenDO.getAccessToken())); + assertNull(oauth2AccessTokenRedisDAO.get(accessTokenDO.getAccessToken())); + // 断言,新的访问令牌 + OAuth2AccessTokenDO dbAccessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(newAccessTokenDO.getAccessToken()); + assertPojoEquals(newAccessTokenDO, dbAccessTokenDO, "createTime", "updateTime", "deleted"); + assertPojoEquals(newAccessTokenDO, refreshTokenDO, "id", "expiresTime", "createTime", "updateTime", "deleted", + "creator", "updater"); + assertFalse(DateUtils.isExpired(newAccessTokenDO.getExpiresTime())); + // 断言,新的访问令牌的缓存 + OAuth2AccessTokenDO redisAccessTokenDO = oauth2AccessTokenRedisDAO.get(newAccessTokenDO.getAccessToken()); + assertPojoEquals(newAccessTokenDO, redisAccessTokenDO, "createTime", "updateTime", "deleted"); + } + + @Test + public void testGetAccessToken() { + // mock 数据(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTime.now().plusDays(1)); + oauth2AccessTokenMapper.insert(accessTokenDO); + // 准备参数 + String accessToken = accessTokenDO.getAccessToken(); + + // 调用 + OAuth2AccessTokenDO result = oauth2TokenService.getAccessToken(accessToken); + // 断言 + assertPojoEquals(accessTokenDO, result, "createTime", "updateTime", "deleted", + "creator", "updater"); + assertPojoEquals(accessTokenDO, oauth2AccessTokenRedisDAO.get(accessToken), "createTime", "updateTime", "deleted", + "creator", "updater"); + } + + @Test + public void testCheckAccessToken_null() { + // 调研,并断言 + assertServiceException(() -> oauth2TokenService.checkAccessToken(randomString()), + new ErrorCode(401, "访问令牌不存在")); + } + + @Test + public void testCheckAccessToken_expired() { + // mock 数据(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTime.now().minusDays(1)); + oauth2AccessTokenMapper.insert(accessTokenDO); + // 准备参数 + String accessToken = accessTokenDO.getAccessToken(); + + // 调研,并断言 + assertServiceException(() -> oauth2TokenService.checkAccessToken(accessToken), + new ErrorCode(401, "访问令牌已过期")); + } + + @Test + public void testCheckAccessToken_success() { + // mock 数据(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTime.now().plusDays(1)); + oauth2AccessTokenMapper.insert(accessTokenDO); + // 准备参数 + String accessToken = accessTokenDO.getAccessToken(); + + // 调研,并断言 + OAuth2AccessTokenDO result = oauth2TokenService.getAccessToken(accessToken); + // 断言 + assertPojoEquals(accessTokenDO, result, "createTime", "updateTime", "deleted", + "creator", "updater"); + } + + @Test + public void testRemoveAccessToken_null() { + // 调用,并断言 + assertNull(oauth2TokenService.removeAccessToken(randomString())); + } + + @Test + public void testRemoveAccessToken_success() { + // mock 数据(访问令牌) + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) + .setExpiresTime(LocalDateTime.now().plusDays(1)); + oauth2AccessTokenMapper.insert(accessTokenDO); + // mock 数据(刷新令牌) + OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class) + .setRefreshToken(accessTokenDO.getRefreshToken()); + oauth2RefreshTokenMapper.insert(refreshTokenDO); + // 调用 + OAuth2AccessTokenDO result = oauth2TokenService.removeAccessToken(accessTokenDO.getAccessToken()); + assertPojoEquals(accessTokenDO, result, "createTime", "updateTime", "deleted", + "creator", "updater"); + // 断言数据 + assertNull(oauth2AccessTokenMapper.selectByAccessToken(accessTokenDO.getAccessToken())); + assertNull(oauth2RefreshTokenMapper.selectByRefreshToken(accessTokenDO.getRefreshToken())); + assertNull(oauth2AccessTokenRedisDAO.get(accessTokenDO.getAccessToken())); + } + + + @Test + public void testGetAccessTokenPage() { + // mock 数据 + OAuth2AccessTokenDO dbAccessToken = randomPojo(OAuth2AccessTokenDO.class, o -> { // 等会查询到 + o.setUserId(10L); + o.setUserType(1); + o.setClientId("test_client"); + o.setExpiresTime(LocalDateTime.now().plusDays(1)); + }); + oauth2AccessTokenMapper.insert(dbAccessToken); + // 测试 userId 不匹配 + oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setUserId(20L))); + // 测试 userType 不匹配 + oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setUserType(2))); + // 测试 userType 不匹配 + oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setClientId("it_client"))); + // 测试 expireTime 不匹配 + oauth2AccessTokenMapper.insert(cloneIgnoreId(dbAccessToken, o -> o.setExpiresTime(LocalDateTimeUtil.now()))); + // 准备参数 + OAuth2AccessTokenPageReqVO reqVO = new OAuth2AccessTokenPageReqVO(); + reqVO.setUserId(10L); + reqVO.setUserType(1); + reqVO.setClientId("test"); + + // 调用 + PageResult pageResult = oauth2TokenService.getAccessTokenPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbAccessToken, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java new file mode 100644 index 0000000..4a1c873 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java @@ -0,0 +1,331 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuSaveVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; + +@Import(MenuServiceImpl.class) +public class MenuServiceImplTest extends BaseDbUnitTest { + + @Resource + private MenuServiceImpl menuService; + + @Resource + private MenuMapper menuMapper; + + @MockBean + private PermissionService permissionService; + @MockBean + private TenantService tenantService; + + @Test + public void testCreateMenu_success() { + // mock 数据(构造父菜单) + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, + "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + // 准备参数 + MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> { + o.setParentId(parentId); + o.setName("testSonName"); + o.setType(MenuTypeEnum.MENU.getType()); + }).setId(null); // 防止 id 被赋值 + Long menuId = menuService.createMenu(reqVO); + + // 校验记录的属性是否正确 + MenuDO dbMenu = menuMapper.selectById(menuId); + assertPojoEquals(reqVO, dbMenu, "id"); + } + + @Test + public void testUpdateMenu_success() { + // mock 数据(构造父子菜单) + MenuDO sonMenuDO = createParentAndSonMenu(); + Long sonId = sonMenuDO.getId(); + // 准备参数 + MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> { + o.setId(sonId); + o.setName("testSonName"); // 修改名字 + o.setParentId(sonMenuDO.getParentId()); + o.setType(MenuTypeEnum.MENU.getType()); + }); + + // 调用 + menuService.updateMenu(reqVO); + // 校验记录的属性是否正确 + MenuDO dbMenu = menuMapper.selectById(sonId); + assertPojoEquals(reqVO, dbMenu); + } + + @Test + public void testUpdateMenu_sonIdNotExist() { + // 准备参数 + MenuSaveVO reqVO = randomPojo(MenuSaveVO.class); + // 调用,并断言异常 + assertServiceException(() -> menuService.updateMenu(reqVO), MENU_NOT_EXISTS); + } + + @Test + public void testDeleteMenu_success() { + // mock 数据 + MenuDO menuDO = randomPojo(MenuDO.class); + menuMapper.insert(menuDO); + // 准备参数 + Long id = menuDO.getId(); + + // 调用 + menuService.deleteMenu(id); + // 断言 + MenuDO dbMenuDO = menuMapper.selectById(id); + assertNull(dbMenuDO); + verify(permissionService).processMenuDeleted(id); + } + + @Test + public void testDeleteMenu_menuNotExist() { + assertServiceException(() -> menuService.deleteMenu(randomLongId()), + MENU_NOT_EXISTS); + } + + @Test + public void testDeleteMenu_existChildren() { + // mock 数据(构造父子菜单) + MenuDO sonMenu = createParentAndSonMenu(); + // 准备参数 + Long parentId = sonMenu.getParentId(); + + // 调用并断言异常 + assertServiceException(() -> menuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN); + } + + @Test + public void testGetMenuList_all() { + // mock 数据 + MenuDO menu100 = randomPojo(MenuDO.class); + menuMapper.insert(menu100); + MenuDO menu101 = randomPojo(MenuDO.class); + menuMapper.insert(menu101); + // 准备参数 + + // 调用 + List list = menuService.getMenuList(); + // 断言 + assertEquals(2, list.size()); + assertPojoEquals(menu100, list.get(0)); + assertPojoEquals(menu101, list.get(1)); + } + + @Test + public void testGetMenuList() { + // mock 数据 + MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setName("芋艿").setStatus(CommonStatusEnum.ENABLE.getStatus())); + menuMapper.insert(menuDO); + // 测试 status 不匹配 + menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 name 不匹配 + menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setName("艿"))); + // 准备参数 + MenuListReqVO reqVO = new MenuListReqVO().setName("芋").setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + List result = menuService.getMenuList(reqVO); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(menuDO, result.get(0)); + } + + @Test + public void testGetMenuListByTenant() { + // mock 数据 + MenuDO menu100 = randomPojo(MenuDO.class, o -> o.setId(100L).setStatus(CommonStatusEnum.ENABLE.getStatus())); + menuMapper.insert(menu100); + MenuDO menu101 = randomPojo(MenuDO.class, o -> o.setId(101L).setStatus(CommonStatusEnum.DISABLE.getStatus())); + menuMapper.insert(menu101); + MenuDO menu102 = randomPojo(MenuDO.class, o -> o.setId(102L).setStatus(CommonStatusEnum.ENABLE.getStatus())); + menuMapper.insert(menu102); + // mock 过滤菜单 + Set menuIds = asSet(100L, 101L); + doNothing().when(tenantService).handleTenantMenu(argThat(handler -> { + handler.handle(menuIds); + return true; + })); + // 准备参数 + MenuListReqVO reqVO = new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + List result = menuService.getMenuListByTenant(reqVO); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(menu100, result.get(0)); + } + + @Test + public void testGetMenuIdListByPermissionFromCache() { + // mock 数据 + MenuDO menu100 = randomPojo(MenuDO.class); + menuMapper.insert(menu100); + MenuDO menu101 = randomPojo(MenuDO.class); + menuMapper.insert(menu101); + // 准备参数 + String permission = menu100.getPermission(); + + // 调用 + List ids = menuService.getMenuIdListByPermissionFromCache(permission); + // 断言 + assertEquals(1, ids.size()); + assertEquals(menu100.getId(), ids.get(0)); + } + + @Test + public void testGetMenuList_ids() { + // mock 数据 + MenuDO menu100 = randomPojo(MenuDO.class); + menuMapper.insert(menu100); + MenuDO menu101 = randomPojo(MenuDO.class); + menuMapper.insert(menu101); + // 准备参数 + Collection ids = Collections.singleton(menu100.getId()); + + // 调用 + List list = menuService.getMenuList(ids); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(menu100, list.get(0)); + } + + @Test + public void testGetMenu() { + // mock 数据 + MenuDO menu = randomPojo(MenuDO.class); + menuMapper.insert(menu); + // 准备参数 + Long id = menu.getId(); + + // 调用 + MenuDO dbMenu = menuService.getMenu(id); + // 断言 + assertPojoEquals(menu, dbMenu); + } + + @Test + public void testValidateParentMenu_success() { + // mock 数据 + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L); + menuMapper.insert(menuDO); + // 准备参数 + Long parentId = menuDO.getId(); + + // 调用,无需断言 + menuService.validateParentMenu(parentId, null); + } + + @Test + public void testValidateParentMenu_canNotSetSelfToBeParent() { + // 调用,并断言异常 + assertServiceException(() -> menuService.validateParentMenu(1L, 1L), + MENU_PARENT_ERROR); + } + + @Test + public void testValidateParentMenu_parentNotExist() { + // 调用,并断言异常 + assertServiceException(() -> menuService.validateParentMenu(randomLongId(), null), + MENU_PARENT_NOT_EXISTS); + } + + @Test + public void testValidateParentMenu_parentTypeError() { + // mock 数据 + MenuDO menuDO = buildMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); + menuMapper.insert(menuDO); + // 准备参数 + Long parentId = menuDO.getId(); + + // 调用,并断言异常 + assertServiceException(() -> menuService.validateParentMenu(parentId, null), + MENU_PARENT_NOT_DIR_OR_MENU); + } + + @Test + public void testValidateMenu_success() { + // mock 父子菜单 + MenuDO sonMenu = createParentAndSonMenu(); + // 准备参数 + Long parentId = sonMenu.getParentId(); + Long otherSonMenuId = randomLongId(); + String otherSonMenuName = randomString(); + + // 调用,无需断言 + menuService.validateMenu(parentId, otherSonMenuName, otherSonMenuId); + } + + @Test + public void testValidateMenu_sonMenuNameDuplicate() { + // mock 父子菜单 + MenuDO sonMenu = createParentAndSonMenu(); + // 准备参数 + Long parentId = sonMenu.getParentId(); + Long otherSonMenuId = randomLongId(); + String otherSonMenuName = sonMenu.getName(); //相同名称 + + // 调用,并断言异常 + assertServiceException(() -> menuService.validateMenu(parentId, otherSonMenuName, otherSonMenuId), + MENU_NAME_DUPLICATE); + } + + // ====================== 初始化方法 ====================== + + /** + * 插入父子菜单,返回子菜单 + * + * @return 子菜单 + */ + private MenuDO createParentAndSonMenu() { + // 构造父子菜单 + MenuDO parentMenuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT); + menuMapper.insert(parentMenuDO); + // 构建子菜单 + MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName", + parentMenuDO.getParentId()); + menuMapper.insert(sonMenuDO); + return sonMenuDO; + } + + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId) { + return buildMenuDO(type, name, parentId, randomCommonStatus()); + } + + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) { + return randomPojo(MenuDO.class, o -> o.setId(null).setName(name).setParentId(parentId) + .setType(type.getType()).setStatus(status)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java new file mode 100644 index 0000000..442abd7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java @@ -0,0 +1,527 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; +import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static cn.hutool.core.collection.ListUtil.toList; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@Import({PermissionServiceImpl.class}) +public class PermissionServiceTest extends BaseDbUnitTest { + + @Resource + private PermissionServiceImpl permissionService; + + @Resource + private RoleMenuMapper roleMenuMapper; + @Resource + private UserRoleMapper userRoleMapper; + + @MockBean + private RoleService roleService; + @MockBean + private MenuService menuService; + @MockBean + private DeptService deptService; + @MockBean + private AdminUserService userService; + + @Test + public void testHasAnyPermissions_superAdmin() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + String[] roles = new String[]{"system:user:query", "system:user:create"}; + // mock 用户登录的角色 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); + // mock 其它方法 + when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true); + + // 调用,并断言 + assertTrue(permissionService.hasAnyPermissions(userId, roles)); + } + } + + @Test + public void testHasAnyPermissions_normal() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + String[] roles = new String[]{"system:user:query", "system:user:create"}; + // mock 用户登录的角色 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); + // mock 菜单 + Long menuId = 1000L; + when(menuService.getMenuIdListByPermissionFromCache( + eq("system:user:create"))).thenReturn(singletonList(menuId)); + roleMenuMapper.insert(randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1000L)); + + // 调用,并断言 + assertTrue(permissionService.hasAnyPermissions(userId, roles)); + } + } + + @Test + public void testHasAnyRoles() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + String[] roles = new String[]{"yunai", "tudou"}; + // mock 用户与角色的缓存 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L).setCode("tudou") + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); + + // 调用,并断言 + assertTrue(permissionService.hasAnyRoles(userId, roles)); + } + } + + // ========== 角色-菜单的相关方法 ========== + + @Test + public void testAssignRoleMenu() { + // 准备参数 + Long roleId = 1L; + Set menuIds = asSet(200L, 300L); + // mock 数据 + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L); + roleMenuMapper.insert(roleMenu01); + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(200L); + roleMenuMapper.insert(roleMenu02); + + // 调用 + permissionService.assignRoleMenu(roleId, menuIds); + // 断言 + List roleMenuList = roleMenuMapper.selectList(); + assertEquals(2, roleMenuList.size()); + assertEquals(1L, roleMenuList.get(0).getRoleId()); + assertEquals(200L, roleMenuList.get(0).getMenuId()); + assertEquals(1L, roleMenuList.get(1).getRoleId()); + assertEquals(300L, roleMenuList.get(1).getMenuId()); + } + + @Test + public void testProcessRoleDeleted() { + // 准备参数 + Long roleId = randomLongId(); + // mock 数据 UserRole + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setRoleId(roleId)); // 被删除 + userRoleMapper.insert(userRoleDO01); + UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 + userRoleMapper.insert(userRoleDO02); + // mock 数据 RoleMenu + RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(roleId)); // 被删除 + roleMenuMapper.insert(roleMenuDO01); + RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 + roleMenuMapper.insert(roleMenuDO02); + + // 调用 + permissionService.processRoleDeleted(roleId); + // 断言数据 RoleMenuDO + List dbRoleMenus = roleMenuMapper.selectList(); + assertEquals(1, dbRoleMenus.size()); + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); + // 断言数据 UserRoleDO + List dbUserRoles = userRoleMapper.selectList(); + assertEquals(1, dbUserRoles.size()); + assertPojoEquals(dbUserRoles.get(0), userRoleDO02); + } + + @Test + public void testProcessMenuDeleted() { + // 准备参数 + Long menuId = randomLongId(); + // mock 数据 + RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setMenuId(menuId)); // 被删除 + roleMenuMapper.insert(roleMenuDO01); + RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 + roleMenuMapper.insert(roleMenuDO02); + + // 调用 + permissionService.processMenuDeleted(menuId); + // 断言数据 + List dbRoleMenus = roleMenuMapper.selectList(); + assertEquals(1, dbRoleMenus.size()); + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); + } + + @Test + public void testGetRoleMenuIds_superAdmin() { + // 准备参数 + Long roleId = 100L; + // mock 方法 + when(roleService.hasAnySuperAdmin(eq(singleton(100L)))).thenReturn(true); + List menuList = singletonList(randomPojo(MenuDO.class).setId(1L)); + when(menuService.getMenuList()).thenReturn(menuList); + + // 调用 + Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); + // 断言 + assertEquals(singleton(1L), menuIds); + } + + @Test + public void testGetRoleMenuIds_normal() { + // 准备参数 + Long roleId = 100L; + // mock 数据 + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); + roleMenuMapper.insert(roleMenu01); + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(2L); + roleMenuMapper.insert(roleMenu02); + + // 调用 + Set menuIds = permissionService.getRoleMenuListByRoleId(roleId); + // 断言 + assertEquals(asSet(1L, 2L), menuIds); + } + + @Test + public void testGetMenuRoleIdListByMenuIdFromCache() { + // 准备参数 + Long menuId = 1L; + // mock 数据 + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); + roleMenuMapper.insert(roleMenu01); + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(200L).setMenuId(1L); + roleMenuMapper.insert(roleMenu02); + + // 调用 + Set roleIds = permissionService.getMenuRoleIdListByMenuIdFromCache(menuId); + // 断言 + assertEquals(asSet(100L, 200L), roleIds); + } + + // ========== 用户-角色的相关方法 ========== + + @Test + public void testAssignUserRole() { + // 准备参数 + Long userId = 1L; + Set roleIds = asSet(200L, 300L); + // mock 数据 + UserRoleDO userRole01 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(100L); + userRoleMapper.insert(userRole01); + UserRoleDO userRole02 = randomPojo(UserRoleDO.class).setUserId(1L).setRoleId(200L); + userRoleMapper.insert(userRole02); + + // 调用 + permissionService.assignUserRole(userId, roleIds); + // 断言 + List userRoleDOList = userRoleMapper.selectList(); + assertEquals(2, userRoleDOList.size()); + assertEquals(1L, userRoleDOList.get(0).getUserId()); + assertEquals(200L, userRoleDOList.get(0).getRoleId()); + assertEquals(1L, userRoleDOList.get(1).getUserId()); + assertEquals(300L, userRoleDOList.get(1).getRoleId()); + } + + @Test + public void testProcessUserDeleted() { + // 准备参数 + Long userId = randomLongId(); + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(userId)); // 被删除 + userRoleMapper.insert(userRoleDO01); + UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 + userRoleMapper.insert(userRoleDO02); + + // 调用 + permissionService.processUserDeleted(userId); + // 断言数据 + List dbUserRoles = userRoleMapper.selectList(); + assertEquals(1, dbUserRoles.size()); + assertPojoEquals(dbUserRoles.get(0), userRoleDO02); + } + + @Test + public void testGetUserRoleIdListByUserId() { + // 准备参数 + Long userId = 1L; + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByUserId(userId); + // 断言 + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdListByUserIdFromCache() { + // 准备参数 + Long userId = 1L; + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByUserIdFromCache(userId); + // 断言 + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdsFromCache() { + // 准备参数 + Long userId = 1L; + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByUserIdFromCache(userId); + // 断言 + assertEquals(asSet(10L, 20L), result); + } + + @Test + public void testGetUserRoleIdListByRoleId() { + // 准备参数 + Collection roleIds = asSet(10L, 20L); + // mock 数据 + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); + userRoleMapper.insert(userRoleDO01); + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); + userRoleMapper.insert(roleMenuDO02); + + // 调用 + Set result = permissionService.getUserRoleIdListByRoleId(roleIds); + // 断言 + assertEquals(asSet(1L, 2L), result); + } + + @Test + public void testGetEnableUserRoleListByUserIdFromCache() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户登录的角色 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(200L)); + RoleDO role01 = randomPojo(RoleDO.class, o -> o.setId(100L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + RoleDO role02 = randomPojo(RoleDO.class, o -> o.setId(200L) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(asSet(100L, 200L)))) + .thenReturn(toList(role01, role02)); + + // 调用 + List result = permissionService.getEnableUserRoleListByUserIdFromCache(userId); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(role01, result.get(0)); + } + } + + // ========== 用户-部门的相关方法 ========== + + @Test + public void testAssignRoleDataScope() { + // 准备参数 + Long roleId = 1L; + Integer dataScope = 2; + Set dataScopeDeptIds = asSet(10L, 20L); + + // 调用 + permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); + // 断言 + verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); + } + + @Test + public void testGetDeptDataPermission_All() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertTrue(result.getAll()); + assertFalse(result.getSelf()); + assertTrue(CollUtil.isEmpty(result.getDeptIds())); + } + } + + @Test + public void testGetDeptDataPermission_DeptCustom() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); + assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } + } + + @Test + public void testGetDeptDataPermission_DeptOnly() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(1, result.getDeptIds().size()); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } + } + + @Test + public void testGetDeptDataPermission_DeptAndChild() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), + null, null); // 最后返回 null 的目的,看看会不会重复调用 + // mock 方法(部门) + DeptDO deptDO = randomPojo(DeptDO.class); + when(deptService.getChildDeptIdListFromCache(eq(3L))).thenReturn(singleton(deptDO.getId())); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertFalse(result.getSelf()); + assertEquals(2, result.getDeptIds().size()); + assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); + } + } + + @Test + public void testGetDeptDataPermission_Self() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) + .thenReturn(permissionService); + + // 准备参数 + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); + + // 调用 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); + // 断言 + assertFalse(result.getAll()); + assertTrue(result.getSelf()); + assertTrue(CollUtil.isEmpty(result.getDeptIds())); + } + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java new file mode 100644 index 0000000..51c1de6 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java @@ -0,0 +1,371 @@ +package cn.iocoder.yudao.module.system.service.permission; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; + +@Import(RoleServiceImpl.class) +public class RoleServiceImplTest extends BaseDbUnitTest { + + @Resource + private RoleServiceImpl roleService; + + @Resource + private RoleMapper roleMapper; + + @MockBean + private PermissionService permissionService; + + @Test + public void testCreateRole() { + // 准备参数 + RoleSaveReqVO reqVO = randomPojo(RoleSaveReqVO.class) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long roleId = roleService.createRole(reqVO, null); + // 断言 + RoleDO roleDO = roleMapper.selectById(roleId); + assertPojoEquals(reqVO, roleDO, "id"); + assertEquals(RoleTypeEnum.CUSTOM.getType(), roleDO.getType()); + assertEquals(CommonStatusEnum.ENABLE.getStatus(), roleDO.getStatus()); + assertEquals(DataScopeEnum.ALL.getScope(), roleDO.getDataScope()); + } + + @Test + public void testUpdateRole() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); + roleMapper.insert(roleDO); + // 准备参数 + Long id = roleDO.getId(); + RoleSaveReqVO reqVO = randomPojo(RoleSaveReqVO.class, o -> o.setId(id)); + + // 调用 + roleService.updateRole(reqVO); + // 断言 + RoleDO newRoleDO = roleMapper.selectById(id); + assertPojoEquals(reqVO, newRoleDO); + } + + @Test + public void testUpdateRoleDataScope() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); + roleMapper.insert(roleDO); + // 准备参数 + Long id = roleDO.getId(); + Integer dataScope = randomEle(DataScopeEnum.values()).getScope(); + Set dataScopeRoleIds = randomSet(Long.class); + + // 调用 + roleService.updateRoleDataScope(id, dataScope, dataScopeRoleIds); + // 断言 + RoleDO dbRoleDO = roleMapper.selectById(id); + assertEquals(dataScope, dbRoleDO.getDataScope()); + assertEquals(dataScopeRoleIds, dbRoleDO.getDataScopeDeptIds()); + } + + @Test + public void testDeleteRole() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); + roleMapper.insert(roleDO); + // 参数准备 + Long id = roleDO.getId(); + + // 调用 + roleService.deleteRole(id); + // 断言 + assertNull(roleMapper.selectById(id)); + // verify 删除相关数据 + verify(permissionService).processRoleDeleted(id); + } + + @Test + public void testValidateRoleDuplicate_success() { + // 调用,不会抛异常 + roleService.validateRoleDuplicate(randomString(), randomString(), null); + } + + @Test + public void testValidateRoleDuplicate_nameDuplicate() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setName("role_name")); + roleMapper.insert(roleDO); + // 准备参数 + String name = "role_name"; + + // 调用,并断言异常 + assertServiceException(() -> roleService.validateRoleDuplicate(name, randomString(), null), + ROLE_NAME_DUPLICATE, name); + } + + @Test + public void testValidateRoleDuplicate_codeDuplicate() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setCode("code")); + roleMapper.insert(roleDO); + // 准备参数 + String code = "code"; + + // 调用,并断言异常 + assertServiceException(() -> roleService.validateRoleDuplicate(randomString(), code, null), + ROLE_CODE_DUPLICATE, code); + } + + @Test + public void testValidateUpdateRole_success() { + RoleDO roleDO = randomPojo(RoleDO.class); + roleMapper.insert(roleDO); + // 准备参数 + Long id = roleDO.getId(); + + // 调用,无异常 + roleService.validateRoleForUpdate(id); + } + + @Test + public void testValidateUpdateRole_roleIdNotExist() { + assertServiceException(() -> roleService.validateRoleForUpdate(randomLongId()), ROLE_NOT_EXISTS); + } + + @Test + public void testValidateUpdateRole_systemRoleCanNotBeUpdate() { + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.SYSTEM.getType())); + roleMapper.insert(roleDO); + // 准备参数 + Long id = roleDO.getId(); + + assertServiceException(() -> roleService.validateRoleForUpdate(id), + ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); + } + + @Test + public void testGetRole() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class); + roleMapper.insert(roleDO); + // 参数准备 + Long id = roleDO.getId(); + + // 调用 + RoleDO dbRoleDO = roleService.getRole(id); + // 断言 + assertPojoEquals(roleDO, dbRoleDO); + } + + @Test + public void testGetRoleFromCache() { + // mock 数据(缓存) + RoleDO roleDO = randomPojo(RoleDO.class); + roleMapper.insert(roleDO); + // 参数准备 + Long id = roleDO.getId(); + + // 调用 + RoleDO dbRoleDO = roleService.getRoleFromCache(id); + // 断言 + assertPojoEquals(roleDO, dbRoleDO); + } + + @Test + public void testGetRoleListByStatus() { + // mock 数据 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + roleMapper.insert(dbRole01); + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + roleMapper.insert(dbRole02); + + // 调用 + List list = roleService.getRoleListByStatus( + singleton(CommonStatusEnum.ENABLE.getStatus())); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbRole01, list.get(0)); + } + + @Test + public void testGetRoleList() { + // mock 数据 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + roleMapper.insert(dbRole01); + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + roleMapper.insert(dbRole02); + + // 调用 + List list = roleService.getRoleList(); + // 断言 + assertEquals(2, list.size()); + assertPojoEquals(dbRole01, list.get(0)); + assertPojoEquals(dbRole02, list.get(1)); + } + + @Test + public void testGetRoleList_ids() { + // mock 数据 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + roleMapper.insert(dbRole01); + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + roleMapper.insert(dbRole02); + // 准备参数 + Collection ids = singleton(dbRole01.getId()); + + // 调用 + List list = roleService.getRoleList(ids); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbRole01, list.get(0)); + } + + @Test + public void testGetRoleListFromCache() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) + .thenReturn(roleService); + + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + roleMapper.insert(dbRole); + // 测试 id 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> {})); + // 准备参数 + Collection ids = singleton(dbRole.getId()); + + // 调用 + List list = roleService.getRoleListFromCache(ids); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbRole, list.get(0)); + } + } + + @Test + public void testGetRolePage() { + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到 + o.setName("土豆"); + o.setCode("tudou"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2022, 2, 8)); + }); + roleMapper.insert(dbRole); + // 测试 name 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯"))); + // 测试 code 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong"))); + // 测试 createTime 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(buildTime(2022, 2, 16)))); + // 准备参数 + RolePageReqVO reqVO = new RolePageReqVO(); + reqVO.setName("土豆"); + reqVO.setCode("tu"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 12)); + + // 调用 + PageResult pageResult = roleService.getRolePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbRole, pageResult.getList().get(0)); + } + + @Test + public void testHasAnySuperAdmin_true() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) + .thenReturn(roleService); + + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class).setCode("super_admin"); + roleMapper.insert(dbRole); + // 准备参数 + Long id = dbRole.getId(); + + // 调用,并调用 + assertTrue(roleService.hasAnySuperAdmin(singletonList(id))); + } + } + + @Test + public void testHasAnySuperAdmin_false() { + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) + .thenReturn(roleService); + + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class).setCode("tenant_admin"); + roleMapper.insert(dbRole); + // 准备参数 + Long id = dbRole.getId(); + + // 调用,并调用 + assertFalse(roleService.hasAnySuperAdmin(singletonList(id))); + } + } + + @Test + public void testValidateRoleList_success() { + // mock 数据 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + roleMapper.insert(roleDO); + // 准备参数 + List ids = singletonList(roleDO.getId()); + + // 调用,无需断言 + roleService.validateRoleList(ids); + } + + @Test + public void testValidateRoleList_notFound() { + // 准备参数 + List ids = singletonList(randomLongId()); + + // 调用, 并断言异常 + assertServiceException(() -> roleService.validateRoleList(ids), ROLE_NOT_EXISTS); + } + + @Test + public void testValidateRoleList_notEnable() { + // mock 数据 + RoleDO RoleDO = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + roleMapper.insert(RoleDO); + // 准备参数 + List ids = singletonList(RoleDO.getId()); + + // 调用, 并断言异常 + assertServiceException(() -> roleService.validateRoleList(ids), ROLE_IS_DISABLE, RoleDO.getName()); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java new file mode 100644 index 0000000..f22701c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java @@ -0,0 +1,236 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@Import(SmsChannelServiceImpl.class) +public class SmsChannelServiceTest extends BaseDbUnitTest { + + @Resource + private SmsChannelServiceImpl smsChannelService; + + @Resource + private SmsChannelMapper smsChannelMapper; + + @MockBean + private SmsClientFactory smsClientFactory; + @MockBean + private SmsTemplateService smsTemplateService; + + @Test + public void testCreateSmsChannel_success() { + // 准备参数 + SmsChannelSaveReqVO reqVO = randomPojo(SmsChannelSaveReqVO.class, o -> o.setStatus(randomCommonStatus())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long smsChannelId = smsChannelService.createSmsChannel(reqVO); + // 断言 + assertNotNull(smsChannelId); + // 校验记录的属性是否正确 + SmsChannelDO smsChannel = smsChannelMapper.selectById(smsChannelId); + assertPojoEquals(reqVO, smsChannel, "id"); + // 断言 cache + assertNull(smsChannelService.getIdClientCache().getIfPresent(smsChannel.getId())); + assertNull(smsChannelService.getCodeClientCache().getIfPresent(smsChannel.getCode())); + } + + @Test + public void testUpdateSmsChannel_success() { + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SmsChannelSaveReqVO reqVO = randomPojo(SmsChannelSaveReqVO.class, o -> { + o.setId(dbSmsChannel.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + o.setCallbackUrl(randomString()); + }); + + // 调用 + smsChannelService.updateSmsChannel(reqVO); + // 校验是否更新正确 + SmsChannelDO smsChannel = smsChannelMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, smsChannel); + // 断言 cache + assertNull(smsChannelService.getIdClientCache().getIfPresent(smsChannel.getId())); + assertNull(smsChannelService.getCodeClientCache().getIfPresent(smsChannel.getCode())); + } + + @Test + public void testUpdateSmsChannel_notExists() { + // 准备参数 + SmsChannelSaveReqVO reqVO = randomPojo(SmsChannelSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> smsChannelService.updateSmsChannel(reqVO), SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testDeleteSmsChannel_success() { + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsChannel.getId(); + + // 调用 + smsChannelService.deleteSmsChannel(id); + // 校验数据不存在了 + assertNull(smsChannelMapper.selectById(id)); + // 断言 cache + assertNull(smsChannelService.getIdClientCache().getIfPresent(dbSmsChannel.getId())); + assertNull(smsChannelService.getCodeClientCache().getIfPresent(dbSmsChannel.getCode())); + } + + @Test + public void testDeleteSmsChannel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> smsChannelService.deleteSmsChannel(id), SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testDeleteSmsChannel_hasChildren() { + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsChannel.getId(); + // mock 方法 + when(smsTemplateService.getSmsTemplateCountByChannelId(eq(id))).thenReturn(10L); + + // 调用, 并断言异常 + assertServiceException(() -> smsChannelService.deleteSmsChannel(id), SMS_CHANNEL_HAS_CHILDREN); + } + + @Test + public void testGetSmsChannel() { + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel); // @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsChannel.getId(); + + // 调用,并断言 + assertPojoEquals(dbSmsChannel, smsChannelService.getSmsChannel(id)); + } + + @Test + public void testGetSmsChannelList() { + // mock 数据 + SmsChannelDO dbSmsChannel01 = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel01); + SmsChannelDO dbSmsChannel02 = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(dbSmsChannel02); + // 准备参数 + + // 调用 + List list = smsChannelService.getSmsChannelList(); + // 断言 + assertEquals(2, list.size()); + assertPojoEquals(dbSmsChannel01, list.get(0)); + assertPojoEquals(dbSmsChannel02, list.get(1)); + } + + @Test + public void testGetSmsChannelPage() { + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到 + o.setSignature("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2020, 12, 12)); + }); + smsChannelMapper.insert(dbSmsChannel); + // 测试 signature 不匹配 + smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码"))); + // 测试 status 不匹配 + smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11)))); + // 准备参数 + SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO(); + reqVO.setSignature("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24)); + + // 调用 + PageResult pageResult = smsChannelService.getSmsChannelPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); + } + + @Test + public void testGetSmsClient_id() { + // mock 数据 + SmsChannelDO channel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(channel); + // mock 参数 + Long id = channel.getId(); + // mock 方法 + SmsClient mockClient = mock(SmsClient.class); + when(smsClientFactory.getSmsClient(eq(id))).thenReturn(mockClient); + + // 调用 + SmsClient client = smsChannelService.getSmsClient(id); + // 断言 + assertSame(client, mockClient); + verify(smsClientFactory).createOrUpdateSmsClient(argThat(arg -> { + SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class); + return properties.equals(arg); + })); + } + + @Test + public void testGetSmsClient_code() { + // mock 数据 + SmsChannelDO channel = randomPojo(SmsChannelDO.class); + smsChannelMapper.insert(channel); + // mock 参数 + String code = channel.getCode(); + // mock 方法 + SmsClient mockClient = mock(SmsClient.class); + when(smsClientFactory.getSmsClient(eq(code))).thenReturn(mockClient); + + // 调用 + SmsClient client = smsChannelService.getSmsClient(code); + // 断言 + assertSame(client, mockClient); + verify(smsClientFactory).createOrUpdateSmsClient(argThat(arg -> { + SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class); + return properties.equals(arg); + })); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java new file mode 100644 index 0000000..fea1419 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsCodeServiceImplTest.java @@ -0,0 +1,209 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import cn.iocoder.yudao.module.system.framework.sms.config.SmsCodeProperties; +import com.baomidou.mybatisplus.annotation.DbType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@Import(SmsCodeServiceImpl.class) +public class SmsCodeServiceImplTest extends BaseDbUnitTest { + + @Resource + private SmsCodeServiceImpl smsCodeService; + + @Resource + private SmsCodeMapper smsCodeMapper; + + @MockBean + private SmsCodeProperties smsCodeProperties; + @MockBean + private SmsSendService smsSendService; + + @BeforeEach + public void setUp() { + when(smsCodeProperties.getExpireTimes()).thenReturn(Duration.ofMinutes(5)); + when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMinutes(1)); + when(smsCodeProperties.getSendMaximumQuantityPerDay()).thenReturn(10); + when(smsCodeProperties.getBeginCode()).thenReturn(9999); + when(smsCodeProperties.getEndCode()).thenReturn(9999); + } + + @Test + public void sendSmsCode_success() { + // 准备参数 + SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene()); + }); + // mock 方法 + SqlConstants.init(DbType.MYSQL); + + // 调用 + smsCodeService.sendSmsCode(reqDTO); + // 断言 code 验证码 + SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null); + assertPojoEquals(reqDTO, smsCodeDO); + assertEquals("9999", smsCodeDO.getCode()); + assertEquals(1, smsCodeDO.getTodayIndex()); + assertFalse(smsCodeDO.getUsed()); + // 断言调用 + verify(smsSendService).sendSingleSms(eq(reqDTO.getMobile()), isNull(), isNull(), + eq("user-sms-login"), eq(MapUtil.of("code", "9999"))); + } + + @Test + public void sendSmsCode_tooFast() { + // mock 数据 + SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class, + o -> o.setMobile("15601691300").setTodayIndex(1)); + smsCodeMapper.insert(smsCodeDO); + // 准备参数 + SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene()); + }); + // mock 方法 + SqlConstants.init(DbType.MYSQL); + + // 调用,并断言异常 + assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO), + SMS_CODE_SEND_TOO_FAST); + } + + @Test + public void sendSmsCode_exceedDay() { + // mock 数据 + SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class, + o -> o.setMobile("15601691300").setTodayIndex(10).setCreateTime(LocalDateTime.now())); + smsCodeMapper.insert(smsCodeDO); + // 准备参数 + SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene()); + }); + // mock 方法 + SqlConstants.init(DbType.MYSQL); + when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMillis(0)); + + // 调用,并断言异常 + assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO), + SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); + } + + @Test + public void testUseSmsCode_success() { + // 准备参数 + SmsCodeUseReqDTO reqDTO = randomPojo(SmsCodeUseReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(randomEle(SmsSceneEnum.values()).getScene()); + }); + // mock 数据 + SqlConstants.init(DbType.MYSQL); + smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> { + o.setMobile(reqDTO.getMobile()).setScene(reqDTO.getScene()) + .setCode(reqDTO.getCode()).setUsed(false); + })); + + // 调用 + smsCodeService.useSmsCode(reqDTO); + // 断言 + SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null); + assertTrue(smsCodeDO.getUsed()); + assertNotNull(smsCodeDO.getUsedTime()); + assertEquals(reqDTO.getUsedIp(), smsCodeDO.getUsedIp()); + } + + @Test + public void validateSmsCode_success() { + // 准备参数 + SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(randomEle(SmsSceneEnum.values()).getScene()); + }); + // mock 数据 + SqlConstants.init(DbType.MYSQL); + smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile()) + .setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false))); + + // 调用 + smsCodeService.validateSmsCode(reqDTO); + } + + @Test + public void validateSmsCode_notFound() { + // 准备参数 + SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(randomEle(SmsSceneEnum.values()).getScene()); + }); + // mock 数据 + SqlConstants.init(DbType.MYSQL); + + // 调用,并断言异常 + assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO), + SMS_CODE_NOT_FOUND); + } + + @Test + public void validateSmsCode_expired() { + // 准备参数 + SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(randomEle(SmsSceneEnum.values()).getScene()); + }); + // mock 数据 + SqlConstants.init(DbType.MYSQL); + smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile()) + .setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false) + .setCreateTime(LocalDateTime.now().minusMinutes(6)))); + + // 调用,并断言异常 + assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO), + SMS_CODE_EXPIRED); + } + + @Test + public void validateSmsCode_used() { + // 准备参数 + SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> { + o.setMobile("15601691300"); + o.setScene(randomEle(SmsSceneEnum.values()).getScene()); + }); + // mock 数据 + SqlConstants.init(DbType.MYSQL); + smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile()) + .setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(true) + .setCreateTime(LocalDateTime.now()))); + + // 调用,并断言异常 + assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO), + SMS_CODE_USED); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImplTest.java new file mode 100644 index 0000000..eed34b9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImplTest.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper; +import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomBoolean; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Import(SmsLogServiceImpl.class) +public class SmsLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private SmsLogServiceImpl smsLogService; + + @Resource + private SmsLogMapper smsLogMapper; + + @Test + public void testGetSmsLogPage() { + // mock 数据 + SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到 + o.setChannelId(1L); + o.setTemplateId(10L); + o.setMobile("15601691300"); + o.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); + o.setSendTime(buildTime(2020, 11, 11)); + o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + o.setReceiveTime(buildTime(2021, 11, 11)); + }); + smsLogMapper.insert(dbSmsLog); + // 测试 channelId 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L))); + // 测试 templateId 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L))); + // 测试 mobile 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999"))); + // 测试 sendStatus 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus()))); + // 测试 sendTime 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12)))); + // 测试 receiveStatus 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus()))); + // 测试 receiveTime 不匹配 + smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12)))); + // 准备参数 + SmsLogPageReqVO reqVO = new SmsLogPageReqVO(); + reqVO.setChannelId(1L); + reqVO.setTemplateId(10L); + reqVO.setMobile("156"); + reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); + reqVO.setSendTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30)); + reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30)); + + // 调用 + PageResult pageResult = smsLogService.getSmsLogPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsLog, pageResult.getList().get(0)); + } + + @Test + public void testCreateSmsLog() { + // 准备参数 + String mobile = randomString(); + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + Boolean isSend = randomBoolean(); + SmsTemplateDO templateDO = randomPojo(SmsTemplateDO.class, + o -> o.setType(randomEle(SmsTemplateTypeEnum.values()).getType())); + String templateContent = randomString(); + Map templateParams = randomTemplateParams(); + // mock 方法 + + // 调用 + Long logId = smsLogService.createSmsLog(mobile, userId, userType, isSend, + templateDO, templateContent, templateParams); + // 断言 + SmsLogDO logDO = smsLogMapper.selectById(logId); + assertEquals(isSend ? SmsSendStatusEnum.INIT.getStatus() : SmsSendStatusEnum.IGNORE.getStatus(), + logDO.getSendStatus()); + assertEquals(mobile, logDO.getMobile()); + assertEquals(userType, logDO.getUserType()); + assertEquals(userId, logDO.getUserId()); + assertEquals(templateDO.getId(), logDO.getTemplateId()); + assertEquals(templateDO.getCode(), logDO.getTemplateCode()); + assertEquals(templateDO.getType(), logDO.getTemplateType()); + assertEquals(templateDO.getChannelId(), logDO.getChannelId()); + assertEquals(templateDO.getChannelCode(), logDO.getChannelCode()); + assertEquals(templateContent, logDO.getTemplateContent()); + assertEquals(templateParams, logDO.getTemplateParams()); + assertEquals(SmsReceiveStatusEnum.INIT.getStatus(), logDO.getReceiveStatus()); + } + + @Test + public void testUpdateSmsSendResult() { + // mock 数据 + SmsLogDO dbSmsLog = randomSmsLogDO( + o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus())); + smsLogMapper.insert(dbSmsLog); + // 准备参数 + Long id = dbSmsLog.getId(); + Boolean success = randomBoolean(); + String apiSendCode = randomString(); + String apiSendMsg = randomString(); + String apiRequestId = randomString(); + String apiSerialNo = randomString(); + + // 调用 + smsLogService.updateSmsSendResult(id, success, + apiSendCode, apiSendMsg, apiRequestId, apiSerialNo); + // 断言 + dbSmsLog = smsLogMapper.selectById(id); + assertEquals(success ? SmsSendStatusEnum.SUCCESS.getStatus() : SmsSendStatusEnum.FAILURE.getStatus(), + dbSmsLog.getSendStatus()); + assertNotNull(dbSmsLog.getSendTime()); + assertEquals(apiSendCode, dbSmsLog.getApiSendCode()); + assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg()); + assertEquals(apiRequestId, dbSmsLog.getApiRequestId()); + assertEquals(apiSerialNo, dbSmsLog.getApiSerialNo()); + } + + @Test + public void testUpdateSmsReceiveResult() { + // mock 数据 + SmsLogDO dbSmsLog = randomSmsLogDO( + o -> o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus())); + smsLogMapper.insert(dbSmsLog); + // 准备参数 + Long id = dbSmsLog.getId(); + Boolean success = randomBoolean(); + LocalDateTime receiveTime = randomLocalDateTime(); + String apiReceiveCode = randomString(); + String apiReceiveMsg = randomString(); + + // 调用 + smsLogService.updateSmsReceiveResult(id, success, receiveTime, apiReceiveCode, apiReceiveMsg); + // 断言 + dbSmsLog = smsLogMapper.selectById(id); + assertEquals(success ? SmsReceiveStatusEnum.SUCCESS.getStatus() + : SmsReceiveStatusEnum.FAILURE.getStatus(), dbSmsLog.getReceiveStatus()); + assertEquals(receiveTime, dbSmsLog.getReceiveTime()); + assertEquals(apiReceiveCode, dbSmsLog.getApiReceiveCode()); + assertEquals(apiReceiveMsg, dbSmsLog.getApiReceiveMsg()); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static SmsLogDO randomSmsLogDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setTemplateParams(randomTemplateParams()); + o.setTemplateType(randomEle(SmsTemplateTypeEnum.values()).getType()); // 保证 templateType 的范围 + o.setUserType(randomEle(UserTypeEnum.values()).getValue()); // 保证 userType 的范围 + o.setSendStatus(randomEle(SmsSendStatusEnum.values()).getStatus()); // 保证 sendStatus 的范围 + o.setReceiveStatus(randomEle(SmsReceiveStatusEnum.values()).getStatus()); // 保证 receiveStatus 的范围 + }; + return randomPojo(SmsLogDO.class, ArrayUtils.append(consumer, consumers)); + } + + private static Map randomTemplateParams() { + return MapUtil.builder().put(randomString(), randomString()) + .put(randomString(), randomString()).build(); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java new file mode 100644 index 0000000..487c6f7 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java @@ -0,0 +1,298 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; +import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; +import cn.iocoder.yudao.module.system.service.member.MemberService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class SmsSendServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private SmsSendServiceImpl smsSendService; + + @Mock + private AdminUserService adminUserService; + @Mock + private MemberService memberService; + @Mock + private SmsChannelService smsChannelService; + @Mock + private SmsTemplateService smsTemplateService; + @Mock + private SmsLogService smsLogService; + @Mock + private SmsProducer smsProducer; + + @Test + public void testSendSingleSmsToAdmin() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock adminUserService 的方法 + AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300")); + when(adminUserService.getUser(eq(userId))).thenReturn(user); + + // mock SmsTemplateService 的方法 + SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock SmsChannelService 的方法 + SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel); + // mock SmsLogService 的方法 + Long smsLogId = randomLongId(); + when(smsLogService.createSmsLog(eq(user.getMobile()), eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(Boolean.TRUE), eq(template), + eq(content), eq(templateParams))).thenReturn(smsLogId); + + // 调用 + Long resultSmsLogId = smsSendService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams); + // 断言 + assertEquals(smsLogId, resultSmsLogId); + // 断言调用 + verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()), + eq(template.getChannelId()), eq(template.getApiTemplateId()), + eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login")))); + } + + @Test + public void testSendSingleSmsToUser() { + // 准备参数 + Long userId = randomLongId(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock memberService 的方法 + String mobile = "15601691300"; + when(memberService.getMemberUserMobile(eq(userId))).thenReturn(mobile); + + // mock SmsTemplateService 的方法 + SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock SmsChannelService 的方法 + SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel); + // mock SmsLogService 的方法 + Long smsLogId = randomLongId(); + when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(Boolean.TRUE), eq(template), + eq(content), eq(templateParams))).thenReturn(smsLogId); + + // 调用 + Long resultSmsLogId = smsSendService.sendSingleSmsToMember(null, userId, templateCode, templateParams); + // 断言 + assertEquals(smsLogId, resultSmsLogId); + // 断言调用 + verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile), + eq(template.getChannelId()), eq(template.getApiTemplateId()), + eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login")))); + } + + /** + * 发送成功,当短信模板开启时 + */ + @Test + public void testSendSingleSms_successWhenSmsTemplateEnable() { + // 准备参数 + String mobile = randomString(); + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock SmsTemplateService 的方法 + SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock SmsChannelService 的方法 + SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel); + // mock SmsLogService 的方法 + Long smsLogId = randomLongId(); + when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.TRUE), eq(template), + eq(content), eq(templateParams))).thenReturn(smsLogId); + + // 调用 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); + // 断言 + assertEquals(smsLogId, resultSmsLogId); + // 断言调用 + verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile), + eq(template.getChannelId()), eq(template.getApiTemplateId()), + eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login")))); + } + + /** + * 发送成功,当短信模板关闭时 + */ + @Test + public void testSendSingleSms_successWhenSmsTemplateDisable() { + // 准备参数 + String mobile = randomString(); + Long userId = randomLongId(); + Integer userType = randomEle(UserTypeEnum.values()).getValue(); + String templateCode = randomString(); + Map templateParams = MapUtil.builder().put("code", "1234") + .put("op", "login").build(); + // mock SmsTemplateService 的方法 + SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> { + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + o.setContent("验证码为{code}, 操作为{op}"); + o.setParams(Lists.newArrayList("code", "op")); + }); + when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); + String content = randomString(); + when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams))) + .thenReturn(content); + // mock SmsChannelService 的方法 + SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel); + // mock SmsLogService 的方法 + Long smsLogId = randomLongId(); + when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.FALSE), eq(template), + eq(content), eq(templateParams))).thenReturn(smsLogId); + + // 调用 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); + // 断言 + assertEquals(smsLogId, resultSmsLogId); + // 断言调用 + verify(smsProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(), + anyLong(), any(), anyList()); + } + + @Test + public void testCheckSmsTemplateValid_notExists() { + // 准备参数 + String templateCode = randomString(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> smsSendService.validateSmsTemplate(templateCode), + SMS_SEND_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testBuildTemplateParams_paramMiss() { + // 准备参数 + SmsTemplateDO template = randomPojo(SmsTemplateDO.class, + o -> o.setParams(Lists.newArrayList("code"))); + Map templateParams = new HashMap<>(); + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> smsSendService.buildTemplateParams(template, templateParams), + SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code"); + } + + @Test + public void testCheckMobile_notExists() { + // 准备参数 + // mock 方法 + + // 调用,并断言异常 + assertServiceException(() -> smsSendService.validateMobile(null), + SMS_SEND_MOBILE_NOT_EXISTS); + } + + @Test + public void testSendBatchNotify() { + // 准备参数 + // mock 方法 + + // 调用 + UnsupportedOperationException exception = Assertions.assertThrows( + UnsupportedOperationException.class, + () -> smsSendService.sendBatchSms(null, null, null, null, null) + ); + // 断言 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage()); + } + + @Test + @SuppressWarnings("unchecked") + public void testDoSendSms() throws Throwable { + // 准备参数 + SmsSendMessage message = randomPojo(SmsSendMessage.class); + // mock SmsClientFactory 的方法 + SmsClient smsClient = spy(SmsClient.class); + when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient); + // mock SmsClient 的方法 + SmsSendRespDTO sendResult = randomPojo(SmsSendRespDTO.class); + when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()), + eq(message.getTemplateParams()))).thenReturn(sendResult); + + // 调用 + smsSendService.doSendSms(message); + // 断言 + verify(smsLogService).updateSmsSendResult(eq(message.getLogId()), + eq(sendResult.getSuccess()), eq(sendResult.getApiCode()), + eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getSerialNo())); + } + + @Test + public void testReceiveSmsStatus() throws Throwable { + // 准备参数 + String channelCode = randomString(); + String text = randomString(); + // mock SmsClientFactory 的方法 + SmsClient smsClient = spy(SmsClient.class); + when(smsChannelService.getSmsClient(eq(channelCode))).thenReturn(smsClient); + // mock SmsClient 的方法 + List receiveResults = randomPojoList(SmsReceiveRespDTO.class); + + // 调用 + smsSendService.receiveSmsStatus(channelCode, text); + // 断言 + receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()), + eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode()))); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java new file mode 100644 index 0000000..5cad481 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java @@ -0,0 +1,348 @@ +package cn.iocoder.yudao.module.system.service.sms; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; +import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; +import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@Import(SmsTemplateServiceImpl.class) +public class SmsTemplateServiceImplTest extends BaseDbUnitTest { + + @Resource + private SmsTemplateServiceImpl smsTemplateService; + + @Resource + private SmsTemplateMapper smsTemplateMapper; + + @MockBean + private SmsChannelService smsChannelService; + @MockBean + private SmsClient smsClient; + + @Test + public void testFormatSmsTemplateContent() { + // 准备参数 + String content = "正在进行登录操作{operation},您的验证码是{code}"; + Map params = MapUtil.builder("operation", "登录") + .put("code", "1234").build(); + + // 调用 + String result = smsTemplateService.formatSmsTemplateContent(content, params); + // 断言 + assertEquals("正在进行登录操作登录,您的验证码是1234", result); + } + + @Test + public void testParseTemplateContentParams() { + // 准备参数 + String content = "正在进行登录操作{operation},您的验证码是{code}"; + // mock 方法 + + // 调用 + List params = smsTemplateService.parseTemplateContentParams(content); + // 断言 + assertEquals(Lists.newArrayList("operation", "code"), params); + } + + @Test + @SuppressWarnings("unchecked") + public void testCreateSmsTemplate_success() throws Throwable { + // 准备参数 + SmsTemplateSaveReqVO reqVO = randomPojo(SmsTemplateSaveReqVO.class, o -> { + o.setContent("正在进行登录操作{operation},您的验证码是{code}"); + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围 + }).setId(null); // 防止 id 被赋值 + // mock Channel 的方法 + SmsChannelDO channelDO = randomPojo(SmsChannelDO.class, o -> { + o.setId(reqVO.getChannelId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); + // mock 获得 API 短信模板成功 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn( + randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()))); + + // 调用 + Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); + // 断言 + assertNotNull(smsTemplateId); + // 校验记录的属性是否正确 + SmsTemplateDO smsTemplate = smsTemplateMapper.selectById(smsTemplateId); + assertPojoEquals(reqVO, smsTemplate, "id"); + assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); + assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); + } + + @Test + @SuppressWarnings("unchecked") + public void testUpdateSmsTemplate_success() throws Throwable { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SmsTemplateSaveReqVO reqVO = randomPojo(SmsTemplateSaveReqVO.class, o -> { + o.setId(dbSmsTemplate.getId()); // 设置更新的 ID + o.setContent("正在进行登录操作{operation},您的验证码是{code}"); + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围 + }); + // mock 方法 + SmsChannelDO channelDO = randomPojo(SmsChannelDO.class, o -> { + o.setId(reqVO.getChannelId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); + // mock 获得 API 短信模板成功 + when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn( + randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()))); + + // 调用 + smsTemplateService.updateSmsTemplate(reqVO); + // 校验是否更新正确 + SmsTemplateDO smsTemplate = smsTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, smsTemplate); + assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); + assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); + } + + @Test + public void testUpdateSmsTemplate_notExists() { + // 准备参数 + SmsTemplateSaveReqVO reqVO = randomPojo(SmsTemplateSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> smsTemplateService.updateSmsTemplate(reqVO), SMS_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteSmsTemplate_success() { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsTemplate.getId(); + + // 调用 + smsTemplateService.deleteSmsTemplate(id); + // 校验数据不存在了 + assertNull(smsTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteSmsTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> smsTemplateService.deleteSmsTemplate(id), SMS_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testGetSmsTemplate() { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsTemplate.getId(); + + // 调用 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplate(id); + // 校验 + assertPojoEquals(dbSmsTemplate, smsTemplate); + } + + @Test + public void testGetSmsTemplateByCodeFromCache() { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + String code = dbSmsTemplate.getCode(); + + // 调用 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplateByCodeFromCache(code); + // 校验 + assertPojoEquals(dbSmsTemplate, smsTemplate); + } + + @Test + public void testGetSmsTemplatePage() { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 + o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCode("tudou"); + o.setContent("芋道源码"); + o.setApiTemplateId("yunai"); + o.setChannelId(1L); + o.setCreateTime(buildTime(2021, 11, 11)); + }); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 type 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); + // 测试 status 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 code 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); + // 测试 content 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); + // 测试 apiTemplateId 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); + // 测试 createTime 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); + // 准备参数 + SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); + reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCode("tu"); + reqVO.setContent("芋道"); + reqVO.setApiTemplateId("yu"); + reqVO.setChannelId(1L); + reqVO.setCreateTime(buildBetweenTime(2021, 11, 1, 2021, 12, 1)); + + // 调用 + PageResult pageResult = smsTemplateService.getSmsTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); + } + + @Test + public void testGetSmsTemplateCountByChannelId() { + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> o.setChannelId(1L)); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); + // 准备参数 + Long channelId = 1L; + + // 调用 + Long count = smsTemplateService.getSmsTemplateCountByChannelId(channelId); + // 断言 + assertEquals(1, count); + } + + @Test + public void testValidateSmsChannel_success() { + // 准备参数 + Long channelId = randomLongId(); + // mock 方法 + SmsChannelDO channelDO = randomPojo(SmsChannelDO.class, o -> { + o.setId(channelId); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelId))).thenReturn(channelDO); + + // 调用 + SmsChannelDO returnChannelDO = smsTemplateService.validateSmsChannel(channelId); + // 断言 + assertPojoEquals(returnChannelDO, channelDO); + } + + @Test + public void testValidateSmsChannel_notExists() { + // 准备参数 + Long channelId = randomLongId(); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.validateSmsChannel(channelId), + SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testValidateSmsChannel_disable() { + // 准备参数 + Long channelId = randomLongId(); + // mock 方法 + SmsChannelDO channelDO = randomPojo(SmsChannelDO.class, o -> { + o.setId(channelId); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); // 保证 status 禁用,触发失败 + }); + when(smsChannelService.getSmsChannel(eq(channelId))).thenReturn(channelDO); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.validateSmsChannel(channelId), + SMS_CHANNEL_DISABLE); + } + + @Test + public void testValidateDictDataValueUnique_success() { + // 调用,成功 + smsTemplateService.validateSmsTemplateCodeDuplicate(randomLongId(), randomString()); + } + + @Test + public void testValidateSmsTemplateCodeDuplicate_valueDuplicateForCreate() { + // 准备参数 + String code = randomString(); + // mock 数据 + smsTemplateMapper.insert(randomSmsTemplateDO(o -> o.setCode(code))); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.validateSmsTemplateCodeDuplicate(null, code), + SMS_TEMPLATE_CODE_DUPLICATE, code); + } + + @Test + public void testValidateDictDataValueUnique_valueDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String code = randomString(); + // mock 数据 + smsTemplateMapper.insert(randomSmsTemplateDO(o -> o.setCode(code))); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.validateSmsTemplateCodeDuplicate(id, code), + SMS_TEMPLATE_CODE_DUPLICATE, code); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static SmsTemplateDO randomSmsTemplateDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围 + }; + return randomPojo(SmsTemplateDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java new file mode 100644 index 0000000..7e094d8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java @@ -0,0 +1,472 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.WxMaUserService; +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import com.xingyuv.jushauth.config.AuthConfig; +import com.xingyuv.jushauth.model.AuthResponse; +import com.xingyuv.jushauth.model.AuthUser; +import com.xingyuv.jushauth.request.AuthDefaultRequest; +import com.xingyuv.jushauth.request.AuthRequest; +import com.xingyuv.jushauth.utils.AuthStateUtils; +import com.xingyuv.justauth.AuthRequestFactory; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.core.StringRedisTemplate; + +import javax.annotation.Resource; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link SocialClientServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(SocialClientServiceImpl.class) +public class SocialClientServiceImplTest extends BaseDbUnitTest { + + @Resource + private SocialClientServiceImpl socialClientService; + + @Resource + private SocialClientMapper socialClientMapper; + + @MockBean + private AuthRequestFactory authRequestFactory; + + @MockBean + private WxMpService wxMpService; + @MockBean + private WxMpProperties wxMpProperties; + @MockBean + private StringRedisTemplate stringRedisTemplate; + @MockBean + private WxMaService wxMaService; + @MockBean + private WxMaProperties wxMaProperties; + + @Test + public void testGetAuthorizeUrl() { + try (MockedStatic authStateUtilsMock = mockStatic(AuthStateUtils.class)) { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String redirectUri = "sss"; + // mock 获得对应的 AuthRequest 实现 + AuthRequest authRequest = mock(AuthRequest.class); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + // mock 方法 + authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman"); + when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy"); + + // 调用 + String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri); + // 断言 + assertEquals("https://www.iocoder.cn?redirect_uri=sss", url); + } + } + + @Test + public void testAuthSocialUser_success() { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String code = randomString(); + String state = randomString(); + // mock 方法(AuthRequest) + AuthRequest authRequest = mock(AuthRequest.class); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + // mock 方法(AuthResponse) + AuthUser authUser = randomPojo(AuthUser.class); + AuthResponse authResponse = new AuthResponse<>(2000, null, authUser); + when(authRequest.login(argThat(authCallback -> { + assertEquals(code, authCallback.getCode()); + assertEquals(state, authCallback.getState()); + return true; + }))).thenReturn(authResponse); + + // 调用 + AuthUser result = socialClientService.getAuthUser(socialType, userType, code, state); + // 断言 + assertSame(authUser, result); + } + + @Test + public void testAuthSocialUser_fail() { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String code = randomString(); + String state = randomString(); + // mock 方法(AuthRequest) + AuthRequest authRequest = mock(AuthRequest.class); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + // mock 方法(AuthResponse) + AuthResponse authResponse = new AuthResponse<>(0, "模拟失败", null); + when(authRequest.login(argThat(authCallback -> { + assertEquals(code, authCallback.getCode()); + assertEquals(state, authCallback.getState()); + return true; + }))).thenReturn(authResponse); + + // 调用并断言 + assertServiceException( + () -> socialClientService.getAuthUser(socialType, userType, code, state), + SOCIAL_USER_AUTH_FAILURE, "模拟失败"); + } + + @Test + public void testBuildAuthRequest_clientNull() { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(SocialTypeEnum.class).getType(); + // mock 获得对应的 AuthRequest 实现 + AuthRequest authRequest = mock(AuthDefaultRequest.class); + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config"); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + + // 调用 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); + // 断言 + assertSame(authRequest, result); + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config")); + } + + @Test + public void testBuildAuthRequest_clientDisable() { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(SocialTypeEnum.class).getType(); + // mock 获得对应的 AuthRequest 实现 + AuthRequest authRequest = mock(AuthDefaultRequest.class); + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config"); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) + .setUserType(userType).setSocialType(socialType)); + socialClientMapper.insert(client); + + // 调用 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); + // 断言 + assertSame(authRequest, result); + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config")); + } + + @Test + public void testBuildAuthRequest_clientEnable() { + // 准备参数 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); + Integer userType = randomPojo(SocialTypeEnum.class).getType(); + // mock 获得对应的 AuthRequest 实现 + AuthConfig authConfig = mock(AuthConfig.class); + AuthRequest authRequest = mock(AuthDefaultRequest.class); + ReflectUtil.setFieldValue(authRequest, "config", authConfig); + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setUserType(userType).setSocialType(socialType)); + socialClientMapper.insert(client); + + // 调用 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); + // 断言 + assertSame(authRequest, result); + assertNotSame(authConfig, ReflectUtil.getFieldValue(authRequest, "config")); + } + + // =================== 微信公众号独有 =================== + + @Test + public void testCreateWxMpJsapiSignature() throws WxErrorException { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String url = randomString(); + // mock 方法 + WxJsapiSignature signature = randomPojo(WxJsapiSignature.class); + when(wxMpService.createJsapiSignature(eq(url))).thenReturn(signature); + + // 调用 + WxJsapiSignature result = socialClientService.createWxMpJsapiSignature(userType, url); + // 断言 + assertSame(signature, result); + } + + @Test + public void testGetWxMpService_clientNull() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 方法 + + // 调用 + WxMpService result = socialClientService.getWxMpService(userType); + // 断言 + assertSame(wxMpService, result); + } + + @Test + public void testGetWxMpService_clientDisable() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType())); + socialClientMapper.insert(client); + + // 调用 + WxMpService result = socialClientService.getWxMpService(userType); + // 断言 + assertSame(wxMpService, result); + } + + @Test + public void testGetWxMpService_clientEnable() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType())); + socialClientMapper.insert(client); + // mock 方法 + WxMpProperties.ConfigStorage configStorage = mock(WxMpProperties.ConfigStorage.class); + when(wxMpProperties.getConfigStorage()).thenReturn(configStorage); + + // 调用 + WxMpService result = socialClientService.getWxMpService(userType); + // 断言 + assertNotSame(wxMpService, result); + assertEquals(client.getClientId(), result.getWxMpConfigStorage().getAppId()); + assertEquals(client.getClientSecret(), result.getWxMpConfigStorage().getSecret()); + } + + // =================== 微信小程序独有 =================== + + @Test + public void testGetWxMaPhoneNumberInfo_success() throws WxErrorException { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String phoneCode = randomString(); + // mock 方法 + WxMaUserService userService = mock(WxMaUserService.class); + when(wxMaService.getUserService()).thenReturn(userService); + WxMaPhoneNumberInfo phoneNumber = randomPojo(WxMaPhoneNumberInfo.class); + when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber); + + // 调用 + WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode); + // 断言 + assertSame(phoneNumber, result); + } + + @Test + public void testGetWxMaPhoneNumberInfo_exception() throws WxErrorException { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + String phoneCode = randomString(); + // mock 方法 + WxMaUserService userService = mock(WxMaUserService.class); + when(wxMaService.getUserService()).thenReturn(userService); + WxErrorException wxErrorException = randomPojo(WxErrorException.class); + when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException); + + // 调用并断言异常 + assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode), + SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR); + } + + @Test + public void testGetWxMaService_clientNull() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 方法 + + // 调用 + WxMaService result = socialClientService.getWxMaService(userType); + // 断言 + assertSame(wxMaService, result); + } + + @Test + public void testGetWxMaService_clientDisable() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())); + socialClientMapper.insert(client); + + // 调用 + WxMaService result = socialClientService.getWxMaService(userType); + // 断言 + assertSame(wxMaService, result); + } + + @Test + public void testGetWxMaService_clientEnable() { + // 准备参数 + Integer userType = randomPojo(UserTypeEnum.class).getValue(); + // mock 数据 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())); + socialClientMapper.insert(client); + // mock 方法 + WxMaProperties.ConfigStorage configStorage = mock(WxMaProperties.ConfigStorage.class); + when(wxMaProperties.getConfigStorage()).thenReturn(configStorage); + + // 调用 + WxMaService result = socialClientService.getWxMaService(userType); + // 断言 + assertNotSame(wxMaService, result); + assertEquals(client.getClientId(), result.getWxMaConfig().getAppid()); + assertEquals(client.getClientSecret(), result.getWxMaConfig().getSecret()); + } + + // =================== 客户端管理 =================== + + @Test + public void testCreateSocialClient_success() { + // 准备参数 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, + o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType()) + .setUserType(randomEle(UserTypeEnum.values()).getValue()) + .setStatus(randomCommonStatus())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long socialClientId = socialClientService.createSocialClient(reqVO); + // 断言 + assertNotNull(socialClientId); + // 校验记录的属性是否正确 + SocialClientDO socialClient = socialClientMapper.selectById(socialClientId); + assertPojoEquals(reqVO, socialClient, "id"); + } + + @Test + public void testUpdateSocialClient_success() { + // mock 数据 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> { + o.setId(dbSocialClient.getId()); // 设置更新的 ID + o.setSocialType(randomEle(SocialTypeEnum.values()).getType()) + .setUserType(randomEle(UserTypeEnum.values()).getValue()) + .setStatus(randomCommonStatus()); + }); + + // 调用 + socialClientService.updateSocialClient(reqVO); + // 校验是否更新正确 + SocialClientDO socialClient = socialClientMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, socialClient); + } + + @Test + public void testUpdateSocialClient_notExists() { + // 准备参数 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> socialClientService.updateSocialClient(reqVO), SOCIAL_CLIENT_NOT_EXISTS); + } + + @Test + public void testDeleteSocialClient_success() { + // mock 数据 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSocialClient.getId(); + + // 调用 + socialClientService.deleteSocialClient(id); + // 校验数据不存在了 + assertNull(socialClientMapper.selectById(id)); + } + + @Test + public void testDeleteSocialClient_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> socialClientService.deleteSocialClient(id), SOCIAL_CLIENT_NOT_EXISTS); + } + + @Test + public void testGetSocialClient() { + // mock 数据 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSocialClient.getId(); + + // 调用 + SocialClientDO socialClient = socialClientService.getSocialClient(id); + // 校验数据正确 + assertPojoEquals(dbSocialClient, socialClient); + } + + @Test + public void testGetSocialClientPage() { + // mock 数据 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到 + o.setName("芋头"); + o.setSocialType(SocialTypeEnum.GITEE.getType()); + o.setUserType(UserTypeEnum.ADMIN.getValue()); + o.setClientId("yudao"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + socialClientMapper.insert(dbSocialClient); + // 测试 name 不匹配 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString()))); + // 测试 socialType 不匹配 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType()))); + // 测试 userType 不匹配 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); + // 测试 clientId 不匹配 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao"))); + // 测试 status 不匹配 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 准备参数 + SocialClientPageReqVO reqVO = new SocialClientPageReqVO(); + reqVO.setName("芋"); + reqVO.setSocialType(SocialTypeEnum.GITEE.getType()); + reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); + reqVO.setClientId("yu"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 调用 + PageResult pageResult = socialClientService.getSocialClientPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSocialClient, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java new file mode 100644 index 0000000..c3e7538 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java @@ -0,0 +1,288 @@ +package cn.iocoder.yudao.module.system.service.social; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; +import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; +import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import com.xingyuv.jushauth.model.AuthUser; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.hutool.core.util.RandomUtil.randomLong; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.when; + +/** + * {@link SocialUserServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(SocialUserServiceImpl.class) +public class SocialUserServiceImplTest extends BaseDbUnitTest { + + @Resource + private SocialUserServiceImpl socialUserService; + + @Resource + private SocialUserMapper socialUserMapper; + @Resource + private SocialUserBindMapper socialUserBindMapper; + + @MockBean + private SocialClientService socialClientService; + + @Test + public void testGetSocialUserList() { + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + // mock 获得社交用户 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(SocialTypeEnum.GITEE.getType()); + socialUserMapper.insert(socialUser); // 可被查到 + socialUserMapper.insert(randomPojo(SocialUserDO.class)); // 不可被查到 + // mock 获得绑定 + socialUserBindMapper.insert(randomPojo(SocialUserBindDO.class) // 可被查询到 + .setUserId(userId).setUserType(userType).setSocialType(SocialTypeEnum.GITEE.getType()) + .setSocialUserId(socialUser.getId())); + socialUserBindMapper.insert(randomPojo(SocialUserBindDO.class) // 不可被查询到 + .setUserId(2L).setUserType(userType).setSocialType(SocialTypeEnum.DINGTALK.getType())); + + // 调用 + List result = socialUserService.getSocialUserList(userId, userType); + // 断言 + assertEquals(1, result.size()); + assertPojoEquals(socialUser, result.get(0)); + } + + @Test + public void testBindSocialUser() { + // 准备参数 + SocialUserBindReqDTO reqDTO = new SocialUserBindReqDTO() + .setUserId(1L).setUserType(UserTypeEnum.ADMIN.getValue()) + .setSocialType(SocialTypeEnum.GITEE.getType()).setCode("test_code").setState("test_state"); + // mock 数据:获得社交用户 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(reqDTO.getSocialType()) + .setCode(reqDTO.getCode()).setState(reqDTO.getState()); + socialUserMapper.insert(socialUser); + // mock 数据:用户可能之前已经绑定过该社交类型 + socialUserBindMapper.insert(randomPojo(SocialUserBindDO.class).setUserId(1L).setUserType(UserTypeEnum.ADMIN.getValue()) + .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(-1L)); + // mock 数据:社交用户可能之前绑定过别的用户 + socialUserBindMapper.insert(randomPojo(SocialUserBindDO.class).setUserType(UserTypeEnum.ADMIN.getValue()) + .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(socialUser.getId())); + + // 调用 + String openid = socialUserService.bindSocialUser(reqDTO); + // 断言 + List socialUserBinds = socialUserBindMapper.selectList(); + assertEquals(1, socialUserBinds.size()); + assertEquals(socialUser.getOpenid(), openid); + } + + @Test + public void testUnbindSocialUser_success() { + // 准备参数 + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + Integer type = SocialTypeEnum.GITEE.getType(); + String openid = "test_openid"; + // mock 数据:社交用户 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(type).setOpenid(openid); + socialUserMapper.insert(socialUser); + // mock 数据:社交绑定关系 + SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType) + .setUserId(userId).setSocialType(type); + socialUserBindMapper.insert(socialUserBind); + + // 调用 + socialUserService.unbindSocialUser(userId, userType, type, openid); + // 断言 + assertEquals(0, socialUserBindMapper.selectCount(null).intValue()); + } + + @Test + public void testUnbindSocialUser_notFound() { + // 调用,并断言 + assertServiceException( + () -> socialUserService.unbindSocialUser(randomLong(), UserTypeEnum.ADMIN.getValue(), + SocialTypeEnum.GITEE.getType(), "test_openid"), + SOCIAL_USER_NOT_FOUND); + } + + @Test + public void testGetSocialUser() { + // 准备参数 + Integer userType = UserTypeEnum.ADMIN.getValue(); + Integer type = SocialTypeEnum.GITEE.getType(); + String code = "tudou"; + String state = "yuanma"; + // mock 社交用户 + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state); + socialUserMapper.insert(socialUserDO); + // mock 社交用户的绑定 + Long userId = randomLong(); + SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType).setUserId(userId) + .setSocialType(type).setSocialUserId(socialUserDO.getId()); + socialUserBindMapper.insert(socialUserBind); + + // 调用 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(userType, type, code, state); + // 断言 + assertEquals(userId, socialUser.getUserId()); + assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); + } + + @Test + public void testAuthSocialUser_exists() { + // 准备参数 + Integer socialType = SocialTypeEnum.GITEE.getType(); + Integer userType = randomEle(SocialTypeEnum.values()).getType(); + String code = "tudou"; + String state = "yuanma"; + // mock 方法 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state); + socialUserMapper.insert(socialUser); + + // 调用 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state); + // 断言 + assertPojoEquals(socialUser, result); + } + + @Test + public void testAuthSocialUser_notNull() { + // mock 数据 + SocialUserDO socialUser = randomPojo(SocialUserDO.class, + o -> o.setType(SocialTypeEnum.GITEE.getType()).setCode("tudou").setState("yuanma")); + socialUserMapper.insert(socialUser); + // 准备参数 + Integer socialType = SocialTypeEnum.GITEE.getType(); + Integer userType = randomEle(SocialTypeEnum.values()).getType(); + String code = "tudou"; + String state = "yuanma"; + + // 调用 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state); + // 断言 + assertPojoEquals(socialUser, result); + } + + @Test + public void testAuthSocialUser_insert() { + // 准备参数 + Integer socialType = SocialTypeEnum.GITEE.getType(); + Integer userType = randomEle(SocialTypeEnum.values()).getType(); + String code = "tudou"; + String state = "yuanma"; + // mock 方法 + AuthUser authUser = randomPojo(AuthUser.class); + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser); + + // 调用 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state); + // 断言 + assertBindSocialUser(socialType, result, authUser); + assertEquals(code, result.getCode()); + assertEquals(state, result.getState()); + } + + @Test + public void testAuthSocialUser_update() { + // 准备参数 + Integer socialType = SocialTypeEnum.GITEE.getType(); + Integer userType = randomEle(SocialTypeEnum.values()).getType(); + String code = "tudou"; + String state = "yuanma"; + // mock 数据 + socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid")); + // mock 方法 + AuthUser authUser = randomPojo(AuthUser.class); + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser); + + // 调用 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state); + // 断言 + assertBindSocialUser(socialType, result, authUser); + assertEquals(code, result.getCode()); + assertEquals(state, result.getState()); + } + + private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) { + assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken()); + assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo()); + assertEquals(authUser.getNickname(), socialUser.getNickname()); + assertEquals(authUser.getAvatar(), socialUser.getAvatar()); + assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo()); + assertEquals(type, socialUser.getType()); + assertEquals(authUser.getUuid(), socialUser.getOpenid()); + } + + @Test + public void testGetSocialUser_id() { + // mock 数据 + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class); + socialUserMapper.insert(socialUserDO); + // 参数准备 + Long id = socialUserDO.getId(); + + // 调用 + SocialUserDO dbSocialUserDO = socialUserService.getSocialUser(id); + // 断言 + assertPojoEquals(socialUserDO, dbSocialUserDO); + } + + @Test + public void testGetSocialUserPage() { + // mock 数据 + SocialUserDO dbSocialUser = randomPojo(SocialUserDO.class, o -> { // 等会查询到 + o.setType(SocialTypeEnum.GITEE.getType()); + o.setNickname("芋艿"); + o.setOpenid("yudaoyuanma"); + o.setCreateTime(buildTime(2020, 1, 15)); + }); + socialUserMapper.insert(dbSocialUser); + // 测试 type 不匹配 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setType(SocialTypeEnum.DINGTALK.getType()))); + // 测试 nickname 不匹配 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setNickname(randomString()))); + // 测试 openid 不匹配 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setOpenid("java"))); + // 测试 createTime 不匹配 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setCreateTime(buildTime(2020, 1, 21)))); + // 准备参数 + SocialUserPageReqVO reqVO = new SocialUserPageReqVO(); + reqVO.setType(SocialTypeEnum.GITEE.getType()); + reqVO.setNickname("芋"); + reqVO.setOpenid("yudao"); + reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20)); + + // 调用 + PageResult pageResult = socialUserService.getSocialUserPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSocialUser, pageResult.getList().get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java new file mode 100644 index 0000000..ab4784b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java @@ -0,0 +1,236 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** +* {@link TenantPackageServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(TenantPackageServiceImpl.class) +public class TenantPackageServiceImplTest extends BaseDbUnitTest { + + @Resource + private TenantPackageServiceImpl tenantPackageService; + + @Resource + private TenantPackageMapper tenantPackageMapper; + + @MockBean + private TenantService tenantService; + + @Test + public void testCreateTenantPackage_success() { + // 准备参数 + TenantPackageSaveReqVO reqVO = randomPojo(TenantPackageSaveReqVO.class, + o -> o.setStatus(randomCommonStatus())) + .setId(null); // 防止 id 被赋值 + + // 调用 + Long tenantPackageId = tenantPackageService.createTenantPackage(reqVO); + // 断言 + assertNotNull(tenantPackageId); + // 校验记录的属性是否正确 + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(tenantPackageId); + assertPojoEquals(reqVO, tenantPackage, "id"); + } + + @Test + public void testUpdateTenantPackage_success() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setStatus(randomCommonStatus())); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + // 准备参数 + TenantPackageSaveReqVO reqVO = randomPojo(TenantPackageSaveReqVO.class, o -> { + o.setId(dbTenantPackage.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + // mock 方法 + Long tenantId01 = randomLongId(); + Long tenantId02 = randomLongId(); + when(tenantService.getTenantListByPackageId(eq(reqVO.getId()))).thenReturn( + asList(randomPojo(TenantDO.class, o -> o.setId(tenantId01)), + randomPojo(TenantDO.class, o -> o.setId(tenantId02)))); + + // 调用 + tenantPackageService.updateTenantPackage(reqVO); + // 校验是否更新正确 + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, tenantPackage); + // 校验调用租户的菜单 + verify(tenantService).updateTenantRoleMenu(eq(tenantId01), eq(reqVO.getMenuIds())); + verify(tenantService).updateTenantRoleMenu(eq(tenantId02), eq(reqVO.getMenuIds())); + } + + @Test + public void testUpdateTenantPackage_notExists() { + // 准备参数 + TenantPackageSaveReqVO reqVO = randomPojo(TenantPackageSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> tenantPackageService.updateTenantPackage(reqVO), TENANT_PACKAGE_NOT_EXISTS); + } + + @Test + public void testDeleteTenantPackage_success() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenantPackage.getId(); + // mock 租户未使用该套餐 + when(tenantService.getTenantCountByPackageId(eq(id))).thenReturn(0L); + + // 调用 + tenantPackageService.deleteTenantPackage(id); + // 校验数据不存在了 + assertNull(tenantPackageMapper.selectById(id)); + } + + @Test + public void testDeleteTenantPackage_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> tenantPackageService.deleteTenantPackage(id), TENANT_PACKAGE_NOT_EXISTS); + } + + @Test + public void testDeleteTenantPackage_used() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenantPackage.getId(); + // mock 租户在使用该套餐 + when(tenantService.getTenantCountByPackageId(eq(id))).thenReturn(1L); + + // 调用, 并断言异常 + assertServiceException(() -> tenantPackageService.deleteTenantPackage(id), TENANT_PACKAGE_USED); + } + + @Test + public void testGetTenantPackagePage() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("源码解析"); + o.setCreateTime(buildTime(2022, 10, 10)); + }); + tenantPackageMapper.insert(dbTenantPackage); + // 测试 name 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setName("源码"))); + // 测试 status 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 remark 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setRemark("解析"))); + // 测试 createTime 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setCreateTime(buildTime(2022, 11, 11)))); + // 准备参数 + TenantPackagePageReqVO reqVO = new TenantPackagePageReqVO(); + reqVO.setName("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("源码"); + reqVO.setCreateTime(buildBetweenTime(2022, 10, 9, 2022, 10, 11)); + + // 调用 + PageResult pageResult = tenantPackageService.getTenantPackagePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbTenantPackage, pageResult.getList().get(0)); + } + + @Test + public void testValidTenantPackage_success() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + + // 调用 + TenantPackageDO result = tenantPackageService.validTenantPackage(dbTenantPackage.getId()); + // 断言 + assertPojoEquals(dbTenantPackage, result); + } + + @Test + public void testValidTenantPackage_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> tenantPackageService.validTenantPackage(id), TENANT_PACKAGE_NOT_EXISTS); + } + + @Test + public void testValidTenantPackage_disable() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + + // 调用, 并断言异常 + assertServiceException(() -> tenantPackageService.validTenantPackage(dbTenantPackage.getId()), + TENANT_PACKAGE_DISABLE, dbTenantPackage.getName()); + } + + @Test + public void testGetTenantPackage() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class); + tenantPackageMapper.insert(dbTenantPackage);// @Sql: 先插入出一条存在的数据 + + // 调用 + TenantPackageDO result = tenantPackageService.getTenantPackage(dbTenantPackage.getId()); + // 断言 + assertPojoEquals(result, dbTenantPackage); + } + + @Test + public void testGetTenantPackageListByStatus() { + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); + tenantPackageMapper.insert(dbTenantPackage); + // 测试 status 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, + o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + + // 调用 + List list = tenantPackageService.getTenantPackageListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + assertEquals(1, list.size()); + assertPojoEquals(dbTenantPackage, list.get(0)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java new file mode 100644 index 0000000..87d66ea --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java @@ -0,0 +1,458 @@ +package cn.iocoder.yudao.module.system.service.tenant; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; +import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import cn.iocoder.yudao.module.system.service.permission.MenuService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.permission.RoleService; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO.PACKAGE_ID_SYSTEM; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * {@link TenantServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(TenantServiceImpl.class) +public class TenantServiceImplTest extends BaseDbUnitTest { + + @Resource + private TenantServiceImpl tenantService; + + @Resource + private TenantMapper tenantMapper; + + @MockBean + private TenantProperties tenantProperties; + @MockBean + private TenantPackageService tenantPackageService; + @MockBean + private AdminUserService userService; + @MockBean + private RoleService roleService; + @MockBean + private MenuService menuService; + @MockBean + private PermissionService permissionService; + + @BeforeEach + public void setUp() { + // 清理租户上下文 + TenantContextHolder.clear(); + } + + @Test + public void testGetTenantIdList() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L)); + tenantMapper.insert(tenant); + + // 调用,并断言业务异常 + List result = tenantService.getTenantIdList(); + assertEquals(Collections.singletonList(1L), result); + } + + @Test + public void testValidTenant_notExists() { + assertServiceException(() -> tenantService.validTenant(randomLongId()), TENANT_NOT_EXISTS); + } + + @Test + public void testValidTenant_disable() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.DISABLE.getStatus())); + tenantMapper.insert(tenant); + + // 调用,并断言业务异常 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_DISABLE, tenant.getName()); + } + + @Test + public void testValidTenant_expired() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setExpireTime(buildTime(2020, 2, 2))); + tenantMapper.insert(tenant); + + // 调用,并断言业务异常 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_EXPIRE, tenant.getName()); + } + + @Test + public void testValidTenant_success() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setExpireTime(LocalDateTime.now().plusDays(1))); + tenantMapper.insert(tenant); + + // 调用,并断言业务异常 + tenantService.validTenant(1L); + } + + @Test + public void testCreateTenant() { + // mock 套餐 100L + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, o -> o.setId(100L)); + when(tenantPackageService.validTenantPackage(eq(100L))).thenReturn(tenantPackage); + // mock 角色 200L + when(roleService.createRole(argThat(role -> { + assertEquals(RoleCodeEnum.TENANT_ADMIN.getName(), role.getName()); + assertEquals(RoleCodeEnum.TENANT_ADMIN.getCode(), role.getCode()); + assertEquals(0, role.getSort()); + assertEquals("系统自动生成", role.getRemark()); + return true; + }), eq(RoleTypeEnum.SYSTEM.getType()))).thenReturn(200L); + // mock 用户 300L + when(userService.createUser(argThat(user -> { + assertEquals("yunai", user.getUsername()); + assertEquals("yuanma", user.getPassword()); + assertEquals("芋道", user.getNickname()); + assertEquals("15601691300", user.getMobile()); + return true; + }))).thenReturn(300L); + + // 准备参数 + TenantSaveReqVO reqVO = randomPojo(TenantSaveReqVO.class, o -> { + o.setContactName("芋道"); + o.setContactMobile("15601691300"); + o.setPackageId(100L); + o.setStatus(randomCommonStatus()); + o.setWebsite("https://www.iocoder.cn"); + o.setUsername("yunai"); + o.setPassword("yuanma"); + }).setId(null); // 设置为 null,方便后面校验 + + // 调用 + Long tenantId = tenantService.createTenant(reqVO); + // 断言 + assertNotNull(tenantId); + // 校验记录的属性是否正确 + TenantDO tenant = tenantMapper.selectById(tenantId); + assertPojoEquals(reqVO, tenant, "id"); + assertEquals(300L, tenant.getContactUserId()); + // verify 分配权限 + verify(permissionService).assignRoleMenu(eq(200L), same(tenantPackage.getMenuIds())); + // verify 分配角色 + verify(permissionService).assignUserRole(eq(300L), eq(singleton(200L))); + } + + @Test + public void testUpdateTenant_success() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setStatus(randomCommonStatus())); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + TenantSaveReqVO reqVO = randomPojo(TenantSaveReqVO.class, o -> { + o.setId(dbTenant.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + o.setWebsite(randomString()); + }); + + // mock 套餐 + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setMenuIds(asSet(200L, 201L))); + when(tenantPackageService.validTenantPackage(eq(reqVO.getPackageId()))).thenReturn(tenantPackage); + // mock 所有角色 + RoleDO role100 = randomPojo(RoleDO.class, o -> o.setId(100L).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())); + role100.setTenantId(dbTenant.getId()); + RoleDO role101 = randomPojo(RoleDO.class, o -> o.setId(101L)); + role101.setTenantId(dbTenant.getId()); + when(roleService.getRoleList()).thenReturn(asList(role100, role101)); + // mock 每个角色的权限 + when(permissionService.getRoleMenuListByRoleId(eq(101L))).thenReturn(asSet(201L, 202L)); + + // 调用 + tenantService.updateTenant(reqVO); + // 校验是否更新正确 + TenantDO tenant = tenantMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, tenant); + // verify 设置角色权限 + verify(permissionService).assignRoleMenu(eq(100L), eq(asSet(200L, 201L))); + verify(permissionService).assignRoleMenu(eq(101L), eq(asSet(201L))); + } + + @Test + public void testUpdateTenant_notExists() { + // 准备参数 + TenantSaveReqVO reqVO = randomPojo(TenantSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_NOT_EXISTS); + } + + @Test + public void testUpdateTenant_system() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + TenantSaveReqVO reqVO = randomPojo(TenantSaveReqVO.class, o -> { + o.setId(dbTenant.getId()); // 设置更新的 ID + }); + + // 调用,校验业务异常 + assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_CAN_NOT_UPDATE_SYSTEM); + } + + @Test + public void testDeleteTenant_success() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, + o -> o.setStatus(randomCommonStatus())); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenant.getId(); + + // 调用 + tenantService.deleteTenant(id); + // 校验数据不存在了 + assertNull(tenantMapper.selectById(id)); + } + + @Test + public void testDeleteTenant_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> tenantService.deleteTenant(id), TENANT_NOT_EXISTS); + } + + @Test + public void testDeleteTenant_system() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenant.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> tenantService.deleteTenant(id), TENANT_CAN_NOT_UPDATE_SYSTEM); + } + + @Test + public void testGetTenant() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenant.getId(); + + // 调用 + TenantDO result = tenantService.getTenant(id); + // 校验存在 + assertPojoEquals(result, dbTenant); + } + + @Test + public void testGetTenantPage() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setContactName("芋艿"); + o.setContactMobile("15601691300"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2020, 12, 12)); + }); + tenantMapper.insert(dbTenant); + // 测试 name 不匹配 + tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setName(randomString()))); + // 测试 contactName 不匹配 + tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactName(randomString()))); + // 测试 contactMobile 不匹配 + tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactMobile(randomString()))); + // 测试 status 不匹配 + tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setCreateTime(buildTime(2021, 12, 12)))); + // 准备参数 + TenantPageReqVO reqVO = new TenantPageReqVO(); + reqVO.setName("芋道"); + reqVO.setContactName("艿"); + reqVO.setContactMobile("1560"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24)); + + // 调用 + PageResult pageResult = tenantService.getTenantPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbTenant, pageResult.getList().get(0)); + } + + @Test + public void testGetTenantByName() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setName("芋道")); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + + // 调用 + TenantDO result = tenantService.getTenantByName("芋道"); + // 校验存在 + assertPojoEquals(result, dbTenant); + } + + @Test + public void testGetTenantByWebsite() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setWebsite("https://www.iocoder.cn")); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + + // 调用 + TenantDO result = tenantService.getTenantByWebsite("https://www.iocoder.cn"); + // 校验存在 + assertPojoEquals(result, dbTenant); + } + + @Test + public void testGetTenantListByPackageId() { + // mock 数据 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L)); + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L)); + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据 + + // 调用 + List result = tenantService.getTenantListByPackageId(1L); + assertEquals(1, result.size()); + assertPojoEquals(dbTenant1, result.get(0)); + } + + @Test + public void testGetTenantCountByPackageId() { + // mock 数据 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L)); + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L)); + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据 + + // 调用 + Long count = tenantService.getTenantCountByPackageId(1L); + assertEquals(1, count); + } + + @Test + public void testHandleTenantInfo_disable() { + // 准备参数 + TenantInfoHandler handler = mock(TenantInfoHandler.class); + // mock 禁用 + when(tenantProperties.getEnable()).thenReturn(false); + + // 调用 + tenantService.handleTenantInfo(handler); + // 断言 + verify(handler, never()).handle(any()); + } + + @Test + public void testHandleTenantInfo_success() { + // 准备参数 + TenantInfoHandler handler = mock(TenantInfoHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + + // 调用 + tenantService.handleTenantInfo(handler); + // 断言 + verify(handler).handle(argThat(argument -> { + assertPojoEquals(dbTenant, argument); + return true; + })); + } + + @Test + public void testHandleTenantMenu_disable() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 禁用 + when(tenantProperties.getEnable()).thenReturn(false); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler, never()).handle(any()); + } + + @Test // 系统租户的情况 + public void testHandleTenantMenu_system() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + // mock 菜单 + when(menuService.getMenuList()).thenReturn(Arrays.asList(randomPojo(MenuDO.class, o -> o.setId(100L)), + randomPojo(MenuDO.class, o -> o.setId(101L)))); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler).handle(asSet(100L, 101L)); + } + + @Test // 普通租户的情况 + public void testHandleTenantMenu_normal() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(200L)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + // mock 菜单 + when(tenantPackageService.getTenantPackage(eq(200L))).thenReturn(randomPojo(TenantPackageDO.class, + o -> o.setMenuIds(asSet(100L, 101L)))); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler).handle(asSet(100L, 101L)); + } +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java new file mode 100644 index 0000000..03897a8 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java @@ -0,0 +1,762 @@ +package cn.iocoder.yudao.module.system.service.user; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper; +import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.dept.PostService; +import cn.iocoder.yudao.module.system.service.permission.PermissionService; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import org.junit.jupiter.api.Test; +import org.mockito.stubbing.Answer; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.security.crypto.password.PasswordEncoder; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomBytes; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.assertj.core.util.Lists.newArrayList; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@Import(AdminUserServiceImpl.class) +public class AdminUserServiceImplTest extends BaseDbUnitTest { + + @Resource + private AdminUserServiceImpl userService; + + @Resource + private AdminUserMapper userMapper; + @Resource + private UserPostMapper userPostMapper; + + @MockBean + private DeptService deptService; + @MockBean + private PostService postService; + @MockBean + private PermissionService permissionService; + @MockBean + private PasswordEncoder passwordEncoder; + @MockBean + private TenantService tenantService; + @MockBean + private FileApi fileApi; + + @Test + public void testCreatUser_success() { + // 准备参数 + UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class, o -> { + o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); + o.setMobile(randomString()); + o.setPostIds(asSet(1L, 2L)); + }).setId(null); // 避免 id 被赋值 + // mock 账户额度充足 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setAccountCount(1)); + doNothing().when(tenantService).handleTenantInfo(argThat(handler -> { + handler.handle(tenant); + return true; + })); + // mock deptService 的方法 + DeptDO dept = randomPojo(DeptDO.class, o -> { + o.setId(reqVO.getDeptId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); + // mock postService 的方法 + List posts = CollectionUtils.convertList(reqVO.getPostIds(), postId -> + randomPojo(PostDO.class, o -> { + o.setId(postId); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + })); + when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts); + // mock passwordEncoder 的方法 + when(passwordEncoder.encode(eq(reqVO.getPassword()))).thenReturn("yudaoyuanma"); + + // 调用 + Long userId = userService.createUser(reqVO); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertPojoEquals(reqVO, user, "password", "id"); + assertEquals("yudaoyuanma", user.getPassword()); + assertEquals(CommonStatusEnum.ENABLE.getStatus(), user.getStatus()); + // 断言关联岗位 + List userPosts = userPostMapper.selectListByUserId(user.getId()); + assertEquals(1L, userPosts.get(0).getPostId()); + assertEquals(2L, userPosts.get(1).getPostId()); + } + + @Test + public void testCreatUser_max() { + // 准备参数 + UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class); + // mock 账户额度不足 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setAccountCount(-1)); + doNothing().when(tenantService).handleTenantInfo(argThat(handler -> { + handler.handle(tenant); + return true; + })); + + // 调用,并断言异常 + assertServiceException(() -> userService.createUser(reqVO), USER_COUNT_MAX, -1); + } + + @Test + public void testUpdateUser_success() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(o -> o.setPostIds(asSet(1L, 2L))); + userMapper.insert(dbUser); + userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(1L)); + userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(2L)); + // 准备参数 + UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class, o -> { + o.setId(dbUser.getId()); + o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); + o.setMobile(randomString()); + o.setPostIds(asSet(2L, 3L)); + }); + // mock deptService 的方法 + DeptDO dept = randomPojo(DeptDO.class, o -> { + o.setId(reqVO.getDeptId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); + // mock postService 的方法 + List posts = CollectionUtils.convertList(reqVO.getPostIds(), postId -> + randomPojo(PostDO.class, o -> { + o.setId(postId); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + })); + when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts); + + // 调用 + userService.updateUser(reqVO); + // 断言 + AdminUserDO user = userMapper.selectById(reqVO.getId()); + assertPojoEquals(reqVO, user, "password"); + // 断言关联岗位 + List userPosts = userPostMapper.selectListByUserId(user.getId()); + assertEquals(2L, userPosts.get(0).getPostId()); + assertEquals(3L, userPosts.get(1).getPostId()); + } + + @Test + public void testUpdateUserLogin() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(o -> o.setLoginDate(null)); + userMapper.insert(user); + // 准备参数 + Long id = user.getId(); + String loginIp = randomString(); + + // 调用 + userService.updateUserLogin(id, loginIp); + // 断言 + AdminUserDO dbUser = userMapper.selectById(id); + assertEquals(loginIp, dbUser.getLoginIp()); + assertNotNull(dbUser.getLoginDate()); + } + + @Test + public void testUpdateUserProfile_success() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + UserProfileUpdateReqVO reqVO = randomPojo(UserProfileUpdateReqVO.class, o -> { + o.setMobile(randomString()); + o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); + }); + + // 调用 + userService.updateUserProfile(userId, reqVO); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertPojoEquals(reqVO, user); + } + + @Test + public void testUpdateUserPassword_success() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(o -> o.setPassword("encode:tudou")); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + UserProfileUpdatePasswordReqVO reqVO = randomPojo(UserProfileUpdatePasswordReqVO.class, o -> { + o.setOldPassword("tudou"); + o.setNewPassword("yuanma"); + }); + // mock 方法 + when(passwordEncoder.encode(anyString())).then( + (Answer) invocationOnMock -> "encode:" + invocationOnMock.getArgument(0)); + when(passwordEncoder.matches(eq(reqVO.getOldPassword()), eq(dbUser.getPassword()))).thenReturn(true); + + // 调用 + userService.updateUserPassword(userId, reqVO); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertEquals("encode:yuanma", user.getPassword()); + } + + @Test + public void testUpdateUserAvatar_success() throws Exception { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + byte[] avatarFileBytes = randomBytes(10); + ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); + // mock 方法 + String avatar = randomString(); + when(fileApi.createFile(eq( avatarFileBytes))).thenReturn(avatar); + + // 调用 + userService.updateUserAvatar(userId, avatarFile); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertEquals(avatar, user.getAvatar()); + } + + @Test + public void testUpdateUserPassword02_success() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + String password = "yudao"; + // mock 方法 + when(passwordEncoder.encode(anyString())).then( + (Answer) invocationOnMock -> "encode:" + invocationOnMock.getArgument(0)); + + // 调用 + userService.updateUserPassword(userId, password); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertEquals("encode:" + password, user.getPassword()); + } + + @Test + public void testUpdateUserStatus() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + Integer status = randomCommonStatus(); + + // 调用 + userService.updateUserStatus(userId, status); + // 断言 + AdminUserDO user = userMapper.selectById(userId); + assertEquals(status, user.getStatus()); + } + + @Test + public void testDeleteUser_success(){ + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + + // 调用数据 + userService.deleteUser(userId); + // 校验结果 + assertNull(userMapper.selectById(userId)); + // 校验调用次数 + verify(permissionService, times(1)).processUserDeleted(eq(userId)); + } + + @Test + public void testGetUserByUsername() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + String username = dbUser.getUsername(); + + // 调用 + AdminUserDO user = userService.getUserByUsername(username); + // 断言 + assertPojoEquals(dbUser, user); + } + + @Test + public void testGetUserByMobile() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + String mobile = dbUser.getMobile(); + + // 调用 + AdminUserDO user = userService.getUserByMobile(mobile); + // 断言 + assertPojoEquals(dbUser, user); + } + + @Test + public void testGetUserPage() { + // mock 数据 + AdminUserDO dbUser = initGetUserPageData(); + // 准备参数 + UserPageReqVO reqVO = new UserPageReqVO(); + reqVO.setUsername("tu"); + reqVO.setMobile("1560"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24)); + reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 + // mock 方法 + List deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L))); + when(deptService.getChildDeptList(eq(reqVO.getDeptId()))).thenReturn(deptList); + + // 调用 + PageResult pageResult = userService.getUserPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbUser, pageResult.getList().get(0)); + } + + /** + * 初始化 getUserPage 方法的测试数据 + */ + private AdminUserDO initGetUserPageData() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(o -> { // 等会查询到 + o.setUsername("tudou"); + o.setMobile("15601691300"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2020, 12, 12)); + o.setDeptId(2L); + }); + userMapper.insert(dbUser); + // 测试 username 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setUsername("dou"))); + // 测试 mobile 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setMobile("18818260888"))); + // 测试 status 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setCreateTime(buildTime(2020, 11, 11)))); + // 测试 dept 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setDeptId(0L))); + return dbUser; + } + + @Test + public void testGetUser() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + Long userId = dbUser.getId(); + + // 调用 + AdminUserDO user = userService.getUser(userId); + // 断言 + assertPojoEquals(dbUser, user); + } + + @Test + public void testGetUserListByDeptIds() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(o -> o.setDeptId(1L)); + userMapper.insert(dbUser); + // 测试 deptId 不匹配 + userMapper.insert(cloneIgnoreId(dbUser, o -> o.setDeptId(2L))); + // 准备参数 + Collection deptIds = singleton(1L); + + // 调用 + List list = userService.getUserListByDeptIds(deptIds); + // 断言 + assertEquals(1, list.size()); + assertEquals(dbUser, list.get(0)); + } + + /** + * 情况一,校验不通过,导致插入失败 + */ + @Test + public void testImportUserList_01() { + // 准备参数 + UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { + }); + // mock 方法,模拟失败 + doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any()); + + // 调用 + UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); + // 断言 + assertEquals(0, respVO.getCreateUsernames().size()); + assertEquals(0, respVO.getUpdateUsernames().size()); + assertEquals(1, respVO.getFailureUsernames().size()); + assertEquals(DEPT_NOT_FOUND.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername())); + } + + /** + * 情况二,不存在,进行插入 + */ + @Test + public void testImportUserList_02() { + // 准备参数 + UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 + }); + // mock deptService 的方法 + DeptDO dept = randomPojo(DeptDO.class, o -> { + o.setId(importUser.getDeptId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); + // mock passwordEncoder 的方法 + when(passwordEncoder.encode(eq("yudaoyuanma"))).thenReturn("java"); + + // 调用 + UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); + // 断言 + assertEquals(1, respVO.getCreateUsernames().size()); + AdminUserDO user = userMapper.selectByUsername(respVO.getCreateUsernames().get(0)); + assertPojoEquals(importUser, user); + assertEquals("java", user.getPassword()); + assertEquals(0, respVO.getUpdateUsernames().size()); + assertEquals(0, respVO.getFailureUsernames().size()); + } + + /** + * 情况三,存在,但是不强制更新 + */ + @Test + public void testImportUserList_03() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 + o.setUsername(dbUser.getUsername()); + }); + // mock deptService 的方法 + DeptDO dept = randomPojo(DeptDO.class, o -> { + o.setId(importUser.getDeptId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); + + // 调用 + UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), false); + // 断言 + assertEquals(0, respVO.getCreateUsernames().size()); + assertEquals(0, respVO.getUpdateUsernames().size()); + assertEquals(1, respVO.getFailureUsernames().size()); + assertEquals(USER_USERNAME_EXISTS.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername())); + } + + /** + * 情况四,存在,强制更新 + */ + @Test + public void testImportUserList_04() { + // mock 数据 + AdminUserDO dbUser = randomAdminUserDO(); + userMapper.insert(dbUser); + // 准备参数 + UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 + o.setUsername(dbUser.getUsername()); + }); + // mock deptService 的方法 + DeptDO dept = randomPojo(DeptDO.class, o -> { + o.setId(importUser.getDeptId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(deptService.getDept(eq(dept.getId()))).thenReturn(dept); + + // 调用 + UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true); + // 断言 + assertEquals(0, respVO.getCreateUsernames().size()); + assertEquals(1, respVO.getUpdateUsernames().size()); + AdminUserDO user = userMapper.selectByUsername(respVO.getUpdateUsernames().get(0)); + assertPojoEquals(importUser, user); + assertEquals(0, respVO.getFailureUsernames().size()); + } + + @Test + public void testValidateUserExists_notExists() { + assertServiceException(() -> userService.validateUserExists(randomLongId()), USER_NOT_EXISTS); + } + + @Test + public void testValidateUsernameUnique_usernameExistsForCreate() { + // 准备参数 + String username = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setUsername(username))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateUsernameUnique(null, username), + USER_USERNAME_EXISTS); + } + + @Test + public void testValidateUsernameUnique_usernameExistsForUpdate() { + // 准备参数 + Long id = randomLongId(); + String username = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setUsername(username))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateUsernameUnique(id, username), + USER_USERNAME_EXISTS); + } + + @Test + public void testValidateEmailUnique_emailExistsForCreate() { + // 准备参数 + String email = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setEmail(email))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateEmailUnique(null, email), + USER_EMAIL_EXISTS); + } + + @Test + public void testValidateEmailUnique_emailExistsForUpdate() { + // 准备参数 + Long id = randomLongId(); + String email = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setEmail(email))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateEmailUnique(id, email), + USER_EMAIL_EXISTS); + } + + @Test + public void testValidateMobileUnique_mobileExistsForCreate() { + // 准备参数 + String mobile = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setMobile(mobile))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateMobileUnique(null, mobile), + USER_MOBILE_EXISTS); + } + + @Test + public void testValidateMobileUnique_mobileExistsForUpdate() { + // 准备参数 + Long id = randomLongId(); + String mobile = randomString(); + // mock 数据 + userMapper.insert(randomAdminUserDO(o -> o.setMobile(mobile))); + + // 调用,校验异常 + assertServiceException(() -> userService.validateMobileUnique(id, mobile), + USER_MOBILE_EXISTS); + } + + @Test + public void testValidateOldPassword_notExists() { + assertServiceException(() -> userService.validateOldPassword(randomLongId(), randomString()), + USER_NOT_EXISTS); + } + + @Test + public void testValidateOldPassword_passwordFailed() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(); + userMapper.insert(user); + // 准备参数 + Long id = user.getId(); + String oldPassword = user.getPassword(); + + // 调用,校验异常 + assertServiceException(() -> userService.validateOldPassword(id, oldPassword), + USER_PASSWORD_FAILED); + // 校验调用 + verify(passwordEncoder, times(1)).matches(eq(oldPassword), eq(user.getPassword())); + } + + @Test + public void testUserListByPostIds() { + // 准备参数 + Collection postIds = asSet(10L, 20L); + // mock user1 数据 + AdminUserDO user1 = randomAdminUserDO(o -> o.setPostIds(asSet(10L, 30L))); + userMapper.insert(user1); + userPostMapper.insert(new UserPostDO().setUserId(user1.getId()).setPostId(10L)); + userPostMapper.insert(new UserPostDO().setUserId(user1.getId()).setPostId(30L)); + // mock user2 数据 + AdminUserDO user2 = randomAdminUserDO(o -> o.setPostIds(singleton(100L))); + userMapper.insert(user2); + userPostMapper.insert(new UserPostDO().setUserId(user2.getId()).setPostId(100L)); + + // 调用 + List result = userService.getUserListByPostIds(postIds); + // 断言 + assertEquals(1, result.size()); + assertEquals(user1, result.get(0)); + } + + @Test + public void testGetUserList() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(); + userMapper.insert(user); + // 测试 id 不匹配 + userMapper.insert(randomAdminUserDO()); + // 准备参数 + Collection ids = singleton(user.getId()); + + // 调用 + List result = userService.getUserList(ids); + // 断言 + assertEquals(1, result.size()); + assertEquals(user, result.get(0)); + } + + @Test + public void testGetUserMap() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(); + userMapper.insert(user); + // 测试 id 不匹配 + userMapper.insert(randomAdminUserDO()); + // 准备参数 + Collection ids = singleton(user.getId()); + + // 调用 + Map result = userService.getUserMap(ids); + // 断言 + assertEquals(1, result.size()); + assertEquals(user, result.get(user.getId())); + } + + @Test + public void testGetUserListByNickname() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(o -> o.setNickname("芋头")); + userMapper.insert(user); + // 测试 nickname 不匹配 + userMapper.insert(randomAdminUserDO(o -> o.setNickname("源码"))); + // 准备参数 + String nickname = "芋"; + + // 调用 + List result = userService.getUserListByNickname(nickname); + // 断言 + assertEquals(1, result.size()); + assertEquals(user, result.get(0)); + } + + @Test + public void testGetUserListByStatus() { + // mock 数据 + AdminUserDO user = randomAdminUserDO(o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + userMapper.insert(user); + // 测试 status 不匹配 + userMapper.insert(randomAdminUserDO(o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()))); + // 准备参数 + Integer status = CommonStatusEnum.DISABLE.getStatus(); + + // 调用 + List result = userService.getUserListByStatus(status); + // 断言 + assertEquals(1, result.size()); + assertEquals(user, result.get(0)); + } + + @Test + public void testValidateUserList_success() { + // mock 数据 + AdminUserDO userDO = randomAdminUserDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); + userMapper.insert(userDO); + // 准备参数 + List ids = singletonList(userDO.getId()); + + // 调用,无需断言 + userService.validateUserList(ids); + } + + @Test + public void testValidateUserList_notFound() { + // 准备参数 + List ids = singletonList(randomLongId()); + + // 调用, 并断言异常 + assertServiceException(() -> userService.validateUserList(ids), USER_NOT_EXISTS); + } + + @Test + public void testValidateUserList_notEnable() { + // mock 数据 + AdminUserDO userDO = randomAdminUserDO().setStatus(CommonStatusEnum.DISABLE.getStatus()); + userMapper.insert(userDO); + // 准备参数 + List ids = singletonList(userDO.getId()); + + // 调用, 并断言异常 + assertServiceException(() -> userService.validateUserList(ids), USER_IS_DISABLE, + userDO.getNickname()); + } + + // ========== 随机对象 ========== + + @SafeVarargs + private static AdminUserDO randomAdminUserDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 + }; + return randomPojo(AdminUserDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 0000000..eb823d9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,53 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 16379 # 端口(单元测试,使用 16379 端口) + database: 0 # 数据库索引 + + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module + captcha: + timeout: 5m + width: 160 + height: 60 + enable: true diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/logback.xml b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/logback.xml new file mode 100644 index 0000000..daf756b --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql new file mode 100644 index 0000000..e7946a1 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,33 @@ +DELETE FROM "system_dept"; +DELETE FROM "system_dict_data"; +DELETE FROM "system_role"; +DELETE FROM "system_role_menu"; +DELETE FROM "system_menu"; +DELETE FROM "system_user_role"; +DELETE FROM "system_dict_type"; +DELETE FROM "system_user_session"; +DELETE FROM "system_post"; +DELETE FROM "system_user_post"; +DELETE FROM "system_notice"; +DELETE FROM "system_login_log"; +DELETE FROM "system_operate_log"; +DELETE FROM "system_users"; +DELETE FROM "system_sms_channel"; +DELETE FROM "system_sms_template"; +DELETE FROM "system_sms_log"; +DELETE FROM "system_sms_code"; +DELETE FROM "system_social_client"; +DELETE FROM "system_social_user"; +DELETE FROM "system_social_user_bind"; +DELETE FROM "system_tenant"; +DELETE FROM "system_tenant_package"; +DELETE FROM "system_oauth2_client"; +DELETE FROM "system_oauth2_approve"; +DELETE FROM "system_oauth2_access_token"; +DELETE FROM "system_oauth2_refresh_token"; +DELETE FROM "system_oauth2_code"; +DELETE FROM "system_mail_account"; +DELETE FROM "system_mail_template"; +DELETE FROM "system_mail_log"; +DELETE FROM "system_notify_template"; +DELETE FROM "system_notify_message"; diff --git a/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 0000000..087540a --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,614 @@ +CREATE TABLE IF NOT EXISTS "system_dept" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(30) NOT NULL DEFAULT '', + "parent_id" bigint NOT NULL DEFAULT '0', + "sort" int NOT NULL DEFAULT '0', + "leader_user_id" bigint DEFAULT NULL, + "phone" varchar(11) DEFAULT NULL, + "email" varchar(50) DEFAULT NULL, + "status" tinyint NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '部门表'; + +CREATE TABLE IF NOT EXISTS "system_dict_data" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "sort" int NOT NULL DEFAULT '0', + "label" varchar(100) NOT NULL DEFAULT '', + "value" varchar(100) NOT NULL DEFAULT '', + "dict_type" varchar(100) NOT NULL DEFAULT '', + "status" tinyint NOT NULL DEFAULT '0', + "color_type" varchar(100) NOT NULL DEFAULT '', + "css_class" varchar(100) NOT NULL DEFAULT '', + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '字典数据表'; + +CREATE TABLE IF NOT EXISTS "system_role" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(30) NOT NULL, + "code" varchar(100) NOT NULL, + "sort" int NOT NULL, + "data_scope" tinyint NOT NULL DEFAULT '1', + "data_scope_dept_ids" varchar(500) NOT NULL DEFAULT '', + "status" tinyint NOT NULL, + "type" tinyint NOT NULL, + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '角色信息表'; + +CREATE TABLE IF NOT EXISTS "system_role_menu" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "role_id" bigint NOT NULL, + "menu_id" bigint NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '角色和菜单关联表'; + +CREATE TABLE IF NOT EXISTS "system_menu" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(50) NOT NULL, + "permission" varchar(100) NOT NULL DEFAULT '', + "type" tinyint NOT NULL, + "sort" int NOT NULL DEFAULT '0', + "parent_id" bigint NOT NULL DEFAULT '0', + "path" varchar(200) DEFAULT '', + "icon" varchar(100) DEFAULT '#', + "component" varchar(255) DEFAULT NULL, + "component_name" varchar(255) DEFAULT NULL, + "status" tinyint NOT NULL DEFAULT '0', + "visible" bit NOT NULL DEFAULT TRUE, + "keep_alive" bit NOT NULL DEFAULT TRUE, + "always_show" bit NOT NULL DEFAULT TRUE, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '菜单权限表'; + +CREATE TABLE IF NOT EXISTS "system_user_role" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "role_id" bigint NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp DEFAULT NULL, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp DEFAULT NULL, + "deleted" bit DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '用户和角色关联表'; + +CREATE TABLE IF NOT EXISTS "system_dict_type" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(100) NOT NULL DEFAULT '', + "type" varchar(100) NOT NULL DEFAULT '', + "status" tinyint NOT NULL DEFAULT '0', + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "deleted_time" timestamp NOT NULL, + PRIMARY KEY ("id") +) COMMENT '字典类型表'; + +CREATE TABLE IF NOT EXISTS `system_user_session` ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `token` varchar(32) NOT NULL, + `user_id` bigint DEFAULT NULL, + "user_type" tinyint NOT NULL, + `username` varchar(50) NOT NULL DEFAULT '', + `user_ip` varchar(50) DEFAULT NULL, + `user_agent` varchar(512) DEFAULT NULL, + `session_timeout` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) DEFAULT '' , + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY (`id`) +) COMMENT '用户在线 Session'; + +CREATE TABLE IF NOT EXISTS "system_post" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar(64) NOT NULL, + "name" varchar(50) NOT NULL, + "sort" integer NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(500) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '岗位信息表'; + +CREATE TABLE IF NOT EXISTS `system_user_post`( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint DEFAULT NULL, + "post_id" bigint DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY (`id`) +) COMMENT ='用户岗位表'; + +CREATE TABLE IF NOT EXISTS "system_notice" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "title" varchar(50) NOT NULL COMMENT '公告标题', + "content" text NOT NULL COMMENT '公告内容', + "type" tinyint NOT NULL COMMENT '公告类型(1通知 2公告)', + "status" tinyint NOT NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)', + "creator" varchar(64) DEFAULT '' COMMENT '创建者', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + "updater" varchar(64) DEFAULT '' COMMENT '更新者', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + "deleted" bit NOT NULL DEFAULT 0 COMMENT '是否删除', + "tenant_id" bigint not null default '0', + PRIMARY KEY("id") +) COMMENT '通知公告表'; + +CREATE TABLE IF NOT EXISTS `system_login_log` ( + `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `log_type` bigint(4) NOT NULL, + "user_id" bigint not null default '0', + "user_type" tinyint NOT NULL, + `trace_id` varchar(64) NOT NULL DEFAULT '', + `username` varchar(50) NOT NULL DEFAULT '', + `result` tinyint(4) NOT NULL, + `user_ip` varchar(50) NOT NULL, + `user_agent` varchar(512) NOT NULL, + `creator` varchar(64) DEFAULT '', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) DEFAULT '', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) COMMENT ='系统访问记录'; + +CREATE TABLE IF NOT EXISTS `system_operate_log` ( + `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, + `trace_id` varchar(64) NOT NULL DEFAULT '', + `user_id` bigint(20) NOT NULL, + "user_type" tinyint not null default '0', + `type` varchar(50) NOT NULL, + `sub_type` varchar(50) NOT NULL, + `biz_id` bigint(20) NOT NULL, + `action` varchar(2000) NOT NULL DEFAULT '', + `extra` varchar(512) NOT NULL DEFAULT '', + `request_method` varchar(16) DEFAULT '', + `request_url` varchar(255) DEFAULT '', + `user_ip` varchar(50) DEFAULT NULL, + `user_agent` varchar(200) DEFAULT NULL, + `creator` varchar(64) DEFAULT '', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(64) DEFAULT '', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` bit(1) NOT NULL DEFAULT '0', + "tenant_id" bigint not null default '0', + PRIMARY KEY (`id`) +) COMMENT ='操作日志记录'; + +CREATE TABLE IF NOT EXISTS "system_users" ( + "id" bigint not null GENERATED BY DEFAULT AS IDENTITY, + "username" varchar(30) not null, + "password" varchar(100) not null default '', + "nickname" varchar(30) not null, + "remark" varchar(500) default null, + "dept_id" bigint default null, + "post_ids" varchar(255) default null, + "email" varchar(50) default '', + "mobile" varchar(11) default '', + "sex" tinyint default '0', + "avatar" varchar(100) default '', + "status" tinyint not null default '0', + "login_ip" varchar(50) default '', + "login_date" timestamp default null, + "creator" varchar(64) default '', + "create_time" timestamp not null default current_timestamp, + "updater" varchar(64) default '', + "update_time" timestamp not null default current_timestamp, + "deleted" bit not null default false, + "tenant_id" bigint not null default '0', + primary key ("id") +) comment '用户信息表'; + +CREATE TABLE IF NOT EXISTS "system_sms_channel" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "signature" varchar(10) NOT NULL, + "code" varchar(63) NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(255) DEFAULT NULL, + "api_key" varchar(63) NOT NULL, + "api_secret" varchar(63) DEFAULT NULL, + "callback_url" varchar(255) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信渠道'; + +CREATE TABLE IF NOT EXISTS "system_sms_template" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "type" tinyint NOT NULL, + "status" tinyint NOT NULL, + "code" varchar(63) NOT NULL, + "name" varchar(63) NOT NULL, + "content" varchar(255) NOT NULL, + "params" varchar(255) NOT NULL, + "remark" varchar(255) DEFAULT NULL, + "api_template_id" varchar(63) NOT NULL, + "channel_id" bigint NOT NULL, + "channel_code" varchar(63) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信模板'; + +CREATE TABLE IF NOT EXISTS "system_sms_log" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "channel_id" bigint NOT NULL, + "channel_code" varchar(63) NOT NULL, + "template_id" bigint NOT NULL, + "template_code" varchar(63) NOT NULL, + "template_type" tinyint NOT NULL, + "template_content" varchar(255) NOT NULL, + "template_params" varchar(255) NOT NULL, + "api_template_id" varchar(63) NOT NULL, + "mobile" varchar(11) NOT NULL, + "user_id" bigint DEFAULT '0', + "user_type" tinyint DEFAULT '0', + "send_status" tinyint NOT NULL DEFAULT '0', + "send_time" timestamp DEFAULT NULL, + "send_code" int DEFAULT NULL, + "send_msg" varchar(255) DEFAULT NULL, + "api_send_code" varchar(63) DEFAULT NULL, + "api_send_msg" varchar(255) DEFAULT NULL, + "api_request_id" varchar(255) DEFAULT NULL, + "api_serial_no" varchar(255) DEFAULT NULL, + "receive_status" tinyint NOT NULL DEFAULT '0', + "receive_time" timestamp DEFAULT NULL, + "api_receive_code" varchar(63) DEFAULT NULL, + "api_receive_msg" varchar(255) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信日志'; + +CREATE TABLE IF NOT EXISTS "system_sms_code" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "mobile" varchar(11) NOT NULL, + "code" varchar(11) NOT NULL, + "scene" bigint NOT NULL, + "create_ip" varchar NOT NULL, + "today_index" int NOT NULL, + "used" bit NOT NULL DEFAULT FALSE, + "used_time" timestamp DEFAULT NULL, + "used_ip" varchar NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信日志'; + +CREATE TABLE IF NOT EXISTS "system_social_client" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(255) NOT NULL, + "social_type" int NOT NULL, + "user_type" int NOT NULL, + "client_id" varchar(255) NOT NULL, + "client_secret" varchar(255) NOT NULL, + "agent_id" varchar(255) NOT NULL, + "status" int NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '社交客户端表'; + +CREATE TABLE IF NOT EXISTS "system_social_user" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "type" tinyint NOT NULL, + "openid" varchar(64) NOT NULL, + "token" varchar(256) DEFAULT NULL, + "raw_token_info" varchar(1024) NOT NULL, + "nickname" varchar(32) NOT NULL, + "avatar" varchar(255) DEFAULT NULL, + "raw_user_info" varchar(1024) NOT NULL, + "code" varchar(64) NOT NULL, + "state" varchar(64), + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '社交用户'; + +CREATE TABLE IF NOT EXISTS "system_social_user_bind" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" tinyint NOT NULL, + "social_type" tinyint NOT NULL, + "social_user_id" number NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '社交用户的绑定'; + +CREATE TABLE IF NOT EXISTS "system_tenant" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "contact_user_id" bigint NOT NULL DEFAULT '0', + "contact_name" varchar(255) NOT NULL, + "contact_mobile" varchar(255), + "status" tinyint NOT NULL, + "website" varchar(63) DEFAULT '', + "package_id" bigint NOT NULL, + "expire_time" timestamp NOT NULL, + "account_count" int NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '租户'; + +CREATE TABLE IF NOT EXISTS "system_tenant_package" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(30) NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(256), + "menu_ids" varchar(2048) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '租户套餐表'; + +CREATE TABLE IF NOT EXISTS "system_oauth2_client" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "client_id" varchar NOT NULL, + "secret" varchar NOT NULL, + "name" varchar NOT NULL, + "logo" varchar NOT NULL, + "description" varchar, + "status" int NOT NULL, + "access_token_validity_seconds" int NOT NULL, + "refresh_token_validity_seconds" int NOT NULL, + "redirect_uris" varchar NOT NULL, + "authorized_grant_types" varchar NOT NULL, + "scopes" varchar NOT NULL DEFAULT '', + "auto_approve_scopes" varchar NOT NULL DEFAULT '', + "authorities" varchar NOT NULL DEFAULT '', + "resource_ids" varchar NOT NULL DEFAULT '', + "additional_information" varchar NOT NULL DEFAULT '', + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT 'OAuth2 客户端表'; + +CREATE TABLE IF NOT EXISTS "system_oauth2_approve" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" tinyint NOT NULL, + "client_id" varchar NOT NULL, + "scope" varchar NOT NULL, + "approved" bit NOT NULL DEFAULT FALSE, + "expires_time" datetime NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT 'OAuth2 批准表'; + +CREATE TABLE IF NOT EXISTS "system_oauth2_access_token" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" tinyint NOT NULL, + "user_info" varchar NOT NULL, + "access_token" varchar NOT NULL, + "refresh_token" varchar NOT NULL, + "client_id" varchar NOT NULL, + "scopes" varchar NOT NULL, + "approved" bit NOT NULL DEFAULT FALSE, + "expires_time" datetime NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint NOT NULL, + PRIMARY KEY ("id") +) COMMENT 'OAuth2 访问令牌'; + +CREATE TABLE IF NOT EXISTS "system_oauth2_refresh_token" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" tinyint NOT NULL, + "refresh_token" varchar NOT NULL, + "client_id" varchar NOT NULL, + "scopes" varchar NOT NULL, + "approved" bit NOT NULL DEFAULT FALSE, + "expires_time" datetime NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT 'OAuth2 刷新令牌'; + +CREATE TABLE IF NOT EXISTS "system_oauth2_code" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" tinyint NOT NULL, + "code" varchar NOT NULL, + "client_id" varchar NOT NULL, + "scopes" varchar NOT NULL, + "expires_time" datetime NOT NULL, + "redirect_uri" varchar NOT NULL, + "state" varchar NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT 'OAuth2 刷新令牌'; + +CREATE TABLE IF NOT EXISTS "system_mail_account" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "mail" varchar NOT NULL, + "username" varchar NOT NULL, + "password" varchar NOT NULL, + "host" varchar NOT NULL, + "port" int NOT NULL, + "ssl_enable" bit NOT NULL, + "starttls_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '邮箱账号表'; + +CREATE TABLE IF NOT EXISTS "system_mail_template" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "code" varchar NOT NULL, + "account_id" bigint NOT NULL, + "nickname" varchar, + "title" varchar NOT NULL, + "content" varchar NOT NULL, + "params" varchar NOT NULL, + "status" varchar NOT NULL, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '邮件模版表'; + +CREATE TABLE IF NOT EXISTS "system_mail_log" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint, + "user_type" varchar, + "to_mail" varchar NOT NULL, + "account_id" bigint NOT NULL, + "from_mail" varchar NOT NULL, + "template_id" bigint NOT NULL, + "template_code" varchar NOT NULL, + "template_nickname" varchar, + "template_title" varchar NOT NULL, + "template_content" varchar NOT NULL, + "template_params" varchar NOT NULL, + "send_status" varchar NOT NULL, + "send_time" datetime, + "send_message_id" varchar, + "send_exception" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '邮件日志表'; + +-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里 +CREATE TABLE IF NOT EXISTS "system_notify_template" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "code" varchar NOT NULL, + "nickname" varchar NOT NULL, + "content" varchar NOT NULL, + "type" varchar NOT NULL, + "params" varchar, + "status" varchar NOT NULL, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '站内信模板表'; + +CREATE TABLE IF NOT EXISTS "system_notify_message" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "user_id" bigint NOT NULL, + "user_type" varchar NOT NULL, + "template_id" bigint NOT NULL, + "template_code" varchar NOT NULL, + "template_nickname" varchar NOT NULL, + "template_content" varchar NOT NULL, + "template_type" int NOT NULL, + "template_params" varchar NOT NULL, + "read_status" bit NOT NULL, + "read_time" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint not null default '0', + PRIMARY KEY ("id") +) COMMENT '站内信消息表'; diff --git a/ruoyi-vue-pro-master/yudao-server/Dockerfile b/ruoyi-vue-pro-master/yudao-server/Dockerfile new file mode 100644 index 0000000..8fd9574 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/Dockerfile @@ -0,0 +1,23 @@ +## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 +## 感谢复旦核博士的建议!灰子哥,牛皮! +FROM eclipse-temurin:8-jre + +## 创建目录,并使用它作为工作目录 +RUN mkdir -p /yudao-server +WORKDIR /yudao-server +## 将后端项目的 Jar 文件,复制到镜像中 +COPY ./target/yudao-server.jar app.jar + +## 设置 TZ 时区 +ENV TZ=Asia/Shanghai +## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖 +ENV JAVA_OPTS="-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom" + +## 应用参数 +ENV ARGS="" + +## 暴露后端项目的 48080 端口 +EXPOSE 48080 + +## 启动后端项目 +CMD java ${JAVA_OPTS} -jar app.jar $ARGS diff --git a/ruoyi-vue-pro-master/yudao-server/pom.xml b/ruoyi-vue-pro-master/yudao-server/pom.xml new file mode 100644 index 0000000..bc850b5 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/pom.xml @@ -0,0 +1,139 @@ + + + + cn.iocoder.boot + yudao + ${revision} + + 4.0.0 + + yudao-server + jar + + ${project.artifactId} + + 后端 Server 的主项目,通过引入需要 yudao-module-xxx 的依赖, + 从而实现提供 RESTful API 给 yudao-ui-admin、yudao-ui-user 等前端项目。 + 本质上来说,它就是个空壳(容器)! + + https://github.com/YunaiV/ruoyi-vue-pro + + + + cn.iocoder.boot + yudao-module-system-biz + ${revision} + + + cn.iocoder.boot + yudao-module-infra-biz + ${revision} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + cn.iocoder.boot + yudao-spring-boot-starter-protection + + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/YudaoServerApplication.java b/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/YudaoServerApplication.java new file mode 100644 index 0000000..57db3f9 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/YudaoServerApplication.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.server; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 项目的启动类 + * + * 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + * + * @author 芋道源码 + */ +@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}.server", "${yudao.info.base-package}.module"}) +public class YudaoServerApplication { + + public static void main(String[] args) { + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + + SpringApplication.run(YudaoServerApplication.class, args); +// new SpringApplicationBuilder(YudaoServerApplication.class) +// .applicationStartup(new BufferingApplicationStartup(20480)) +// .run(args); + + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 + } + +} diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java b/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java new file mode 100644 index 0000000..a9e6908 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.server.controller; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; + +/** + * 默认 Controller,解决部分 module 未开启时的 404 提示。 + * 例如说,/bpm/** 路径,工作流 + * + * @author 芋道源码 + */ +@RestController +public class DefaultController { + + @RequestMapping("/admin-api/bpm/**") + public CommonResult bpm404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[工作流模块 yudao-module-bpm - 已禁用][参考 https://doc.iocoder.cn/bpm/ 开启]"); + } + + @RequestMapping("/admin-api/mp/**") + public CommonResult mp404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]"); + } + + @RequestMapping(value = {"/admin-api/product/**", // 商品中心 + "/admin-api/trade/**", // 交易中心 + "/admin-api/promotion/**"}) // 营销中心 + public CommonResult mall404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); + } + + @RequestMapping("/admin-api/erp/**") + public CommonResult erp404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[ERP 模块 yudao-module-erp - 已禁用][参考 https://doc.iocoder.cn/erp/build/ 开启]"); + } + + @RequestMapping("/admin-api/crm/**") + public CommonResult crm404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[CRM 模块 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]"); + } + + @RequestMapping(value = {"/admin-api/report/**"}) + public CommonResult report404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]"); + } + + @RequestMapping(value = {"/admin-api/pay/**"}) + public CommonResult pay404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[支付模块 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]"); + } + +} diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-dev.yaml b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-dev.yaml new file mode 100644 index 0000000..e1cfb12 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-dev.yaml @@ -0,0 +1,203 @@ +server: + port: 48080 + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 400-infra.server.iocoder.cn # 地址 + port: 6379 # 端口 + database: 1 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### 定时任务相关配置 #################### + +# Quartz 配置项,对应 QuartzProperties 配置类 +spring: + quartz: + auto-startup: true # 测试环境,需要开启 Job + scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName + job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。 + wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true + properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 + org: + quartz: + # Scheduler 相关配置 + scheduler: + instanceName: schedulerName + instanceId: AUTO # 自动生成 instance ID + # JobStore 相关配置 + jobStore: + # JobStore 实现类。可见博客:https://blog.csdn.net/weixin_42458219/article/details/122247162 + class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + isClustered: true # 是集群模式 + clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒 + misfireThreshold: 60000 # misfire 阀值,单位:毫秒。 + # 线程池相关配置 + threadPool: + threadCount: 25 # 线程池大小。默认为 10 。 + threadPriority: 5 # 线程优先级 + class: org.quartz.simpl.SimpleThreadPool # 线程池类型 + jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置 + initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。 + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: guest # RabbitMQ 服务的账号 + password: guest # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +# 日志文件配置 +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 微信公众号相关配置 #################### +wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 + mp: + # 公众号配置(必填) + app-id: wx041349c6f39b268b + secret: 5abee519483bc9f8cb37ce280e814bd0 + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 + appid: wx63c280fe3248a3e7 + secret: 6f270509224a7ae1296bbf1c8cb97aed + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wa # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + pay: + order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + demo: true # 开启演示模式 + tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + +justauth: + enabled: true + type: + DINGTALK: # 钉钉 + client-id: dingvrnreaje3yqvzhxg + client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI + ignore-check-redirect-uri: true + WECHAT_ENTERPRISE: # 企业微信 + client-id: wwd411c69a39ad2e54 + client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw + agent-id: 1000004 + ignore-check-redirect-uri: true + # noinspection SpringBootApplicationYaml + WECHAT_MINI_APP: # 微信小程序 + client-id: ${wx.miniapp.appid} + client-secret: ${wx.miniapp.secret} + ignore-check-redirect-uri: true + ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 + WECHAT_MP: # 微信公众号 + client-id: ${wx.mp.app-id} + client-secret: ${wx.mp.secret} + ignore-check-redirect-uri: true + cache: + type: REDIS + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-local.yaml b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-local.yaml new file mode 100644 index 0000000..63a0d9d --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application-local.yaml @@ -0,0 +1,255 @@ +server: + port: 48080 + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 + - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 + - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 + - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 + # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 + # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 + # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 + username: root + password: 123456 + # username: sa # SQL Server 连接的示例 + # password: Yudao@2024 # SQL Server 连接的示例 + # username: SYSDBA # DM 连接的示例 + # password: SYSDBA001 # DM 连接的示例 + # username: root # OpenGauss 连接的示例 + # password: Yudao@2024 # OpenGauss 连接的示例 + slave: # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: dev # 密码,建议生产环境开启 + +--- #################### 定时任务相关配置 #################### + +# Quartz 配置项,对应 QuartzProperties 配置类 +spring: + quartz: + auto-startup: true # 本地开发环境,尽量不要开启 Job + scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName + job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。 + wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true + properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 + org: + quartz: + # Scheduler 相关配置 + scheduler: + instanceName: schedulerName + instanceId: AUTO # 自动生成 instance ID + # JobStore 相关配置 + jobStore: + # JobStore 实现类。可见博客:https://blog.csdn.net/weixin_42458219/article/details/122247162 + class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + isClustered: true # 是集群模式 + clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒 + misfireThreshold: 60000 # misfire 阀值,单位:毫秒。 + # 线程池相关配置 + threadPool: + threadCount: 25 # 线程池大小。默认为 10 。 + threadPriority: 5 # 线程优先级 + class: org.quartz.simpl.SimpleThreadPool # 线程池类型 + jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置 + initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。 + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + +spring: + # RabbitMQ 配置项,对应 RabbitProperties 配置类 + rabbitmq: + host: 127.0.0.1 # RabbitMQ 服务的地址 + port: 5672 # RabbitMQ 服务的端口 + username: rabbit # RabbitMQ 服务的账号 + password: rabbit # RabbitMQ 服务的密码 + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + # Spring Boot Admin Server 服务端的相关配置 + context-path: /admin # 配置 Spring + +# 日志文件配置 +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + level: + # 配置自己写的 MyBatis Mapper 打印日志 + cn.iocoder.yudao.module.bpm.dal.mysql: debug + cn.iocoder.yudao.module.infra.dal.mysql: debug + cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 配置 ApiErrorLogMapper 的日志级别为 info,避免和 GlobalExceptionHandler 重复打印 + cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info + cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper: INFO # 配置 FileConfigMapper 的日志级别为 info + cn.iocoder.yudao.module.pay.dal.mysql: debug + cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 PayNotifyTaskMapper 的日志级别为 info + cn.iocoder.yudao.module.system.dal.mysql: debug + cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info + cn.iocoder.yudao.module.tool.dal.mysql: debug + cn.iocoder.yudao.module.member.dal.mysql: debug + cn.iocoder.yudao.module.trade.dal.mysql: debug + cn.iocoder.yudao.module.promotion.dal.mysql: debug + cn.iocoder.yudao.module.statistics.dal.mysql: debug + cn.iocoder.yudao.module.crm.dal.mysql: debug + cn.iocoder.yudao.module.erp.dal.mysql: debug + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + +debug: false + +--- #################### 微信公众号、小程序相关配置 #################### +wx: + mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 +# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) +# secret: 5abee519483bc9f8cb37ce280e814bd0 + app-id: wx5b23ba7a5589ecbb # 测试号(自己的) + secret: 2a7b3b20c537e52e74afd395eb85f61f +# app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) +# secret: bd4f9fab889591b62aeac0d7b8d8b4a0 + # 存储配置,解决 AccessToken 的跨节点的共享 + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wx # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 + # appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的) + # secret: 333ae72f41552af1e998fe1f54e1584a + appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 + secret: 6f270509224a7ae1296bbf1c8cb97aed +# appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) +# secret: 4a1a04e07f6a4a0751b39c3064a92c8b + config-storage: + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 + key-prefix: wa # Redis Key 的前缀 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + captcha: + enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试; + security: + mock-enable: true + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + pay: + order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 + refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 + access-log: # 访问日志的配置项 + enable: false + demo: false # 关闭演示模式 + tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + +justauth: + enabled: true + type: + DINGTALK: # 钉钉 + client-id: dingvrnreaje3yqvzhxg + client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI + ignore-check-redirect-uri: true + WECHAT_ENTERPRISE: # 企业微信 + client-id: wwd411c69a39ad2e54 + client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw + agent-id: 1000004 + ignore-check-redirect-uri: true + # noinspection SpringBootApplicationYaml + WECHAT_MINI_APP: # 微信小程序 + client-id: ${wx.miniapp.appid} + client-secret: ${wx.miniapp.secret} + ignore-check-redirect-uri: true + ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 + WECHAT_MP: # 微信公众号 + client-id: ${wx.mp.app-id} + client-secret: ${wx.mp.secret} + ignore-check-redirect-uri: true + cache: + type: REDIS + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 + diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/resources/application.yaml b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application.yaml new file mode 100644 index 0000000..6cb5386 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/resources/application.yaml @@ -0,0 +1,264 @@ +spring: + application: + name: yudao-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + mvc: + pathmatch: + matching-strategy: ANT_PATH_MATCHER # 解决 SpringFox 与 SpringBoot 2.6.x 不兼容的问题,参见 SpringFoxHandlerProviderBeanPostProcessor 类 +# throw-exception-if-no-handler-found: true # 404 错误时抛出异常,方便统一处理 +# static-path-pattern: /static/** # 静态资源路径; 注意:如果不配置,则 throw-exception-if-no-handler-found 不生效!!! TODO 芋艿:不能配置,会导致 swagger 不生效 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 Date 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +--- #################### 接口文档配置 #################### + +springdoc: + api-docs: + enabled: true + path: /v3/api-docs + swagger-ui: + enabled: true + path: /swagger-ui + default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 + +knife4j: + enable: true + setting: + language: zh_cn + +# 工作流 Flowable 配置 +flowable: + # 1. false: 默认值,Flowable 启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常 + # 2. true: 启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表 + # 3. create_drop: 启动时自动创建表,关闭时自动删除表 + # 4. drop_create: 启动时,删除旧表,再创建新表 + database-schema-update: true # 设置为 false,可通过 https://github.com/flowable/flowable-sql 初始化 + db-history-used: true # flowable6 默认 true 生成信息表,无需手动设置 + check-process-definitions: false # 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程 + history-level: audit # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 +# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 +# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 +# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + banner: false # 关闭控制台的 Banner 打印 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + encryptor: + password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 + +mybatis-plus-join: + banner: false # 是否打印 mybatis plus join banner,默认true + sub-table-logic: true # 全局启用副表逻辑删除,默认true。关闭后关联查询不会加副表逻辑删除 + ms-cache: true # 拦截器MappedStatement缓存,默认 true + table-alias: t # 表别名(默认 t) + logic-del-type: on # 副表逻辑删除条件的位置,支持 WHERE、ON,默认 ON + +# Spring Data Redis 配置 +spring: + data: + redis: + repositories: + enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度 + +# VO 转换(数据翻译)相关 +easy-trans: + is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 + is-enable-cloud: false # 禁用 TransType.RPC 微服务模式 + +--- #################### 验证码相关配置 #################### + +aj: + captcha: + jigsaw: classpath:images/jigsaw # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 + pic-click: classpath:images/pic-click # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 + cache-type: redis # 缓存 local/redis... + cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存 + timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行 + type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选 + water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode + interference-options: 0 # 滑动干扰项(0/1/2) + req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false + req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定 + req-get-lock-seconds: 10 # 验证失败后,锁定时间间隔 + req-get-minute-limit: 30 # get 接口一分钟内请求数限制 + req-check-minute-limit: 60 # check 接口一分钟内请求数限制 + req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制 + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + # Producer 配置项 + producer: + group: ${spring.application.name}_PRODUCER # 生产者分组 + +spring: + # Kafka 配置项,对应 KafkaProperties 配置类 + kafka: + # Kafka Producer 配置项 + producer: + acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。 + retries: 3 # 发送失败时,重试发送的次数 + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化 + # Kafka Consumer 配置项 + consumer: + auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解 + value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer + properties: + spring.json.trusted.packages: '*' + # Kafka Consumer Listener 监听器配置 + listener: + missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错 + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 + base-package: cn.iocoder.yudao + web: + admin-ui: + url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + security: + permit-all_urls: + - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,不需要登录 + websocket: + enable: true # websocket的开关 + path: /infra/ws # 路径 + sender-type: local # 消息发送的类型,可选值为 local、redis、rocketmq、kafka、rabbitmq + sender-rocketmq: + topic: ${spring.application.name}-websocket # 消息发送的 RocketMQ Topic + consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 RocketMQ Consumer Group + sender-rabbitmq: + exchange: ${spring.application.name}-websocket-exchange # 消息发送的 RabbitMQ Exchange + queue: ${spring.application.name}-websocket-queue # 消息发送的 RabbitMQ Queue + sender-kafka: + topic: ${spring.application.name}-websocket # 消息发送的 Kafka Topic + consumer-group: ${spring.application.name}-websocket-consumer # 消息发送的 Kafka Consumer Group + swagger: + title: 芋道快速开发平台 + description: 提供管理后台、用户 App 的所有功能 + version: ${yudao.info.version} + url: ${yudao.web.admin-ui.url} + email: xingyu4j@vip.qq.com + license: MIT + license-url: https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE + captcha: + enable: true # 验证码的开关,默认为 true + codegen: + base-package: ${yudao.info.base-package} + db-schemas: ${spring.datasource.dynamic.datasource.master.name} + front-type: 10 # 前端模版的类型,参见 CodegenFrontTypeEnum 枚举类 + tenant: # 多租户相关配置项 + enable: true + ignore-urls: + - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 + - /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号 + - /admin-api/system/captcha/get # 获取图片验证码,和租户无关 + - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 + - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 + - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 + - /admin-api/pay/notify/** # 支付回调通知,不携带租户编号 + - /jmreport/* # 积木报表,无法携带租户编号 + - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号 + ignore-tables: + - system_tenant + - system_tenant_package + - system_dict_data + - system_dict_type + - system_error_code + - system_menu + - system_sms_channel + - system_sms_template + - system_sms_log + - system_sensitive_word + - system_oauth2_client + - system_mail_account + - system_mail_template + - system_mail_log + - system_notify_template + - infra_codegen_column + - infra_codegen_table + - infra_config + - infra_file_config + - infra_file + - infra_file_content + - infra_job + - infra_job_log + - infra_job_log + - infra_data_source_config + - jimu_dict + - jimu_dict_item + - jimu_report + - jimu_report_data_source + - jimu_report_db + - jimu_report_db_field + - jimu_report_db_param + - jimu_report_link + - jimu_report_map + - jimu_report_share + - rep_demo_dxtj + - rep_demo_employee + - rep_demo_gongsi + - rep_demo_jianpiao + - tmp_report_data_1 + - tmp_report_data_income + sms-code: # 短信验证码相关的配置项 + expire-times: 10m + send-frequency: 1m + send-maximum-quantity-per-day: 10 + begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 + end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + trade: + order: + app-id: 1 # 商户编号 + pay-expire-time: 2h # 支付的过期时间 + receive-expire-time: 14d # 收货的过期时间 + comment-expire-time: 7d # 评论的过期时间 + express: + client: kd_niao + kd-niao: + api-key: cb022f1e-48f1-4c4a-a723-9001ac9676b8 + business-id: 1809751 + kd100: + key: pLXUGAwK5305 + customer: E77DF18BE109F454A5CD319E44BF5177 + +debug: false + +# 积木报表配置 +jeecg: + jmreport: + saas-mode: tenant \ No newline at end of file diff --git a/ruoyi-vue-pro-master/yudao-server/src/main/resources/logback-spring.xml b/ruoyi-vue-pro-master/yudao-server/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..b1b9f3f --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-vue-pro-master/yudao-server/src/test/java/cn/iocoder/yudao/ProjectReactor.java b/ruoyi-vue-pro-master/yudao-server/src/test/java/cn/iocoder/yudao/ProjectReactor.java new file mode 100644 index 0000000..84a91e3 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-server/src/test/java/cn/iocoder/yudao/ProjectReactor.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao; + +import cn.hutool.core.io.FileTypeUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.stream.Collectors; + +import static java.io.File.separator; + +/** + * 项目修改器,一键替换 Maven 的 groupId、artifactId,项目的 package 等 + *

+ * 通过修改 groupIdNew、artifactIdNew、projectBaseDirNew 三个变量 + * + * @author 芋道源码 + */ +@Slf4j +public class ProjectReactor { + + private static final String GROUP_ID = "cn.iocoder.boot"; + private static final String ARTIFACT_ID = "yudao"; + private static final String PACKAGE_NAME = "cn.iocoder.yudao"; + private static final String TITLE = "芋道管理系统"; + + /** + * 白名单文件,不进行重写,避免出问题 + */ + private static final Set WHITE_FILE_TYPES = SetUtils.asSet("gif", "jpg", "svg", "png", // 图片 + "eot", "woff2", "ttf", "woff", // 字体 + "xdb"); // IP 库 + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + String projectBaseDir = getProjectBaseDir(); + log.info("[main][原项目路劲改地址 ({})]", projectBaseDir); + + // ========== 配置,需要你手动修改 ========== + String groupIdNew = "cn.star.gg"; + String artifactIdNew = "star"; + String packageNameNew = "cn.start.pp"; + String titleNew = "土豆管理系统"; + String projectBaseDirNew = projectBaseDir + "-new"; // 一键改名后,“新”项目所在的目录 + log.info("[main][检测新项目目录 ({})是否存在]", projectBaseDirNew); + if (FileUtil.exist(projectBaseDirNew)) { + log.error("[main][新项目目录检测 ({})已存在,请更改新的目录!程序退出]", projectBaseDirNew); + return; + } + // 如果新目录中存在 PACKAGE_NAME,ARTIFACT_ID 等关键字,路径会被替换,导致生成的文件不在预期目录 + if (StrUtil.containsAny(projectBaseDirNew, PACKAGE_NAME, ARTIFACT_ID, StrUtil.upperFirst(ARTIFACT_ID))) { + log.error("[main][新项目目录 `projectBaseDirNew` 检测 ({}) 存在冲突名称「{}」或者「{}」,请更改新的目录!程序退出]", + projectBaseDirNew, PACKAGE_NAME, ARTIFACT_ID); + return; + } + log.info("[main][完成新项目目录检测,新项目路径地址 ({})]", projectBaseDirNew); + // 获得需要复制的文件 + log.info("[main][开始获得需要重写的文件,预计需要 10-20 秒]"); + Collection files = listFiles(projectBaseDir); + log.info("[main][需要重写的文件数量:{},预计需要 15-30 秒]", files.size()); + // 写入文件 + files.forEach(file -> { + // 如果是白名单的文件类型,不进行重写,直接拷贝 + String fileType = getFileType(file); + if (WHITE_FILE_TYPES.contains(fileType)) { + copyFile(file, projectBaseDir, projectBaseDirNew, packageNameNew, artifactIdNew); + return; + } + // 如果非白名单的文件类型,重写内容,在生成文件 + String content = replaceFileContent(file, groupIdNew, artifactIdNew, packageNameNew, titleNew); + writeFile(file, content, projectBaseDir, projectBaseDirNew, packageNameNew, artifactIdNew); + }); + log.info("[main][重写完成]共耗时:{} 秒", (System.currentTimeMillis() - start) / 1000); + } + + private static String getProjectBaseDir() { + String baseDir = System.getProperty("user.dir"); + if (StrUtil.isEmpty(baseDir)) { + throw new NullPointerException("项目基础路径不存在"); + } + return baseDir; + } + + private static Collection listFiles(String projectBaseDir) { + Collection files = FileUtil.loopFiles(projectBaseDir); + // 移除 IDEA、Git 自身的文件、Node 编译出来的文件 + files = files.stream() + .filter(file -> !file.getPath().contains(separator + "target" + separator) + && !file.getPath().contains(separator + "node_modules" + separator) + && !file.getPath().contains(separator + ".idea" + separator) + && !file.getPath().contains(separator + ".git" + separator) + && !file.getPath().contains(separator + "dist" + separator) + && !file.getPath().contains(".iml") + && !file.getPath().contains(".html.gz")) + .collect(Collectors.toList()); + return files; + } + + private static String replaceFileContent(File file, String groupIdNew, + String artifactIdNew, String packageNameNew, + String titleNew) { + String content = FileUtil.readString(file, StandardCharsets.UTF_8); + // 如果是白名单的文件类型,不进行重写 + String fileType = getFileType(file); + if (WHITE_FILE_TYPES.contains(fileType)) { + return content; + } + // 执行文件内容都重写 + return content.replaceAll(GROUP_ID, groupIdNew) + .replaceAll(PACKAGE_NAME, packageNameNew) + .replaceAll(ARTIFACT_ID, artifactIdNew) // 必须放在最后替换,因为 ARTIFACT_ID 太短! + .replaceAll(StrUtil.upperFirst(ARTIFACT_ID), StrUtil.upperFirst(artifactIdNew)) + .replaceAll(TITLE, titleNew); + } + + private static void writeFile(File file, String fileContent, String projectBaseDir, + String projectBaseDirNew, String packageNameNew, String artifactIdNew) { + String newPath = buildNewFilePath(file, projectBaseDir, projectBaseDirNew, packageNameNew, artifactIdNew); + FileUtil.writeUtf8String(fileContent, newPath); + } + + private static void copyFile(File file, String projectBaseDir, + String projectBaseDirNew, String packageNameNew, String artifactIdNew) { + String newPath = buildNewFilePath(file, projectBaseDir, projectBaseDirNew, packageNameNew, artifactIdNew); + FileUtil.copyFile(file, new File(newPath)); + } + + private static String buildNewFilePath(File file, String projectBaseDir, + String projectBaseDirNew, String packageNameNew, String artifactIdNew) { + return file.getPath().replace(projectBaseDir, projectBaseDirNew) // 新目录 + .replace(PACKAGE_NAME.replaceAll("\\.", Matcher.quoteReplacement(separator)), + packageNameNew.replaceAll("\\.", Matcher.quoteReplacement(separator))) + .replace(ARTIFACT_ID, artifactIdNew) // + .replaceAll(StrUtil.upperFirst(ARTIFACT_ID), StrUtil.upperFirst(artifactIdNew)); + } + + private static String getFileType(File file) { + return file.length() > 0 ? FileTypeUtil.getType(file) : ""; + } + +} diff --git a/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-uniapp/README.md b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-uniapp/README.md new file mode 100644 index 0000000..9f72209 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-uniapp/README.md @@ -0,0 +1,4 @@ +基于 Vue + uni-app 实现的管理后台。仓库地址: + +* Gitee: +* GitHub: diff --git a/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vben/README.md b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vben/README.md new file mode 100644 index 0000000..c6a866c --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vben/README.md @@ -0,0 +1,4 @@ +基于 Vue3 + vben(ant-design-vue) 实现的管理后台。仓库地址: + +* Gitee: +* GitHub: diff --git a/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue2/README.md b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue2/README.md new file mode 100644 index 0000000..f1fbdad --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue2/README.md @@ -0,0 +1,4 @@ +基于 Vue2 + element-ui 实现的管理后台。仓库地址: + +* Gitee: +* GitHub: diff --git a/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue3/README.md b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue3/README.md new file mode 100644 index 0000000..6983c52 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-admin-vue3/README.md @@ -0,0 +1,4 @@ +基于 Vue3 + element-plus 实现的管理后台。仓库地址: + +* Gitee: +* GitHub: diff --git a/ruoyi-vue-pro-master/yudao-ui/yudao-ui-mall-uniapp/README.md b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-mall-uniapp/README.md new file mode 100644 index 0000000..57b1868 --- /dev/null +++ b/ruoyi-vue-pro-master/yudao-ui/yudao-ui-mall-uniapp/README.md @@ -0,0 +1,8 @@ +仓库地址: + +* Gitee: +* GitHub: + +功能列表: +* 基于 uniapp 开发,支持微信小程序、微信公众号、H5 移动端,未来会支持支付宝小程序、抖音小程序等 +* 支持 SaaS 多租户,可满足商品、订单、支付、会员、优惠券、秒杀、拼团、砍价、分销、积分等多种经营需求 diff --git a/yudao-mall-uniapp-master/.gitignore b/yudao-mall-uniapp-master/.gitignore new file mode 100644 index 0000000..0670590 --- /dev/null +++ b/yudao-mall-uniapp-master/.gitignore @@ -0,0 +1,12 @@ +unpackage/* +node_modules/* +.idea/* +deploy.sh +.hbuilderx/ +.vscode/ +**/.DS_Store +.env +yarn.lock +package-lock.json +*.keystore +pnpm-lock.yaml diff --git a/yudao-mall-uniapp-master/.image/common/mall-feature.png b/yudao-mall-uniapp-master/.image/common/mall-feature.png new file mode 100644 index 0000000..25b8d11 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/mall-feature.png differ diff --git a/yudao-mall-uniapp-master/.image/common/mall-preview.png b/yudao-mall-uniapp-master/.image/common/mall-preview.png new file mode 100644 index 0000000..e164cd2 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/mall-preview.png differ diff --git a/yudao-mall-uniapp-master/.image/common/project-vs.png b/yudao-mall-uniapp-master/.image/common/project-vs.png new file mode 100644 index 0000000..561e092 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/project-vs.png differ diff --git a/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-architecture.png b/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-architecture.png new file mode 100644 index 0000000..7bd7d59 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-architecture.png differ diff --git a/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-biz.png b/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-biz.png new file mode 100644 index 0000000..24a385a Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/ruoyi-vue-pro-biz.png differ diff --git a/yudao-mall-uniapp-master/.image/common/yudao-cloud-architecture.png b/yudao-mall-uniapp-master/.image/common/yudao-cloud-architecture.png new file mode 100644 index 0000000..59416d8 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/yudao-cloud-architecture.png differ diff --git a/yudao-mall-uniapp-master/.image/common/yudao-roadmap.png b/yudao-mall-uniapp-master/.image/common/yudao-roadmap.png new file mode 100644 index 0000000..f4becc9 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/common/yudao-roadmap.png differ diff --git a/yudao-mall-uniapp-master/.image/mall/会员详情.png b/yudao-mall-uniapp-master/.image/mall/会员详情.png new file mode 100644 index 0000000..108c59b Binary files /dev/null and b/yudao-mall-uniapp-master/.image/mall/会员详情.png differ diff --git a/yudao-mall-uniapp-master/.image/mall/商品详情.png b/yudao-mall-uniapp-master/.image/mall/商品详情.png new file mode 100644 index 0000000..1236b0b Binary files /dev/null and b/yudao-mall-uniapp-master/.image/mall/商品详情.png differ diff --git a/yudao-mall-uniapp-master/.image/mall/店铺装修.png b/yudao-mall-uniapp-master/.image/mall/店铺装修.png new file mode 100644 index 0000000..d583c6b Binary files /dev/null and b/yudao-mall-uniapp-master/.image/mall/店铺装修.png differ diff --git a/yudao-mall-uniapp-master/.image/mall/营销中心.png b/yudao-mall-uniapp-master/.image/mall/营销中心.png new file mode 100644 index 0000000..4007a0a Binary files /dev/null and b/yudao-mall-uniapp-master/.image/mall/营销中心.png differ diff --git a/yudao-mall-uniapp-master/.image/mall/订单详情.png b/yudao-mall-uniapp-master/.image/mall/订单详情.png new file mode 100644 index 0000000..ede2046 Binary files /dev/null and b/yudao-mall-uniapp-master/.image/mall/订单详情.png differ diff --git a/yudao-mall-uniapp-master/.prettierignore b/yudao-mall-uniapp-master/.prettierignore new file mode 100644 index 0000000..7384df0 --- /dev/null +++ b/yudao-mall-uniapp-master/.prettierignore @@ -0,0 +1,6 @@ +/unpackage/* +/node_modules/** +/uni_modules/** +/public/* +**/*.svg +**/*.sh diff --git a/yudao-mall-uniapp-master/.prettierrc b/yudao-mall-uniapp-master/.prettierrc new file mode 100644 index 0000000..fe0a3f9 --- /dev/null +++ b/yudao-mall-uniapp-master/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 100, + "semi": true, + "vueIndentScriptAndStyle": true, + "singleQuote": true, + "trailingComma": "all", + "proseWrap": "never", + "htmlWhitespaceSensitivity": "strict", + "endOfLine": "auto" +} diff --git a/yudao-mall-uniapp-master/App.vue b/yudao-mall-uniapp-master/App.vue new file mode 100644 index 0000000..485b5cb --- /dev/null +++ b/yudao-mall-uniapp-master/App.vue @@ -0,0 +1,39 @@ + + + diff --git a/yudao-mall-uniapp-master/LICENSE b/yudao-mall-uniapp-master/LICENSE new file mode 100644 index 0000000..9799627 --- /dev/null +++ b/yudao-mall-uniapp-master/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 lidongtony + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yudao-mall-uniapp-master/README.md b/yudao-mall-uniapp-master/README.md new file mode 100644 index 0000000..2aeb2e4 --- /dev/null +++ b/yudao-mall-uniapp-master/README.md @@ -0,0 +1,56 @@ +**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!** + +**「我喜欢写代码,乐此不疲」** +**「我喜欢做开源,以此为乐」** + +我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。 + +如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 + +## 🐶 新手必读 + +* 演示地址: +* 启动文档: +* 视频教程: + +## 🐯 商城简介 + +**芋道商城**,基于 [芋道开发平台](https://github.com/YunaiV/ruoyi-vue-pro) 构建,以开发者为中心,打造中国第一流的 Java 开源商城系统,全部开源,个人与企业可 100% 免费使用。 + +> 有任何问题,或者想要的功能,可以在 Issues 中提给艿艿。 +> +> 😜 给项目点点 Star 吧,这对我们真的很重要! + +![功能图](/.image/common/mall-feature.png) + +* 基于 uni-app + Vue3 开发,支持微信小程序、微信公众号、H5 移动端,未来会支持支付宝小程序、抖音小程序等 +* 支持 SaaS 多租户,可满足商品、订单、支付、会员、优惠券、秒杀、拼团、砍价、分销、积分等多种经营需求 + +## 🔥 后端架构 + +支持 Spring Boot、Spring Cloud 两种架构: + +① Spring Boot 单体架构: + +![架构图](/.image/common/ruoyi-vue-pro-architecture.png) + +② Spring Cloud 微服务架构: + +![架构图](/.image/common/yudao-cloud-architecture.png) + +## 🐱 移动端预览 + +![移动端预览](/.image/common/mall-preview.png) + +## 🐶 管理端预览 + +![店铺装修](/.image/mall/店铺装修.png) + +![会员详情](/.image/mall/会员详情.png) + +![商品详情](/.image/mall/商品详情.png) + +![订单详情](/.image/mall/订单详情.png) + +![营销中心](/.image/mall/营销中心.png) + diff --git a/yudao-mall-uniapp-master/androidPrivacy.json b/yudao-mall-uniapp-master/androidPrivacy.json new file mode 100644 index 0000000..0d726ca --- /dev/null +++ b/yudao-mall-uniapp-master/androidPrivacy.json @@ -0,0 +1,3 @@ +{ + "prompt" : "template" +} diff --git a/yudao-mall-uniapp-master/index.html b/yudao-mall-uniapp-master/index.html new file mode 100644 index 0000000..2269a69 --- /dev/null +++ b/yudao-mall-uniapp-master/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + +

+ + + diff --git a/yudao-mall-uniapp-master/jsconfig.json b/yudao-mall-uniapp-master/jsconfig.json new file mode 100644 index 0000000..b1968ee --- /dev/null +++ b/yudao-mall-uniapp-master/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "baseUrl": ".", + "paths": { + "@/*": ["./*"] + } + } +} diff --git a/yudao-mall-uniapp-master/main.js b/yudao-mall-uniapp-master/main.js new file mode 100644 index 0000000..2680ac6 --- /dev/null +++ b/yudao-mall-uniapp-master/main.js @@ -0,0 +1,15 @@ +import App from './App'; +import { createSSRApp } from 'vue'; +import { setupPinia } from './sheep/store'; + + +export function createApp() { + + const app = createSSRApp(App); + + setupPinia(app); + + return { + app, + }; +} diff --git a/yudao-mall-uniapp-master/manifest.json b/yudao-mall-uniapp-master/manifest.json new file mode 100644 index 0000000..e0a75df --- /dev/null +++ b/yudao-mall-uniapp-master/manifest.json @@ -0,0 +1,239 @@ +{ + "name": "芋道商城", + "appid": "__UNI__460BC4C", + "description": "基于 uni-app + Vue3 技术驱动的在线商城系统,内含诸多功能与丰富的活动,期待您的使用和反馈。", + "versionName": "2.1.0", + "versionCode": 183, + "transformPx": false, + "app-plus": { + "usingComponents": true, + "nvueCompiler": "uni-app", + "nvueStyleCompiler": "uni-app", + "compilerVersion": 3, + "nvueLaunchMode": "fast", + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + "safearea": { + "bottom": { + "offset": "none" + } + }, + "modules": { + "Payment": {}, + "Share": {}, + "VideoPlayer": {}, + "OAuth": {} + }, + "distribute": { + "android": { + "permissions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "minSdkVersion": 21, + "schemes": "shopro" + }, + "ios": { + "urlschemewhitelist": [ + "baidumap", + "iosamap" + ], + "dSYMs": false, + "privacyDescription": { + "NSPhotoLibraryUsageDescription": "需要同意访问您的相册选取图片才能完善该条目", + "NSPhotoLibraryAddUsageDescription": "需要同意访问您的相册才能保存该图片", + "NSCameraUsageDescription": "需要同意访问您的摄像头拍摄照片才能完善该条目", + "NSUserTrackingUsageDescription": "开启追踪并不会获取您在其它站点的隐私信息,该行为仅用于标识设备,保障服务安全和提升浏览体验" + }, + "urltypes": "shopro", + "capabilities": { + "entitlements": { + "com.apple.developer.associated-domains": [ + "applinks:shopro.sheepjs.com" + ] + } + }, + "idfa": true + }, + "sdkConfigs": { + "speech": { + "ifly": {} + }, + "ad": {}, + "oauth": { + "apple": {}, + "weixin": { + "appid": "wxae7a0c156da9383b", + "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/" + } + }, + "payment": { + "weixin": { + "__platform__": [ + "ios", + "android" + ], + "appid": "wxae7a0c156da9383b", + "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/" + }, + "alipay": { + "__platform__": [ + "ios", + "android" + ] + } + }, + "share": { + "weixin": { + "appid": "wxae7a0c156da9383b", + "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/" + } + } + }, + "orientation": [ + "portrait-primary" + ], + "splashscreen": { + "androidStyle": "common", + "iosStyle": "common", + "useOriginalMsgbox": true + }, + "icons": { + "android": { + "hdpi": "unpackage/res/icons/72x72.png", + "xhdpi": "unpackage/res/icons/96x96.png", + "xxhdpi": "unpackage/res/icons/144x144.png", + "xxxhdpi": "unpackage/res/icons/192x192.png" + }, + "ios": { + "appstore": "unpackage/res/icons/1024x1024.png", + "ipad": { + "app": "unpackage/res/icons/76x76.png", + "app@2x": "unpackage/res/icons/152x152.png", + "notification": "unpackage/res/icons/20x20.png", + "notification@2x": "unpackage/res/icons/40x40.png", + "proapp@2x": "unpackage/res/icons/167x167.png", + "settings": "unpackage/res/icons/29x29.png", + "settings@2x": "unpackage/res/icons/58x58.png", + "spotlight": "unpackage/res/icons/40x40.png", + "spotlight@2x": "unpackage/res/icons/80x80.png" + }, + "iphone": { + "app@2x": "unpackage/res/icons/120x120.png", + "app@3x": "unpackage/res/icons/180x180.png", + "notification@2x": "unpackage/res/icons/40x40.png", + "notification@3x": "unpackage/res/icons/60x60.png", + "settings@2x": "unpackage/res/icons/58x58.png", + "settings@3x": "unpackage/res/icons/87x87.png", + "spotlight@2x": "unpackage/res/icons/80x80.png", + "spotlight@3x": "unpackage/res/icons/120x120.png" + } + } + } + } + }, + "quickapp": {}, + "quickapp-native": { + "icon": "/static/logo.png", + "package": "com.example.demo", + "features": [ + { + "name": "system.clipboard" + } + ] + }, + "quickapp-webview": { + "icon": "/static/logo.png", + "package": "com.example.demo", + "minPlatformVersion": 1070, + "versionName": "1.0.0", + "versionCode": 100 + }, + "mp-weixin": { + "appid": "wx98df718e528399d2", + "setting": { + "urlCheck": false, + "minified": true, + "postcss": true + }, + "optimization": { + "subPackages": true + }, + "plugins": {}, + "lazyCodeLoading": "requiredComponents", + "usingComponents": {}, + "permission": {}, + "requiredPrivateInfos": [ + "chooseAddress" + ] + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "mp-jd": { + "usingComponents": true + }, + "h5": { + "template": "index.html", + "router": { + "mode": "hash", + "base": "./" + }, + "sdkConfigs": { + "maps": {} + }, + "async": { + "timeout": 20000 + }, + "title": "芋道商城", + "optimization": { + "treeShaking": { + "enable": true + } + } + }, + "vueVersion": "3", + "_spaceID": "192b4892-5452-4e1d-9f09-eee1ece40639", + "locale": "zh-Hans", + "fallbackLocale": "zh-Hans" +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/package.json b/yudao-mall-uniapp-master/package.json new file mode 100644 index 0000000..d83ca3a --- /dev/null +++ b/yudao-mall-uniapp-master/package.json @@ -0,0 +1,103 @@ +{ + "id": "shopro", + "name": "shopro", + "displayName": "芋道商城", + "version": "2.1.0", + "description": "芋道商城,一套代码,同时发行到iOS、Android、H5、微信小程序多个平台,请使用手机扫码快速体验强大功能", + "scripts": { + "prettier": "prettier --write \"{pages,sheep}/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"" + }, + "repository": "https://github.com/sheepjs/shop.git", + "keywords": [ + "商城", + "B2C", + "商城模板" + ], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/sheepjs/shop/issues" + }, + "homepage": "https://github.com/dcloudio/hello-uniapp#readme", + "dcloudext": { + "category": [ + "前端页面模板", + "uni-app前端项目模板" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "u", + "vue3": "y" + } + } + } + }, + "dependencies": { + "@hyoga/uni-socket.io": "^1.0.1", + "dayjs": "^1.11.7", + "lodash": "^4.17.21", + "luch-request": "^3.0.8", + "pinia": "^2.0.33", + "pinia-plugin-persist-uni": "^1.2.0", + "weixin-js-sdk": "^1.6.0" + }, + "devDependencies": { + "prettier": "^2.8.7", + "vconsole": "^3.15.0" + } +} diff --git a/yudao-mall-uniapp-master/pages.json b/yudao-mall-uniapp-master/pages.json new file mode 100644 index 0000000..1e14b74 --- /dev/null +++ b/yudao-mall-uniapp-master/pages.json @@ -0,0 +1,655 @@ +{ + "easycom": { + "autoscan": true, + "custom": { + "^s-(.*)": "@/sheep/components/s-$1/s-$1.vue", + "^su-(.*)": "@/sheep/ui/su-$1/su-$1.vue" + } + }, + "pages": [{ + "path": "pages/index/index", + "aliasPath": "/", + "style": { + "navigationBarTitleText": "首页", + "enablePullDownRefresh": true + }, + "meta": { + "auth": false, + "sync": true, + "title": "首页", + "group": "商城" + } + }, + { + "path": "pages/index/user", + "style": { + "navigationBarTitleText": "个人中心", + "enablePullDownRefresh": true + }, + "meta": { + "sync": true, + "title": "个人中心", + "group": "商城" + } + }, + { + "path": "pages/index/category", + "style": { + "navigationBarTitleText": "商品分类" + }, + "meta": { + "sync": true, + "title": "商品分类", + "group": "商城" + } + }, + { + "path": "pages/index/cart", + "style": { + "navigationBarTitleText": "购物车" + }, + "meta": { + "sync": true, + "title": "购物车", + "group": "商城" + } + }, + { + "path": "pages/index/login", + "style": { + "navigationBarTitleText": "登录" + } + }, + { + "path": "pages/index/search", + "style": { + "navigationBarTitleText": "搜索" + }, + "meta": { + "sync": true, + "title": "搜索", + "group": "商城" + } + }, + { + "path": "pages/index/page", + "style": { + "navigationBarTitleText": "" + }, + "meta": { + "auth": false, + "sync": true, + "title": "自定义页面", + "group": "商城" + } + } + ], + "subPackages": [{ + "root": "pages/goods", + "pages": [{ + "path": "index", + "style": { + "navigationBarTitleText": "商品详情" + }, + "meta": { + "sync": true, + "title": "普通商品", + "group": "商品" + } + }, + { + "path": "groupon", + "style": { + "navigationBarTitleText": "拼团商品" + }, + "meta": { + "sync": true, + "title": "拼团商品", + "group": "商品" + } + }, + + { + "path": "seckill", + "style": { + "navigationBarTitleText": "秒杀商品" + }, + "meta": { + "sync": true, + "title": "秒杀商品", + "group": "商品" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "商品列表" + }, + "meta": { + "sync": true, + "title": "商品列表", + "group": "商品" + } + }, + { + "path": "comment/add", + "style": { + "navigationBarTitleText": "评价商品" + }, + "meta": { + "auth": true + } + }, + { + "path": "comment/list", + "style": { + "navigationBarTitleText": "商品评价" + } + } + ] + }, + { + "root": "pages/order", + "pages": [{ + "path": "detail", + "style": { + "navigationBarTitleText": "订单详情" + }, + "meta": { + "auth": true, + "title": "订单详情" + } + }, + { + "path": "confirm", + "style": { + "navigationBarTitleText": "确认订单" + }, + "meta": { + "auth": true, + "title": "确认订单" + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "我的订单", + "enablePullDownRefresh": true + }, + "meta": { + "auth": true, + "sync": true, + "title": "用户订单", + "group": "订单中心" + } + }, + { + "path": "aftersale/apply", + "style": { + "navigationBarTitleText": "申请售后" + }, + "meta": { + "auth": true, + "title": "申请售后" + } + }, + { + "path": "aftersale/return-delivery", + "style": { + "navigationBarTitleText": "退货物流" + }, + "meta": { + "auth": true, + "title": "退货物流" + } + }, + { + "path": "aftersale/list", + "style": { + "navigationBarTitleText": "售后列表" + }, + "meta": { + "auth": true, + "sync": true, + "title": "售后订单", + "group": "订单中心" + } + }, + { + "path": "aftersale/detail", + "style": { + "navigationBarTitleText": "售后详情" + }, + "meta": { + "auth": true, + "title": "售后详情" + } + }, + { + "path": "aftersale/log", + "style": { + "navigationBarTitleText": "售后进度" + }, + "meta": { + "auth": true, + "title": "售后进度" + } + }, + { + "path": "express/log", + "style": { + "navigationBarTitleText": "物流轨迹" + }, + "meta": { + "auth": true, + "title": "物流轨迹" + } + } + ] + }, + { + "root": "pages/user", + "pages": [{ + "path": "info", + "style": { + "navigationBarTitleText": "我的信息" + }, + "meta": { + "auth": true, + "sync": true, + "title": "用户信息", + "group": "用户中心" + } + }, + { + "path": "goods-collect", + "style": { + "navigationBarTitleText": "我的收藏" + }, + "meta": { + "auth": true, + "sync": true, + "title": "商品收藏", + "group": "用户中心" + } + }, + { + "path": "goods-log", + "style": { + "navigationBarTitleText": "我的足迹" + }, + "meta": { + "auth": true, + "sync": true, + "title": "浏览记录", + "group": "用户中心" + } + }, + { + "path": "address/list", + "style": { + "navigationBarTitleText": "收货地址" + }, + "meta": { + "auth": true, + "sync": true, + "title": "地址管理", + "group": "用户中心" + } + }, + { + "path": "address/edit", + "style": { + "navigationBarTitleText": "编辑地址" + }, + "meta": { + "auth": true, + "title": "编辑地址" + } + }, + { + "path": "wallet/money", + "style": { + "navigationBarTitleText": "我的余额" + }, + "meta": { + "auth": true, + "sync": true, + "title": "用户余额", + "group": "用户中心" + } + }, + { + "path": "wallet/score", + "style": { + "navigationBarTitleText": "我的积分" + }, + "meta": { + "auth": true, + "sync": true, + "title": "用户积分", + "group": "用户中心" + } + } + ] + }, + { + "root": "pages/commission", + "pages": [{ + "path": "index", + "style": { + "navigationBarTitleText": "分销" + }, + "meta": { + "auth": true, + "sync": true, + "title": "分销中心", + "group": "分销商城" + } + }, + { + "path": "wallet", + "style": { + "navigationBarTitleText": "我的佣金" + }, + "meta": { + "auth": true, + "sync": true, + "title": "用户佣金", + "group": "分销中心" + } + }, + { + "path": "goods", + "style": { + "navigationBarTitleText": "推广商品" + }, + "meta": { + "auth": true, + "sync": true, + "title": "推广商品", + "group": "分销商城" + } + }, + { + "path": "order", + "style": { + "navigationBarTitleText": "分销订单" + }, + "meta": { + "auth": true, + "sync": true, + "title": "分销订单", + "group": "分销商城" + } + }, + { + "path": "team", + "style": { + "navigationBarTitleText": "我的团队" + }, + "meta": { + "auth": true, + "sync": true, + "title": "我的团队", + "group": "分销商城" + } + }, { + "path": "promoter", + "style": { + "navigationBarTitleText": "推广人排行榜" + }, + "meta": { + "auth": true, + "sync": true, + "title": "推广人排行榜", + "group": "分销商城" + } + }, { + "path": "commission-ranking", + "style": { + "navigationBarTitleText": "佣金排行榜" + }, + "meta": { + "auth": true, + "sync": true, + "title": "佣金排行榜", + "group": "分销商城" + } + }, { + "path": "withdraw", + "style": { + "navigationBarTitleText": "申请提现" + }, + "meta": { + "auth": true, + "sync": true, + "title": "申请提现", + "group": "分销商城" + } + } + ] + }, + { + "root": "pages/app", + "pages": [{ + "path": "sign", + "style": { + "navigationBarTitleText": "签到中心" + }, + "meta": { + "auth": true, + "sync": true, + "title": "签到中心", + "group": "应用" + } + }] + }, + { + "root": "pages/public", + "pages": [{ + "path": "setting", + "style": { + "navigationBarTitleText": "系统设置" + }, + "meta": { + "sync": true, + "title": "系统设置", + "group": "通用" + } + }, + { + "path": "richtext", + "style": { + "navigationBarTitleText": "富文本" + }, + "meta": { + "sync": true, + "title": "富文本", + "group": "通用" + } + }, + { + "path": "faq", + "style": { + "navigationBarTitleText": "常见问题" + }, + "meta": { + "sync": true, + "title": "常见问题", + "group": "通用" + } + }, + { + "path": "error", + "style": { + "navigationBarTitleText": "错误页面" + } + }, + { + "path": "webview", + "style": { + "navigationBarTitleText": "" + } + } + ] + }, + { + "root": "pages/coupon", + "pages": [{ + "path": "list", + "style": { + "navigationBarTitleText": "领券中心" + }, + "meta": { + "sync": true, + "title": "领券中心", + "group": "优惠券" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "优惠券" + }, + "meta": { + "auth": false, + "sync": true, + "title": "优惠券详情", + "group": "优惠券" + } + } + ] + }, + { + "root": "pages/chat", + "pages": [{ + "path": "index", + "style": { + "navigationBarTitleText": "客服" + }, + "meta": { + "auth": true, + "sync": true, + "title": "客服", + "group": "客服" + } + }] + }, + { + "root": "pages/pay", + "pages": [{ + "path": "index", + "style": { + "navigationBarTitleText": "收银台" + } + }, + { + "path": "result", + "style": { + "navigationBarTitleText": "支付结果" + } + }, + { + "path": "recharge", + "style": { + "navigationBarTitleText": "充值余额" + }, + "meta": { + "auth": true, + "sync": true, + "title": "充值余额", + "group": "支付" + } + }, + { + "path": "recharge-log", + "style": { + "navigationBarTitleText": "充值记录" + }, + "meta": { + "auth": true, + "sync": true, + "title": "充值记录", + "group": "支付" + } + } + ] + }, + { + "root": "pages/activity", + "pages": [{ + "path": "groupon/detail", + "style": { + "navigationBarTitleText": "拼团详情" + } + }, + { + "path": "groupon/order", + "style": { + "navigationBarTitleText": "我的拼团", + "enablePullDownRefresh": true + }, + "meta": { + "auth": true, + "sync": true, + "title": "拼团订单", + "group": "营销活动" + } + }, + { + "path": "index", + "style": { + "navigationBarTitleText": "营销商品" + }, + "meta": { + "sync": true, + "title": "营销商品", + "group": "营销活动" + } + }, + { + "path": "groupon/list", + "style": { + "navigationBarTitleText": "拼团活动" + }, + "meta": { + "sync": true, + "title": "拼团活动", + "group": "营销活动" + } + }, + { + "path": "seckill/list", + "style": { + "navigationBarTitleText": "秒杀活动" + }, + "meta": { + "sync": true, + "title": "秒杀活动", + "group": "营销活动" + } + } + ] + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "芋道商城", + "navigationBarBackgroundColor": "#FFFFFF", + "backgroundColor": "#FFFFFF", + "navigationStyle": "custom" + }, + "tabBar": { + "list": [{ + "pagePath": "pages/index/index" + }, + { + "pagePath": "pages/index/cart" + }, + { + "pagePath": "pages/index/user" + } + ] + } +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/activity/groupon/detail.vue b/yudao-mall-uniapp-master/pages/activity/groupon/detail.vue new file mode 100644 index 0000000..0db9ab3 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/activity/groupon/detail.vue @@ -0,0 +1,508 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/activity/groupon/list.vue b/yudao-mall-uniapp-master/pages/activity/groupon/list.vue new file mode 100644 index 0000000..b5a2746 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/activity/groupon/list.vue @@ -0,0 +1,225 @@ + + + + diff --git a/yudao-mall-uniapp-master/pages/activity/groupon/order.vue b/yudao-mall-uniapp-master/pages/activity/groupon/order.vue new file mode 100644 index 0000000..fc2a38a --- /dev/null +++ b/yudao-mall-uniapp-master/pages/activity/groupon/order.vue @@ -0,0 +1,239 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/activity/index.vue b/yudao-mall-uniapp-master/pages/activity/index.vue new file mode 100644 index 0000000..f36a0e5 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/activity/index.vue @@ -0,0 +1,206 @@ + + + + diff --git a/yudao-mall-uniapp-master/pages/activity/seckill/list.vue b/yudao-mall-uniapp-master/pages/activity/seckill/list.vue new file mode 100644 index 0000000..a1714bb --- /dev/null +++ b/yudao-mall-uniapp-master/pages/activity/seckill/list.vue @@ -0,0 +1,385 @@ + + + + diff --git a/yudao-mall-uniapp-master/pages/app/sign.vue b/yudao-mall-uniapp-master/pages/app/sign.vue new file mode 100644 index 0000000..cb87bbe --- /dev/null +++ b/yudao-mall-uniapp-master/pages/app/sign.vue @@ -0,0 +1,451 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/chat/components/goods.vue b/yudao-mall-uniapp-master/pages/chat/components/goods.vue new file mode 100644 index 0000000..7fbc95c --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/components/goods.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/chat/components/order.vue b/yudao-mall-uniapp-master/pages/chat/components/order.vue new file mode 100644 index 0000000..cf57f63 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/components/order.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/chat/components/select-popup.vue b/yudao-mall-uniapp-master/pages/chat/components/select-popup.vue new file mode 100644 index 0000000..cd829a1 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/components/select-popup.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/chat/emoji.js b/yudao-mall-uniapp-master/pages/chat/emoji.js new file mode 100644 index 0000000..83e6e84 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/emoji.js @@ -0,0 +1,58 @@ +export const emojiList = [ + { name: '[笑掉牙]', file: 'xiaodiaoya.png' }, + { name: '[可爱]', file: 'keai.png' }, + { name: '[冷酷]', file: 'lengku.png' }, + { name: '[闭嘴]', file: 'bizui.png' }, + { name: '[生气]', file: 'shengqi.png' }, + { name: '[惊恐]', file: 'jingkong.png' }, + { name: '[瞌睡]', file: 'keshui.png' }, + { name: '[大笑]', file: 'daxiao.png' }, + { name: '[爱心]', file: 'aixin.png' }, + { name: '[坏笑]', file: 'huaixiao.png' }, + { name: '[飞吻]', file: 'feiwen.png' }, + { name: '[疑问]', file: 'yiwen.png' }, + { name: '[开心]', file: 'kaixin.png' }, + { name: '[发呆]', file: 'fadai.png' }, + { name: '[流泪]', file: 'liulei.png' }, + { name: '[汗颜]', file: 'hanyan.png' }, + { name: '[惊悚]', file: 'jingshu.png' }, + { name: '[困~]', file: 'kun.png' }, + { name: '[心碎]', file: 'xinsui.png' }, + { name: '[天使]', file: 'tianshi.png' }, + { name: '[晕]', file: 'yun.png' }, + { name: '[啊]', file: 'a.png' }, + { name: '[愤怒]', file: 'fennu.png' }, + { name: '[睡着]', file: 'shuizhuo.png' }, + { name: '[面无表情]', file: 'mianwubiaoqing.png' }, + { name: '[难过]', file: 'nanguo.png' }, + { name: '[犯困]', file: 'fankun.png' }, + { name: '[好吃]', file: 'haochi.png' }, + { name: '[呕吐]', file: 'outu.png' }, + { name: '[龇牙]', file: 'ziya.png' }, + { name: '[懵比]', file: 'mengbi.png' }, + { name: '[白眼]', file: 'baiyan.png' }, + { name: '[饿死]', file: 'esi.png' }, + { name: '[凶]', file: 'xiong.png' }, + { name: '[感冒]', file: 'ganmao.png' }, + { name: '[流汗]', file: 'liuhan.png' }, + { name: '[笑哭]', file: 'xiaoku.png' }, + { name: '[流口水]', file: 'liukoushui.png' }, + { name: '[尴尬]', file: 'ganga.png' }, + { name: '[惊讶]', file: 'jingya.png' }, + { name: '[大惊]', file: 'dajing.png' }, + { name: '[不好意思]', file: 'buhaoyisi.png' }, + { name: '[大闹]', file: 'danao.png' }, + { name: '[不可思议]', file: 'bukesiyi.png' }, + { name: '[爱你]', file: 'aini.png' }, + { name: '[红心]', file: 'hongxin.png' }, + { name: '[点赞]', file: 'dianzan.png' }, + { name: '[恶魔]', file: 'emo.png' }, +]; + +export let emojiPage = {}; +emojiList.forEach((item, index) => { + if (!emojiPage[Math.floor(index / 30) + 1]) { + emojiPage[Math.floor(index / 30) + 1] = []; + } + emojiPage[Math.floor(index / 30) + 1].push(item); +}); diff --git a/yudao-mall-uniapp-master/pages/chat/index.vue b/yudao-mall-uniapp-master/pages/chat/index.vue new file mode 100644 index 0000000..1d3dfac --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/index.vue @@ -0,0 +1,870 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/chat/socket.js b/yudao-mall-uniapp-master/pages/chat/socket.js new file mode 100644 index 0000000..9113974 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/chat/socket.js @@ -0,0 +1,821 @@ +import { reactive, ref, unref } from 'vue'; +import sheep from '@/sheep'; +// import chat from '@/sheep/api/chat'; +import dayjs from 'dayjs'; +import io from '@hyoga/uni-socket.io'; + +export function useChatWebSocket(socketConfig) { + let SocketIo = null; + + // chat状态数据 + const state = reactive({ + chatDotNum: 0, //总状态红点 + chatList: [], //会话信息 + customerUserInfo: {}, //用户信息 + customerServerInfo: { + //客服信息 + title: '连接中...', + state: 'connecting', + avatar: null, + nickname: '', + }, + socketState: { + isConnect: true, //是否连接成功 + isConnecting: false, //重连中,不允许新的socket开启。 + tip: '', + }, + chatHistoryPagination: { + page: 0, //当前页 + list_rows: 10, //每页条数 + last_id: 0, //最后条ID + lastPage: 0, //总共多少页 + loadStatus: 'loadmore', //loadmore-加载前的状态,loading-加载中的状态,nomore-没有更多的状态 + }, + templateChatList: [], //猜你想问 + + chatConfig: {}, // 配置信息 + + isSendSucces: -1, // 是否发送成功 -1=发送中|0=发送成功|1发送失败 + }); + + /** + * 连接初始化 + * @param {Object} config - 配置信息 + * @param {Function} callBack -回调函数,有新消息接入,保持底部 + */ + const socketInit = (config, callBack) => { + state.chatConfig = config; + if (SocketIo && SocketIo.connected) return; // 如果socket已经连接,返回false + if (state.socketState.isConnecting) return; // 重连中,返回false + + // 启动初始化 + SocketIo = io(config.chat_domain, { + reconnection: true, // 默认 true 是否断线重连 + reconnectionAttempts: 5, // 默认无限次 断线尝试次数 + reconnectionDelay: 1000, // 默认 1000,进行下一次重连的间隔。 + reconnectionDelayMax: 5000, // 默认 5000, 重新连接等待的最长时间 默认 5000 + randomizationFactor: 0.5, // 默认 0.5 [0-1],随机重连延迟时间 + timeout: 20000, // 默认 20s + transports: ['websocket', 'polling'], // websocket | polling, + ...config, + }); + + // 监听连接 + SocketIo.on('connect', async (res) => { + socketReset(callBack); + // socket连接 + // 用户登录 + // 顾客登录 + console.log('socket:connect'); + }); + // 监听消息 + SocketIo.on('message', (res) => { + if (res.error === 0) { + const { message, sender } = res.data; + state.chatList.push(formatMessage(res.data.message)); + + // 告诉父级页面 + // window.parent.postMessage({ + // chatDotNum: ++state.chatDotNum + // }) + callBack && callBack(); + } + }); + // 监听客服接入成功 + SocketIo.on('customer_service_access', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: res.data.customer_service.name, + state: 'online', + avatar: res.data.customer_service.avatar, + }); + state.chatList.push(formatMessage(res.data.message)); + // callBack && callBack() + } + }); + // 监听排队等待 + SocketIo.on('waiting_queue', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: res.data.title, + state: 'waiting', + avatar: '', + }); + // callBack && callBack() + } + }); + // 监听没有客服在线 + SocketIo.on('no_customer_service', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: '暂无客服在线...', + state: 'waiting', + avatar: '', + }); + } + state.chatList.push(formatMessage(res.data.message)); + // callBack && callBack() + }); + // 监听客服上线 + SocketIo.on('customer_service_online', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: res.data.customer_service.name, + state: 'online', + avatar: res.data.customer_service.avatar, + }); + } + }); + // 监听客服下线 + SocketIo.on('customer_service_offline', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: res.data.customer_service.name, + state: 'offline', + avatar: res.data.customer_service.avatar, + }); + } + }); + // 监听客服忙碌 + SocketIo.on('customer_service_busy', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: res.data.customer_service.name, + state: 'busy', + avatar: res.data.customer_service.avatar, + }); + } + }); + // 监听客服断开链接 + SocketIo.on('customer_service_break', (res) => { + if (res.error === 0) { + editCustomerServerInfo({ + title: '客服服务结束', + state: 'offline', + avatar: '', + }); + state.socketState.isConnect = false; + state.socketState.tip = '当前服务已结束'; + } + state.chatList.push(formatMessage(res.data.message)); + // callBack && callBack() + }); + // 监听自定义错误 custom_error + SocketIo.on('custom_error', (error) => { + editCustomerServerInfo({ + title: error.msg, + state: 'offline', + avatar: '', + }); + console.log('custom_error:', error); + }); + // 监听错误 error + SocketIo.on('error', (error) => { + console.log('error:', error); + }); + // 重连失败 connect_error + SocketIo.on('connect_error', (error) => { + console.log('connect_error'); + }); + // 连接上,但无反应 connect_timeout + SocketIo.on('connect_timeout', (error) => { + console.log(error, 'connect_timeout'); + }); + // 服务进程销毁 disconnect + SocketIo.on('disconnect', (error) => { + console.log(error, 'disconnect'); + }); + // 服务重启重连上reconnect + SocketIo.on('reconnect', (error) => { + console.log(error, 'reconnect'); + }); + // 开始重连reconnect_attempt + SocketIo.on('reconnect_attempt', (error) => { + state.socketState.isConnect = false; + state.socketState.isConnecting = true; + editCustomerServerInfo({ + title: `重连中,第${error}次尝试...`, + state: 'waiting', + avatar: '', + }); + console.log(error, 'reconnect_attempt'); + }); + // 重新连接中reconnecting + SocketIo.on('reconnecting', (error) => { + console.log(error, 'reconnecting'); + }); + // 重新连接错误reconnect_error + SocketIo.on('reconnect_error', (error) => { + console.log('reconnect_error'); + }); + // 重新连接失败reconnect_failed + SocketIo.on('reconnect_failed', (error) => { + state.socketState.isConnecting = false; + editCustomerServerInfo({ + title: `重连失败,请刷新重试~`, + state: 'waiting', + avatar: '', + }); + console.log(error, 'reconnect_failed'); + + // setTimeout(() => { + state.isSendSucces = 1; + // }, 500) + }); + }; + + // 重置socket + const socketReset = (callBack) => { + state.chatList = []; + state.chatHistoryList = []; + state.chatHistoryPagination = { + page: 0, + per_page: 10, + last_id: 0, + totalPage: 0, + }; + socketConnection(callBack); // 连接 + }; + + // 退出连接 + const socketClose = () => { + SocketIo.emit('customer_logout', {}, (res) => { + console.log('socket:退出', res); + }); + }; + + // 测试事件 + const socketTest = () => { + SocketIo.emit('test', {}, (res) => { + console.log('test:test', res); + }); + }; + + // 发送消息 + const socketSendMsg = (data, sendMsgCallBack) => { + state.isSendSucces = -1; + state.chatList.push(data); + sendMsgCallBack && sendMsgCallBack(); + SocketIo.emit( + 'message', + { + message: formatInput(data), + ...data.customData, + }, + (res) => { + // setTimeout(() => { + state.isSendSucces = res.error; + // }, 500) + + // console.log(res, 'socket:send'); + // sendMsgCallBack && sendMsgCallBack() + }, + ); + }; + + // 连接socket,存入sessionId + const socketConnection = (callBack) => { + SocketIo.emit( + 'connection', + { + auth: 'user', + token: uni.getStorageSync('socketUserToken') || '', + session_id: uni.getStorageSync('socketSessionId') || '', + }, + (res) => { + if (res.error === 0) { + socketCustomerLogin(callBack); + uni.setStorageSync('socketSessionId', res.data.session_id); + // uni.getStorageSync('socketUserToken') && socketLogin(uni.getStorageSync( + // 'socketUserToken')) // 如果有用户token,绑定 + state.customerUserInfo = res.data.chat_user; + state.socketState.isConnect = true; + } else { + editCustomerServerInfo({ + title: `服务器异常!`, + state: 'waiting', + avatar: '', + }); + state.socketState.isConnect = false; + } + }, + ); + }; + + // 用户id,获取token + const getUserToken = async (id) => { + const res = await chat.unifiedToken(); + if (res.error === 0) { + uni.setStorageSync('socketUserToken', res.data.token); + // SocketIo && SocketIo.connected && socketLogin(res.data.token) + } + return res; + }; + + // 用户登录 + const socketLogin = (token) => { + SocketIo.emit( + 'login', + { + token: token, + }, + (res) => { + console.log(res, 'socket:login'); + state.customerUserInfo = res.data.chat_user; + }, + ); + }; + + // 顾客登录 + const socketCustomerLogin = (callBack) => { + SocketIo.emit( + 'customer_login', + { + room_id: state.chatConfig.room_id, + }, + (res) => { + state.templateChatList = res.data.questions.length ? res.data.questions : []; + state.chatList.push({ + from: 'customer_service', // 用户customer右 | 顾客customer_service左 | 系统system中间 + mode: 'template', // goods,order,image,text,system + date: new Date().getTime(), //时间 + content: { + //内容 + list: state.templateChatList, + }, + }); + res.error === 0 && socketHistoryList(callBack); + }, + ); + }; + + // 获取历史消息 + const socketHistoryList = (historyCallBack) => { + state.chatHistoryPagination.loadStatus = 'loading'; + state.chatHistoryPagination.page += 1; + SocketIo.emit('messages', state.chatHistoryPagination, (res) => { + if (res.error === 0) { + state.chatHistoryPagination.total = res.data.messages.total; + state.chatHistoryPagination.lastPage = res.data.messages.last_page; + state.chatHistoryPagination.page = res.data.messages.current_page; + res.data.messages.data.forEach((item) => { + item.message_type && state.chatList.unshift(formatMessage(item)); + }); + state.chatHistoryPagination.loadStatus = + state.chatHistoryPagination.page < state.chatHistoryPagination.lastPage + ? 'loadmore' + : 'nomore'; + if (state.chatHistoryPagination.last_id == 0) { + state.chatHistoryPagination.last_id = res.data.messages.data.length + ? res.data.messages.data[0].id + : 0; + } + state.chatHistoryPagination.page === 1 && historyCallBack && historyCallBack(); + } + + // 历史记录之后,猜你想问 + // state.chatList.push({ + // from: 'customer_service', // 用户customer右 | 顾客customer_service左 | 系统system中间 + // mode: 'template', // goods,order,image,text,system + // date: new Date().getTime(), //时间 + // content: { //内容 + // list: state.templateChatList + // } + // }) + }); + }; + + // 修改客服信息 + const editCustomerServerInfo = (data) => { + state.customerServerInfo = { + ...state.customerServerInfo, + ...data, + }; + }; + + /** + * ================ + * 工具函数 ↓ + * =============== + */ + + /** + * 是否显示时间 + * @param {*} item - 数据 + * @param {*} index - 索引 + */ + const showTime = (item, index) => { + if (unref(state.chatList)[index + 1]) { + let dateString = dayjs(unref(state.chatList)[index + 1].date).fromNow(); + if (dateString === dayjs(unref(item).date).fromNow()) { + return false; + } else { + dateString = dayjs(unref(item).date).fromNow(); + return true; + } + } + return false; + }; + + /** + * 格式化时间 + * @param {*} time - 时间戳 + */ + const formatTime = (time) => { + let diffTime = new Date().getTime() - time; + if (diffTime > 28 * 24 * 60 * 1000) { + return dayjs(time).format('MM/DD HH:mm'); + } + if (diffTime > 360 * 28 * 24 * 60 * 1000) { + return dayjs(time).format('YYYY/MM/DD HH:mm'); + } + return dayjs(time).fromNow(); + }; + + /** + * 获取焦点 + * @param {*} virtualNode - 节点信息 ref + */ + const getFocus = (virtualNode) => { + if (window.getSelection) { + let chatInput = unref(virtualNode); + chatInput.focus(); + let range = window.getSelection(); + range.selectAllChildren(chatInput); + range.collapseToEnd(); + } else if (document.selection) { + let range = document.selection.createRange(); + range.moveToElementText(chatInput); + range.collapse(false); + range.select(); + } + }; + + /** + * 文件上传 + * @param {Blob} file -文件数据流 + * @return {path,fullPath} + */ + + const upload = (name, file) => { + return new Promise((resolve, reject) => { + let data = new FormData(); + data.append('file', file, name); + data.append('group', 'chat'); + ajax({ + url: '/upload', + method: 'post', + headers: { + 'Content-Type': 'multipart/form-data', + }, + data, + success: function (res) { + resolve(res); + }, + error: function (err) { + reject(err); + }, + }); + }); + }; + + /** + * 粘贴到输入框 + * @param {*} e - 粘贴内容 + * @param {*} uploadHttp - 上传图片地址 + */ + const onPaste = async (e) => { + let paste = e.clipboardData || window.clipboardData; + let filesArr = Array.from(paste.files); + filesArr.forEach(async (child) => { + if (child && child.type.includes('image')) { + e.preventDefault(); //阻止默认 + let file = child; + const img = await readImg(file); + const blob = await compressImg(img, file.type); + const { data } = await upload(file.name, blob); + let image = ``; + document.execCommand('insertHTML', false, image); + } else { + document.execCommand('insertHTML', false, paste.getData('text')); + } + }); + }; + + /** + * 拖拽到输入框 + * @param {*} e - 粘贴内容 + * @param {*} uploadHttp - 上传图片地址 + */ + const onDrop = async (e) => { + e.preventDefault(); //阻止默认 + let filesArr = Array.from(e.dataTransfer.files); + filesArr.forEach(async (child) => { + if (child && child.type.includes('image')) { + let file = child; + const img = await readImg(file); + const blob = await compressImg(img, file.type); + const { data } = await upload(file.name, blob); + let image = ``; + document.execCommand('insertHTML', false, image); + } else { + ElMessage({ + message: '禁止拖拽非图片资源', + type: 'warning', + }); + } + }); + }; + + /** + * 解析富文本输入框内容 + * @param {*} virtualNode -节点信息 + * @param {Function} formatInputCallBack - cb 回调 + */ + const formatChatInput = (virtualNode, formatInputCallBack) => { + let res = ''; + let elemArr = Array.from(virtualNode.childNodes); + elemArr.forEach((child, index) => { + if (child.nodeName === '#text') { + //如果为文本节点 + res += child.nodeValue; + if ( + //文本节点的后面是图片,并且不是emoji,分开发送。输入框中的图片和文本表情分开。 + elemArr[index + 1] && + elemArr[index + 1].nodeName === 'IMG' && + elemArr[index + 1] && + elemArr[index + 1].name !== 'emoji' + ) { + const data = { + from: 'customer', + mode: 'text', + date: new Date().getTime(), + content: { + text: filterXSS(res), + }, + }; + formatInputCallBack && formatInputCallBack(data); + res = ''; + } + } else if (child.nodeName === 'BR') { + res += '
'; + } else if (child.nodeName === 'IMG') { + // 有emjio 和 一般图片 + // 图片解析后直接发送,不跟文字表情一组 + if (child.name !== 'emoji') { + let srcReg = /src=[\'\']?([^\'\']*)[\'\']?/i; + let src = child.outerHTML.match(srcReg); + const data = { + from: 'customer', + mode: 'image', + date: new Date().getTime(), + content: { + url: src[1], + path: src[1].replace(/http:\/\/[^\/]*/, ''), + }, + }; + formatInputCallBack && formatInputCallBack(data); + } else { + // 非表情图片跟文字一起发送 + res += child.outerHTML; + } + } else if (child.nodeName === 'DIV') { + res += `
${child.outerHTML}
`; + } + }); + if (res) { + const data = { + from: 'customer', + mode: 'text', + date: new Date().getTime(), + content: { + text: filterXSS(res), + }, + }; + formatInputCallBack && formatInputCallBack(data); + } + unref(virtualNode).innerHTML = ''; + }; + + /** + * 状态回调 + * @param {*} res -接口返回数据 + */ + const callBackNotice = (res) => { + ElNotification({ + title: 'socket', + message: res.msg, + showClose: true, + type: res.error === 0 ? 'success' : 'warning', + duration: 1200, + }); + }; + + /** + * 格式化发送信息 + * @param {Object} message + * @returns obj - 消息对象 + */ + const formatInput = (message) => { + let obj = {}; + switch (message.mode) { + case 'text': + obj = { + message_type: 'text', + message: message.content.text, + }; + break; + case 'image': + obj = { + message_type: 'image', + message: message.content.path, + }; + break; + case 'goods': + obj = { + message_type: 'goods', + message: message.content.item, + }; + break; + case 'order': + obj = { + message_type: 'order', + message: message.content.item, + }; + break; + default: + break; + } + return obj; + }; + /** + * 格式化接收信息 + * @param {*} message + * @returns obj - 消息对象 + */ + const formatMessage = (message) => { + let obj = {}; + switch (message.message_type) { + case 'system': + obj = { + from: 'system', // 用户customer左 | 顾客customer_service右 | 系统system中间 + mode: 'system', // goods,order,image,text,system + date: message.create_time * 1000, //时间 + content: { + //内容 + text: message.message, + }, + }; + break; + case 'text': + obj = { + from: message.sender_identify, + mode: message.message_type, + date: message.create_time * 1000, //时间 + sender: message.sender, + content: { + text: message.message, + messageId: message.id, + }, + }; + break; + case 'image': + obj = { + from: message.sender_identify, + mode: message.message_type, + date: message.create_time * 1000, //时间 + sender: message.sender, + content: { + url: sheep.$url.cdn(message.message), + messageId: message.id, + }, + }; + break; + case 'goods': + obj = { + from: message.sender_identify, + mode: message.message_type, + date: message.create_time * 1000, //时间 + sender: message.sender, + content: { + item: message.message, + messageId: message.id, + }, + }; + break; + case 'order': + obj = { + from: message.sender_identify, + mode: message.message_type, + date: message.create_time * 1000, //时间 + sender: message.sender, + content: { + item: message.message, + messageId: message.id, + }, + }; + break; + default: + break; + } + return obj; + }; + + /** + * file 转换为 img + * @param {*} file - file 文件 + * @returns img - img标签 + */ + const readImg = (file) => { + return new Promise((resolve, reject) => { + const img = new Image(); + const reader = new FileReader(); + reader.onload = function (e) { + img.src = e.target.result; + }; + reader.onerror = function (e) { + reject(e); + }; + reader.readAsDataURL(file); + img.onload = function () { + resolve(img); + }; + img.onerror = function (e) { + reject(e); + }; + }); + }; + + /** + * 压缩图片 + *@param img -被压缩的img对象 + * @param type -压缩后转换的文件类型 + * @param mx -触发压缩的图片最大宽度限制 + * @param mh -触发压缩的图片最大高度限制 + * @returns blob - 文件流 + */ + const compressImg = (img, type = 'image/jpeg', mx = 1000, mh = 1000, quality = 1) => { + return new Promise((resolve, reject) => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + const { width: originWidth, height: originHeight } = img; + // 最大尺寸限制 + const maxWidth = mx; + const maxHeight = mh; + // 目标尺寸 + let targetWidth = originWidth; + let targetHeight = originHeight; + if (originWidth > maxWidth || originHeight > maxHeight) { + if (originWidth / originHeight > 1) { + // 宽图片 + targetWidth = maxWidth; + targetHeight = Math.round(maxWidth * (originHeight / originWidth)); + } else { + // 高图片 + targetHeight = maxHeight; + targetWidth = Math.round(maxHeight * (originWidth / originHeight)); + } + } + canvas.width = targetWidth; + canvas.height = targetHeight; + context.clearRect(0, 0, targetWidth, targetHeight); + // 图片绘制 + context.drawImage(img, 0, 0, targetWidth, targetHeight); + canvas.toBlob( + function (blob) { + resolve(blob); + }, + type, + quality, + ); + }); + }; + + return { + compressImg, + readImg, + formatMessage, + formatInput, + callBackNotice, + + socketInit, + socketSendMsg, + socketClose, + socketHistoryList, + + getFocus, + formatChatInput, + onDrop, + onPaste, + upload, + + getUserToken, + + state, + + socketTest, + + showTime, + formatTime, + }; +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/commission-ranking.vue b/yudao-mall-uniapp-master/pages/commission/commission-ranking.vue new file mode 100644 index 0000000..d8dd4ab --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/commission-ranking.vue @@ -0,0 +1,249 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/components/account-info.vue b/yudao-mall-uniapp-master/pages/commission/components/account-info.vue new file mode 100644 index 0000000..8595aa3 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/account-info.vue @@ -0,0 +1,125 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/components/account-type-select.vue b/yudao-mall-uniapp-master/pages/commission/components/account-type-select.vue new file mode 100644 index 0000000..e79e417 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/account-type-select.vue @@ -0,0 +1,160 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/components/commission-auth.vue b/yudao-mall-uniapp-master/pages/commission/components/commission-auth.vue new file mode 100644 index 0000000..9a484fa --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/commission-auth.vue @@ -0,0 +1,101 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/components/commission-info.vue b/yudao-mall-uniapp-master/pages/commission/components/commission-info.vue new file mode 100644 index 0000000..65f2c59 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/commission-info.vue @@ -0,0 +1,113 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/components/commission-log.vue b/yudao-mall-uniapp-master/pages/commission/components/commission-log.vue new file mode 100644 index 0000000..d6e3e8c --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/commission-log.vue @@ -0,0 +1,165 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/components/commission-menu.vue b/yudao-mall-uniapp-master/pages/commission/components/commission-menu.vue new file mode 100644 index 0000000..5655ca7 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/components/commission-menu.vue @@ -0,0 +1,138 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/goods.vue b/yudao-mall-uniapp-master/pages/commission/goods.vue new file mode 100644 index 0000000..d467849 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/goods.vue @@ -0,0 +1,150 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/index.vue b/yudao-mall-uniapp-master/pages/commission/index.vue new file mode 100644 index 0000000..73c1eb7 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/index.vue @@ -0,0 +1,46 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/order.vue b/yudao-mall-uniapp-master/pages/commission/order.vue new file mode 100644 index 0000000..18b1bf5 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/order.vue @@ -0,0 +1,331 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/promoter.vue b/yudao-mall-uniapp-master/pages/commission/promoter.vue new file mode 100644 index 0000000..b7d0a89 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/promoter.vue @@ -0,0 +1,297 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/team.vue b/yudao-mall-uniapp-master/pages/commission/team.vue new file mode 100644 index 0000000..82a492e --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/team.vue @@ -0,0 +1,581 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/commission/wallet.vue b/yudao-mall-uniapp-master/pages/commission/wallet.vue new file mode 100644 index 0000000..d0ad059 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/wallet.vue @@ -0,0 +1,470 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/commission/withdraw.vue b/yudao-mall-uniapp-master/pages/commission/withdraw.vue new file mode 100644 index 0000000..e9edb95 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/commission/withdraw.vue @@ -0,0 +1,427 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/coupon/detail.vue b/yudao-mall-uniapp-master/pages/coupon/detail.vue new file mode 100644 index 0000000..0a760d2 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/coupon/detail.vue @@ -0,0 +1,378 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/coupon/list.vue b/yudao-mall-uniapp-master/pages/coupon/list.vue new file mode 100644 index 0000000..e7c4394 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/coupon/list.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/comment/add.vue b/yudao-mall-uniapp-master/pages/goods/comment/add.vue new file mode 100644 index 0000000..43d08c4 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/comment/add.vue @@ -0,0 +1,145 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/goods/comment/list.vue b/yudao-mall-uniapp-master/pages/goods/comment/list.vue new file mode 100644 index 0000000..01526b0 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/comment/list.vue @@ -0,0 +1,167 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/comment-item.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/comment-item.vue new file mode 100644 index 0000000..518db2a --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/comment-item.vue @@ -0,0 +1,94 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-activity-tip.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-activity-tip.vue new file mode 100644 index 0000000..5d74c08 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-activity-tip.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell-sku.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell-sku.vue new file mode 100644 index 0000000..11f1b20 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell-sku.vue @@ -0,0 +1,31 @@ + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell.vue new file mode 100644 index 0000000..b4c56dd --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-cell.vue @@ -0,0 +1,60 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-comment-card.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-comment-card.vue new file mode 100644 index 0000000..cc48dfd --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-comment-card.vue @@ -0,0 +1,106 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-content-card.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-content-card.vue new file mode 100644 index 0000000..eaacc82 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-content-card.vue @@ -0,0 +1,52 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-navbar.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-navbar.vue new file mode 100644 index 0000000..1d1153d --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-navbar.vue @@ -0,0 +1,256 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-progress.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-progress.vue new file mode 100644 index 0000000..a6210b1 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-progress.vue @@ -0,0 +1,40 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-skeleton.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-skeleton.vue new file mode 100644 index 0000000..5eebf50 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-skeleton.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/detail/detail-tabbar.vue b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-tabbar.vue new file mode 100644 index 0000000..bcae5be --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/detail/detail-tabbar.vue @@ -0,0 +1,169 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/groupon/groupon-card-list.vue b/yudao-mall-uniapp-master/pages/goods/components/groupon/groupon-card-list.vue new file mode 100644 index 0000000..2fd8f18 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/groupon/groupon-card-list.vue @@ -0,0 +1,141 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/list/list-goods-card.vue b/yudao-mall-uniapp-master/pages/goods/components/list/list-goods-card.vue new file mode 100644 index 0000000..d02519f --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/list/list-goods-card.vue @@ -0,0 +1,103 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/components/list/list-navbar.vue b/yudao-mall-uniapp-master/pages/goods/components/list/list-navbar.vue new file mode 100644 index 0000000..c21e679 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/components/list/list-navbar.vue @@ -0,0 +1,93 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/groupon.vue b/yudao-mall-uniapp-master/pages/goods/groupon.vue new file mode 100644 index 0000000..50bba1c --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/groupon.vue @@ -0,0 +1,532 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/index.vue b/yudao-mall-uniapp-master/pages/goods/index.vue new file mode 100644 index 0000000..0a69aa2 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/index.vue @@ -0,0 +1,412 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/goods/list.vue b/yudao-mall-uniapp-master/pages/goods/list.vue new file mode 100644 index 0000000..36240d5 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/list.vue @@ -0,0 +1,362 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/goods/seckill.vue b/yudao-mall-uniapp-master/pages/goods/seckill.vue new file mode 100644 index 0000000..027449a --- /dev/null +++ b/yudao-mall-uniapp-master/pages/goods/seckill.vue @@ -0,0 +1,555 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/cart.vue b/yudao-mall-uniapp-master/pages/index/cart.vue new file mode 100644 index 0000000..ae90777 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/cart.vue @@ -0,0 +1,196 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/index/category.vue b/yudao-mall-uniapp-master/pages/index/category.vue new file mode 100644 index 0000000..2317d1d --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/category.vue @@ -0,0 +1,236 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/components/first-one.vue b/yudao-mall-uniapp-master/pages/index/components/first-one.vue new file mode 100644 index 0000000..2decc86 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/components/first-one.vue @@ -0,0 +1,26 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/components/first-two.vue b/yudao-mall-uniapp-master/pages/index/components/first-two.vue new file mode 100644 index 0000000..482931c --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/components/first-two.vue @@ -0,0 +1,66 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/components/second-one.vue b/yudao-mall-uniapp-master/pages/index/components/second-one.vue new file mode 100644 index 0000000..86b7078 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/components/second-one.vue @@ -0,0 +1,80 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/index.vue b/yudao-mall-uniapp-master/pages/index/index.vue new file mode 100644 index 0000000..208c959 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/index.vue @@ -0,0 +1,88 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/login.vue b/yudao-mall-uniapp-master/pages/index/login.vue new file mode 100644 index 0000000..b2c82a4 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/login.vue @@ -0,0 +1,38 @@ + + + + diff --git a/yudao-mall-uniapp-master/pages/index/page.vue b/yudao-mall-uniapp-master/pages/index/page.vue new file mode 100644 index 0000000..b5d8ef3 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/page.vue @@ -0,0 +1,51 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/search.vue b/yudao-mall-uniapp-master/pages/index/search.vue new file mode 100644 index 0000000..8497298 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/search.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/index/user.vue b/yudao-mall-uniapp-master/pages/index/user.vue new file mode 100644 index 0000000..705451a --- /dev/null +++ b/yudao-mall-uniapp-master/pages/index/user.vue @@ -0,0 +1,42 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/apply.vue b/yudao-mall-uniapp-master/pages/order/aftersale/apply.vue new file mode 100644 index 0000000..7512302 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/apply.vue @@ -0,0 +1,357 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/detail.vue b/yudao-mall-uniapp-master/pages/order/aftersale/detail.vue new file mode 100644 index 0000000..7bff82b --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/detail.vue @@ -0,0 +1,342 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/list.vue b/yudao-mall-uniapp-master/pages/order/aftersale/list.vue new file mode 100644 index 0000000..6462496 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/list.vue @@ -0,0 +1,187 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/log-item.vue b/yudao-mall-uniapp-master/pages/order/aftersale/log-item.vue new file mode 100644 index 0000000..01329df --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/log-item.vue @@ -0,0 +1,77 @@ + + + + diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/log.vue b/yudao-mall-uniapp-master/pages/order/aftersale/log.vue new file mode 100644 index 0000000..a8df8a2 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/log.vue @@ -0,0 +1,38 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/aftersale/return-delivery.vue b/yudao-mall-uniapp-master/pages/order/aftersale/return-delivery.vue new file mode 100644 index 0000000..461fef0 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/aftersale/return-delivery.vue @@ -0,0 +1,194 @@ + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/order/confirm.vue b/yudao-mall-uniapp-master/pages/order/confirm.vue new file mode 100644 index 0000000..69e7f4d --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/confirm.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/detail.vue b/yudao-mall-uniapp-master/pages/order/detail.vue new file mode 100644 index 0000000..4daa302 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/detail.vue @@ -0,0 +1,633 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/express/log.vue b/yudao-mall-uniapp-master/pages/order/express/log.vue new file mode 100644 index 0000000..0292dbf --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/express/log.vue @@ -0,0 +1,162 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/order/list.vue b/yudao-mall-uniapp-master/pages/order/list.vue new file mode 100644 index 0000000..323d7ae --- /dev/null +++ b/yudao-mall-uniapp-master/pages/order/list.vue @@ -0,0 +1,453 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/pay/index.vue b/yudao-mall-uniapp-master/pages/pay/index.vue new file mode 100644 index 0000000..46e3eaf --- /dev/null +++ b/yudao-mall-uniapp-master/pages/pay/index.vue @@ -0,0 +1,288 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/pay/recharge-log.vue b/yudao-mall-uniapp-master/pages/pay/recharge-log.vue new file mode 100644 index 0000000..67e4688 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/pay/recharge-log.vue @@ -0,0 +1,165 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/pay/recharge.vue b/yudao-mall-uniapp-master/pages/pay/recharge.vue new file mode 100644 index 0000000..9432886 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/pay/recharge.vue @@ -0,0 +1,259 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/pay/result.vue b/yudao-mall-uniapp-master/pages/pay/result.vue new file mode 100644 index 0000000..8294371 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/pay/result.vue @@ -0,0 +1,287 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/public/error.vue b/yudao-mall-uniapp-master/pages/public/error.vue new file mode 100644 index 0000000..3ccc14d --- /dev/null +++ b/yudao-mall-uniapp-master/pages/public/error.vue @@ -0,0 +1,60 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/public/faq.vue b/yudao-mall-uniapp-master/pages/public/faq.vue new file mode 100644 index 0000000..af811c9 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/public/faq.vue @@ -0,0 +1,118 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/public/richtext.vue b/yudao-mall-uniapp-master/pages/public/richtext.vue new file mode 100644 index 0000000..e4a0921 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/public/richtext.vue @@ -0,0 +1,54 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/public/setting.vue b/yudao-mall-uniapp-master/pages/public/setting.vue new file mode 100644 index 0000000..59a11b4 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/public/setting.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/yudao-mall-uniapp-master/pages/public/webview.vue b/yudao-mall-uniapp-master/pages/public/webview.vue new file mode 100644 index 0000000..1327295 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/public/webview.vue @@ -0,0 +1,18 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/user/address/edit.vue b/yudao-mall-uniapp-master/pages/user/address/edit.vue new file mode 100644 index 0000000..a1e36d7 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/address/edit.vue @@ -0,0 +1,257 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/user/address/list.vue b/yudao-mall-uniapp-master/pages/user/address/list.vue new file mode 100644 index 0000000..a812afc --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/address/list.vue @@ -0,0 +1,143 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/pages/user/goods-collect.vue b/yudao-mall-uniapp-master/pages/user/goods-collect.vue new file mode 100644 index 0000000..03099bc --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/goods-collect.vue @@ -0,0 +1,231 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/user/goods-log.vue b/yudao-mall-uniapp-master/pages/user/goods-log.vue new file mode 100644 index 0000000..630f7c5 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/goods-log.vue @@ -0,0 +1,306 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/user/info.vue b/yudao-mall-uniapp-master/pages/user/info.vue new file mode 100644 index 0000000..1b668c5 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/info.vue @@ -0,0 +1,471 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/user/wallet/money.vue b/yudao-mall-uniapp-master/pages/user/wallet/money.vue new file mode 100644 index 0000000..149eb30 --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/wallet/money.vue @@ -0,0 +1,373 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/pages/user/wallet/score.vue b/yudao-mall-uniapp-master/pages/user/wallet/score.vue new file mode 100644 index 0000000..c1a5dca --- /dev/null +++ b/yudao-mall-uniapp-master/pages/user/wallet/score.vue @@ -0,0 +1,277 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/infra/file.js b/yudao-mall-uniapp-master/sheep/api/infra/file.js new file mode 100644 index 0000000..a4bac46 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/infra/file.js @@ -0,0 +1,45 @@ +import { baseUrl, apiPath } from '@/sheep/config'; + +const FileApi = { + // 上传文件 + uploadFile: (file) => { + // TODO 芋艿:访问令牌的接入; + const token = uni.getStorageSync('token'); + uni.showLoading({ + title: '上传中', + }); + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: baseUrl + apiPath + '/infra/file/upload', + filePath: file, + name: 'file', + header: { + // Accept: 'text/json', + Accept : '*/*', + 'tenant-id' :'1', + // Authorization: 'Bearer test247', + }, + success: (uploadFileRes) => { + let result = JSON.parse(uploadFileRes.data); + if (result.error === 1) { + uni.showToast({ + icon: 'none', + title: result.msg, + }); + } else { + return resolve(result); + } + }, + fail: (error) => { + console.log('上传失败:', error); + return resolve(false); + }, + complete: () => { + uni.hideLoading(); + }, + }); + }); + }, +}; + +export default FileApi; diff --git a/yudao-mall-uniapp-master/sheep/api/member/address.js b/yudao-mall-uniapp-master/sheep/api/member/address.js new file mode 100644 index 0000000..d0c16ce --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/address.js @@ -0,0 +1,53 @@ +import request from '@/sheep/request'; + +const AddressApi = { + // 获得用户收件地址列表 + getAddressList: () => { + return request({ + url: '/member/address/list', + method: 'GET' + }); + }, + // 创建用户收件地址 + createAddress: (data) => { + return request({ + url: '/member/address/create', + method: 'POST', + data, + custom: { + showSuccess: true, + successMsg: '保存成功' + }, + }); + }, + // 更新用户收件地址 + updateAddress: (data) => { + return request({ + url: '/member/address/update', + method: 'PUT', + data, + custom: { + showSuccess: true, + successMsg: '更新成功' + }, + }); + }, + // 获得用户收件地址 + getAddress: (id) => { + return request({ + url: '/member/address/get', + method: 'GET', + params: { id } + }); + }, + // 删除用户收件地址 + deleteAddress: (id) => { + return request({ + url: '/member/address/delete', + method: 'DELETE', + params: { id } + }); + }, +}; + +export default AddressApi; diff --git a/yudao-mall-uniapp-master/sheep/api/member/auth.js b/yudao-mall-uniapp-master/sheep/api/member/auth.js new file mode 100644 index 0000000..a1c0660 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/auth.js @@ -0,0 +1,132 @@ +import request from '@/sheep/request'; + +const AuthUtil = { + // 使用手机 + 密码登录 + login: (data) => { + return request({ + url: '/member/auth/login', + method: 'POST', + data, + custom: { + showSuccess: true, + loadingMsg: '登录中', + successMsg: '登录成功', + }, + }); + }, + // 使用手机 + 验证码登录 + smsLogin: (data) => { + return request({ + url: '/member/auth/sms-login', + method: 'POST', + data, + custom: { + showSuccess: true, + loadingMsg: '登录中', + successMsg: '登录成功', + }, + }); + }, + // 发送手机验证码 + sendSmsCode: (mobile, scene) => { + return request({ + url: '/member/auth/send-sms-code', + method: 'POST', + data: { + mobile, + scene, + }, + custom: { + loadingMsg: '发送中', + showSuccess: true, + successMsg: '发送成功', + }, + }); + }, + // 登出系统 + logout: () => { + return request({ + url: '/member/auth/logout', + method: 'POST', + }); + }, + // 刷新令牌 + refreshToken: (refreshToken) => { + return request({ + url: '/member/auth/refresh-token', + method: 'POST', + params: { + refreshToken + }, + custom: { + loading: false, // 不用加载中 + showError: false, // 不展示错误提示 + }, + }); + }, + // 社交授权的跳转 + socialAuthRedirect: (type, redirectUri) => { + return request({ + url: '/member/auth/social-auth-redirect', + method: 'GET', + params: { + type, + redirectUri, + }, + custom: { + showSuccess: true, + loadingMsg: '登陆中', + }, + }); + }, + // 社交快捷登录 + socialLogin: (type, code, state) => { + return request({ + url: '/member/auth/social-login', + method: 'POST', + data: { + type, + code, + state, + }, + custom: { + showSuccess: true, + loadingMsg: '登陆中', + }, + }); + }, + // 微信小程序的一键登录 + weixinMiniAppLogin: (phoneCode, loginCode, state) => { + return request({ + url: '/member/auth/weixin-mini-app-login', + method: 'POST', + data: { + phoneCode, + loginCode, + state + }, + custom: { + showSuccess: true, + loadingMsg: '登陆中', + successMsg: '登录成功', + }, + }); + }, + // 创建微信 JS SDK 初始化所需的签名 + createWeixinMpJsapiSignature: (url) => { + return request({ + url: '/member/auth/create-weixin-jsapi-signature', + method: 'POST', + params: { + url + }, + custom: { + showError: false, + showLoading: false, + }, + }) + }, + // +}; + +export default AuthUtil; diff --git a/yudao-mall-uniapp-master/sheep/api/member/point.js b/yudao-mall-uniapp-master/sheep/api/member/point.js new file mode 100644 index 0000000..188ffd4 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/point.js @@ -0,0 +1,19 @@ +import request from '@/sheep/request'; + +const PointApi = { + // 获得用户积分记录分页 + getPointRecordPage: (params) => { + if (params.addStatus === undefined) { + delete params.addStatus + } + const queryString = Object.keys(params) + .map((key) => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/member/point/record/page?${queryString}`, + method: 'GET', + }); + } +}; + +export default PointApi; diff --git a/yudao-mall-uniapp-master/sheep/api/member/signin.js b/yudao-mall-uniapp-master/sheep/api/member/signin.js new file mode 100644 index 0000000..35169ef --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/signin.js @@ -0,0 +1,37 @@ +import request from '@/sheep/request'; + +const SignInApi = { + // 获得签到规则列表 + getSignInConfigList: () => { + return request({ + url: '/member/sign-in/config/list', + method: 'GET', + }); + }, + // 获得个人签到统计 + getSignInRecordSummary: () => { + return request({ + url: '/member/sign-in/record/get-summary', + method: 'GET', + }); + }, + // 签到 + createSignInRecord: () => { + return request({ + url: '/member/sign-in/record/create', + method: 'POST', + }); + }, + // 获得签到记录分页 + getSignRecordPage: (params) => { + const queryString = Object.keys(params) + .map((key) => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/member/sign-in/record/page?${queryString}`, + method: 'GET', + }); + }, +}; + +export default SignInApi; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/member/social.js b/yudao-mall-uniapp-master/sheep/api/member/social.js new file mode 100644 index 0000000..f7ab259 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/social.js @@ -0,0 +1,54 @@ +import request from '@/sheep/request'; + +const SocialApi = { + // 获得社交用户 + getSocialUser: (type) => { + return request({ + url: '/member/social-user/get', + method: 'GET', + params: { + type + }, + custom: { + showLoading: false, + }, + }); + }, + // 社交绑定 + socialBind: (type, code, state) => { + return request({ + url: '/member/social-user/bind', + method: 'POST', + data: { + type, + code, + state + }, + custom: { + custom: { + showSuccess: true, + loadingMsg: '绑定中', + successMsg: '绑定成功', + }, + }, + }); + }, + // 社交绑定 + socialUnbind: (type, openid) => { + return request({ + url: '/member/social-user/unbind', + method: 'DELETE', + data: { + type, + openid + }, + custom: { + showLoading: false, + loadingMsg: '解除绑定', + successMsg: '解绑成功', + }, + }); + }, +}; + +export default SocialApi; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/member/user.js b/yudao-mall-uniapp-master/sheep/api/member/user.js new file mode 100644 index 0000000..5f06e42 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/member/user.js @@ -0,0 +1,85 @@ +import request from '@/sheep/request'; + +const UserApi = { + // 获得基本信息 + getUserInfo: () => { + return request({ + url: '/member/user/get', + method: 'GET', + custom: { + showLoading: false, + auth: true, + }, + }); + }, + // 修改基本信息 + updateUser: (data) => { + return request({ + url: '/member/user/update', + method: 'PUT', + data, + custom: { + auth: true, + showSuccess: true, + successMsg: '更新成功' + }, + }); + }, + // 修改用户手机 + updateUserMobile: (data) => { + return request({ + url: '/member/user/update-mobile', + method: 'PUT', + data, + custom: { + loadingMsg: '验证中', + showSuccess: true, + successMsg: '修改成功' + }, + }); + }, + // 基于微信小程序的授权码,修改用户手机 + updateUserMobileByWeixin: (code) => { + return request({ + url: '/member/user/update-mobile-by-weixin', + method: 'PUT', + data: { + code + }, + custom: { + showSuccess: true, + loadingMsg: '获取中', + successMsg: '修改成功' + }, + }); + }, + // 修改密码 + updateUserPassword: (data) => { + return request({ + url: '/member/user/update-password', + method: 'PUT', + data, + custom: { + loadingMsg: '验证中', + showSuccess: true, + successMsg: '修改成功' + }, + }); + }, + // 重置密码 + resetUserPassword: (data) => { + return request({ + url: '/member/user/reset-password', + method: 'PUT', + data, + custom: { + loadingMsg: '验证中', + showSuccess: true, + successMsg: '修改成功' + } + }); + }, + +}; + +export default UserApi; diff --git a/yudao-mall-uniapp-master/sheep/api/migration/app.js b/yudao-mall-uniapp-master/sheep/api/migration/app.js new file mode 100644 index 0000000..158414f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/migration/app.js @@ -0,0 +1,21 @@ +import request from '@/sheep/request'; + +// TODO 芋艿:小程序直播还不支持 +export default { + //小程序直播 + mplive: { + getRoomList: (ids) => + request({ + url: 'app/mplive/getRoomList', + method: 'GET', + params: { + ids: ids.join(','), + } + }), + getMpLink: () => + request({ + url: 'app/mplive/getMpLink', + method: 'GET' + }), + }, +}; diff --git a/yudao-mall-uniapp-master/sheep/api/migration/chat.js b/yudao-mall-uniapp-master/sheep/api/migration/chat.js new file mode 100644 index 0000000..140dd75 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/migration/chat.js @@ -0,0 +1,14 @@ +import request from '@/sheep/request'; + +// TODO 芋艿:暂不支持 socket 聊天 +export default { + // 获取聊天token + unifiedToken: () => + request({ + url: 'unifiedToken', + custom: { + showError: false, + showLoading: false, + }, + }), +}; diff --git a/yudao-mall-uniapp-master/sheep/api/migration/index.js b/yudao-mall-uniapp-master/sheep/api/migration/index.js new file mode 100644 index 0000000..31a85ef --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/migration/index.js @@ -0,0 +1,10 @@ +const files = import.meta.glob('./*.js', { eager: true }); +let api = {}; +Object.keys(files).forEach((key) => { + api = { + ...api, + [key.replace(/(.*\/)*([^.]+).*/gi, '$2')]: files[key].default, + }; +}); + +export default api; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/migration/third.js b/yudao-mall-uniapp-master/sheep/api/migration/third.js new file mode 100644 index 0000000..85db8cc --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/migration/third.js @@ -0,0 +1,48 @@ +import request from '@/sheep/request'; + +export default { + // 微信相关 + wechat: { + // 小程序订阅消息 + subscribeTemplate: (params) => + request({ + url: 'third/wechat/subscribeTemplate', + method: 'GET', + params: { + platform: 'miniProgram', + }, + custom: { + showError: false, + showLoading: false, + }, + }), + + // 获取微信小程序码 + getWxacode: async (path, query) => { + return await request({ + url: '/member/social-user/wxa-qrcode', + method: 'POST', + data: { + scene: query, + path, + checkPath: false, // TODO 开发环境暂不检查 path 是否存在 + }, + }); + }, + }, + + // 苹果相关 + apple: { + // 第三方登录 + login: (data) => + request({ + url: 'third/apple/login', + method: 'POST', + data, + custom: { + showSuccess: true, + loadingMsg: '登陆中', + }, + }), + }, +}; diff --git a/yudao-mall-uniapp-master/sheep/api/pay/channel.js b/yudao-mall-uniapp-master/sheep/api/pay/channel.js new file mode 100644 index 0000000..4e7bfc5 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/pay/channel.js @@ -0,0 +1,14 @@ +import request from '@/sheep/request'; + +const PayChannelApi = { + // 获得指定应用的开启的支付渠道编码列表 + getEnableChannelCodeList: (appId) => { + return request({ + url: '/pay/channel/get-enable-code-list', + method: 'GET', + params: { appId } + }); + }, +}; + +export default PayChannelApi; diff --git a/yudao-mall-uniapp-master/sheep/api/pay/order.js b/yudao-mall-uniapp-master/sheep/api/pay/order.js new file mode 100644 index 0000000..f985359 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/pay/order.js @@ -0,0 +1,22 @@ +import request from '@/sheep/request'; + +const PayOrderApi = { + // 获得支付订单 + getOrder: (id) => { + return request({ + url: '/pay/order/get', + method: 'GET', + params: { id } + }); + }, + // 提交支付订单 + submitOrder: (data) => { + return request({ + url: '/pay/order/submit', + method: 'POST', + data + }); + } +}; + +export default PayOrderApi; diff --git a/yudao-mall-uniapp-master/sheep/api/pay/wallet.js b/yudao-mall-uniapp-master/sheep/api/pay/wallet.js new file mode 100644 index 0000000..023902a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/pay/wallet.js @@ -0,0 +1,68 @@ +import request from '@/sheep/request'; + +const PayWalletApi = { + // 获取钱包 + getPayWallet() { + return request({ + url: '/pay/wallet/get', + method: 'GET', + custom: { + showLoading: false, + auth: true, + }, + }); + }, + // 获得钱包流水分页 + getWalletTransactionPage: (params) => { + const queryString = Object.keys(params) + .map((key) => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/pay/wallet-transaction/page?${queryString}`, + method: 'GET', + }); + }, + // 获得钱包流水统计 + getWalletTransactionSummary: (params) => { + const queryString = `createTime=${params.createTime[0]}&createTime=${params.createTime[1]}`; + return request({ + url: `/pay/wallet-transaction/get-summary?${queryString}`, + // url: `/pay/wallet-transaction/get-summary`, + method: 'GET', + // params: params + }); + }, + // 获得钱包充值套餐列表 + getWalletRechargePackageList: () => { + return request({ + url: '/pay/wallet-recharge-package/list', + method: 'GET', + custom: { + showError: false, + showLoading: false, + }, + }); + }, + // 创建钱包充值记录(发起充值) + createWalletRecharge: (data) => { + return request({ + url: '/pay/wallet-recharge/create', + method: 'POST', + data, + }); + }, + // 获得钱包充值记录分页 + getWalletRechargePage: (params) => { + return request({ + url: '/pay/wallet-recharge/page', + method: 'GET', + params, + custom: { + showError: false, + showLoading: false, + }, + }); + }, +}; + +export default PayWalletApi; diff --git a/yudao-mall-uniapp-master/sheep/api/product/category.js b/yudao-mall-uniapp-master/sheep/api/product/category.js new file mode 100644 index 0000000..3b6f8f0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/product/category.js @@ -0,0 +1,21 @@ +import request from '@/sheep/request'; + +const CategoryApi = { + // 查询分类列表 + getCategoryList: () => { + return request({ + url: '/product/category/list', + method: 'GET', + }); + }, + // 查询分类列表,指定编号 + getCategoryListByIds: (ids) => { + return request({ + url: '/product/category/list-by-ids', + method: 'GET', + params: { ids }, + }); + }, +}; + +export default CategoryApi; diff --git a/yudao-mall-uniapp-master/sheep/api/product/comment.js b/yudao-mall-uniapp-master/sheep/api/product/comment.js new file mode 100644 index 0000000..2bbffd1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/product/comment.js @@ -0,0 +1,22 @@ +import request from '@/sheep/request'; + +const CommentApi = { + // 获得商品评价分页 + getCommentPage: (spuId, pageNo, pageSize, type) => { + return request({ + url: '/product/comment/page', + method: 'GET', + params: { + spuId, + pageNo, + pageSize, + type, + }, + custom: { + showLoading: false, + showError: false, + }, + }); + }, +}; +export default CommentApi; diff --git a/yudao-mall-uniapp-master/sheep/api/product/favorite.js b/yudao-mall-uniapp-master/sheep/api/product/favorite.js new file mode 100644 index 0000000..134c231 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/product/favorite.js @@ -0,0 +1,54 @@ +import request from '@/sheep/request'; + +const FavoriteApi = { + // 获得商品收藏分页 + getFavoritePage: (data) => { + return request({ + url: '/product/favorite/page', + method: 'GET', + params: data, + }); + }, + // 检查是否收藏过商品 + isFavoriteExists: (spuId) => { + return request({ + url: '/product/favorite/exits', + method: 'GET', + params: { + spuId, + }, + }); + }, + // 添加商品收藏 + createFavorite: (spuId) => { + return request({ + url: '/product/favorite/create', + method: 'POST', + data: { + spuId, + }, + custom: { + auth: true, + showSuccess: true, + successMsg: '收藏成功', + }, + }); + }, + // 取消商品收藏 + deleteFavorite: (spuId) => { + return request({ + url: '/product/favorite/delete', + method: 'DELETE', + data: { + spuId, + }, + custom: { + auth: true, + showSuccess: true, + successMsg: '取消成功', + }, + }); + }, +}; + +export default FavoriteApi; diff --git a/yudao-mall-uniapp-master/sheep/api/product/history.js b/yudao-mall-uniapp-master/sheep/api/product/history.js new file mode 100644 index 0000000..9ed53e3 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/product/history.js @@ -0,0 +1,39 @@ +import request from '@/sheep/request'; + +const SpuHistoryApi = { + // 删除商品浏览记录 + deleteBrowseHistory: (spuIds) => { + return request({ + url: '/product/browse-history/delete', + method: 'DELETE', + data: { spuIds }, + custom: { + showSuccess: true, + successMsg: '删除成功', + }, + }); + }, + // 清空商品浏览记录 + cleanBrowseHistory: () => { + return request({ + url: '/product/browse-history/clean', + method: 'DELETE', + custom: { + showSuccess: true, + successMsg: '清空成功', + }, + }); + }, + // 获得商品浏览记录分页 + getBrowseHistoryPage: (data) => { + return request({ + url: '/product/browse-history/page', + method: 'GET', + data, + custom: { + showLoading: false + }, + }); + }, +}; +export default SpuHistoryApi; diff --git a/yudao-mall-uniapp-master/sheep/api/product/spu.js b/yudao-mall-uniapp-master/sheep/api/product/spu.js new file mode 100644 index 0000000..3b84c1d --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/product/spu.js @@ -0,0 +1,41 @@ +import request from '@/sheep/request'; + +const SpuApi = { + // 获得商品 SPU 列表 + getSpuListByIds: (ids) => { + return request({ + url: '/product/spu/list-by-ids', + method: 'GET', + params: { ids }, + custom: { + showLoading: false, + showError: false, + }, + }); + }, + // 获得商品 SPU 分页 + getSpuPage: (params) => { + return request({ + url: '/product/spu/page', + method: 'GET', + params, + custom: { + showLoading: false, + showError: false, + }, + }); + }, + // 查询商品 + getSpuDetail: (id) => { + return request({ + url: '/product/spu/get-detail', + method: 'GET', + params: { id }, + custom: { + showLoading: false, + showError: false, + }, + }); + }, +}; +export default SpuApi; diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/activity.js b/yudao-mall-uniapp-master/sheep/api/promotion/activity.js new file mode 100644 index 0000000..eb47ce1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/activity.js @@ -0,0 +1,16 @@ +import request from '@/sheep/request'; + +const ActivityApi = { + // 获得单个商品,近期参与的每个活动 + getActivityListBySpuId: (spuId) => { + return request({ + url: '/promotion/activity/list-by-spu-id', + method: 'GET', + params: { + spuId, + }, + }); + }, +}; + +export default ActivityApi; diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/article.js b/yudao-mall-uniapp-master/sheep/api/promotion/article.js new file mode 100644 index 0000000..ded5fb1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/article.js @@ -0,0 +1,12 @@ +import request from '@/sheep/request'; + +export default { + // 获得文章详情 + getArticle: (id, title) => { + return request({ + url: '/promotion/article/get', + method: 'GET', + params: { id, title } + }); + } +} diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/combination.js b/yudao-mall-uniapp-master/sheep/api/promotion/combination.js new file mode 100644 index 0000000..44f61e9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/combination.js @@ -0,0 +1,76 @@ +import request from '@/sheep/request'; + +// 拼团 API +const CombinationApi = { + // 获得拼团活动列表 + getCombinationActivityList: (count) => { + return request({ + url: '/promotion/combination-activity/list', + method: 'GET', + params: { count }, + }); + }, + + // 获得拼团活动分页 + getCombinationActivityPage: (params) => { + return request({ + url: '/promotion/combination-activity/page', + method: 'GET', + params, + }); + }, + + // 获得拼团活动明细 + getCombinationActivity: (id) => { + return request({ + url: '/promotion/combination-activity/get-detail', + method: 'GET', + params: { + id, + }, + }); + }, + + // 获得最近 n 条拼团记录(团长发起的) + getHeadCombinationRecordList: (activityId, status, count) => { + return request({ + url: '/promotion/combination-record/get-head-list', + method: 'GET', + params: { + activityId, + status, + count, + }, + }); + }, + + // 获得我的拼团记录分页 + getCombinationRecordPage: (params) => { + return request({ + url: "/promotion/combination-record/page", + method: 'GET', + params + }); + }, + + // 获得拼团记录明细 + getCombinationRecordDetail: (id) => { + return request({ + url: '/promotion/combination-record/get-detail', + method: 'GET', + params: { + id, + }, + }); + }, + + // 获得拼团记录的概要信息 + getCombinationRecordSummary: () => { + return request({ + url: '/promotion/combination-record/get-summary', + method: 'GET', + }); + }, +}; + +export default CombinationApi; diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/coupon.js b/yudao-mall-uniapp-master/sheep/api/promotion/coupon.js new file mode 100644 index 0000000..c9dfa52 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/coupon.js @@ -0,0 +1,101 @@ +import request from '@/sheep/request'; + +const CouponApi = { + // 获得优惠劵模板列表 + getCouponTemplateListByIds: (ids) => { + return request({ + url: '/promotion/coupon-template/list-by-ids', + method: 'GET', + params: { ids }, + custom: { + showLoading: false, // 不展示 Loading,避免领取优惠劵时,不成功提示 + showError: false, + }, + }); + }, + // 获得优惠劵模版列表 + getCouponTemplateList: (spuId, productScope, count) => { + return request({ + url: '/promotion/coupon-template/list', + method: 'GET', + params: { spuId, productScope, count }, + }); + }, + // 获得优惠劵模版分页 + getCouponTemplatePage: (params) => { + return request({ + url: '/promotion/coupon-template/page', + method: 'GET', + params, + }); + }, + // 获得优惠劵模版 + getCouponTemplate: (id) => { + return request({ + url: '/promotion/coupon-template/get', + method: 'GET', + params: { id }, + }); + }, + // 我的优惠劵列表 + getCouponPage: (params) => { + return request({ + url: '/promotion/coupon/page', + method: 'GET', + params, + }); + }, + // 领取优惠券 + takeCoupon: (templateId) => { + return request({ + url: '/promotion/coupon/take', + method: 'POST', + data: { templateId }, + custom: { + auth: true, + showLoading: true, + loadingMsg: '领取中', + showSuccess: true, + successMsg: '领取成功', + }, + }); + }, + // 获得优惠劵 + getCoupon: (id) => { + return request({ + url: '/promotion/coupon/get', + method: 'GET', + params: { id }, + }); + }, + // 获得未使用的优惠劵数量 + getUnusedCouponCount: () => { + return request({ + url: '/promotion/coupon/get-unused-count', + method: 'GET', + custom: { + showLoading: false, + auth: true, + }, + }); + }, + // 获得匹配指定商品的优惠劵列表 + getMatchCouponList: (price, spuIds, skuIds, categoryIds) => { + return request({ + url: '/promotion/coupon/match-list', + method: 'GET', + params: { + price, + spuIds: spuIds.join(','), + skuIds: skuIds.join(','), + categoryIds: categoryIds.join(','), + }, + custom: { + showError: false, + showLoading: false, // 避免影响 settlementOrder 结算的结果 + }, + }); + } +}; + +export default CouponApi; diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/diy.js b/yudao-mall-uniapp-master/sheep/api/promotion/diy.js new file mode 100644 index 0000000..e524f69 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/diy.js @@ -0,0 +1,38 @@ +import request from '@/sheep/request'; + +const DiyApi = { + getUsedDiyTemplate: () => { + return request({ + url: '/promotion/diy-template/used', + method: 'GET', + custom: { + showError: false, + showLoading: false, + }, + }); + }, + getDiyTemplate: (id) => { + return request({ + url: '/promotion/diy-template/get', + method: 'GET', + params: { + id + }, + custom: { + showError: false, + showLoading: false, + }, + }); + }, + getDiyPage: (id) => { + return request({ + url: '/promotion/diy-page/get', + method: 'GET', + params: { + id + } + }); + }, +}; + +export default DiyApi; diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/rewardActivity.js b/yudao-mall-uniapp-master/sheep/api/promotion/rewardActivity.js new file mode 100644 index 0000000..5f74db7 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/rewardActivity.js @@ -0,0 +1,14 @@ +import request from '@/sheep/request'; + +const RewardActivityApi = { + // 获得满减送活动 + getRewardActivity: (id) => { + return request({ + url: '/promotion/reward-activity/get', + method: 'GET', + params: { id }, + }); + } +}; + +export default RewardActivityApi; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/promotion/seckill.js b/yudao-mall-uniapp-master/sheep/api/promotion/seckill.js new file mode 100644 index 0000000..4d41e8b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/promotion/seckill.js @@ -0,0 +1,33 @@ +import request from "@/sheep/request"; + +const SeckillApi = { + // 获得秒杀时间段列表 + getSeckillConfigList: () => { + return request({ url: 'promotion/seckill-config/list', method: 'GET' }); + }, + + // 获得当前秒杀活动 + getNowSeckillActivity: () => { + return request({ url: 'promotion/seckill-activity/get-now', method: 'GET' }); + }, + + // 获得秒杀活动分页 + getSeckillActivityPage: (params) => { + return request({ url: 'promotion/seckill-activity/page', method: 'GET', params }); + }, + + /** + * 获得秒杀活动明细 + * @param {number} id 秒杀活动编号 + * @return {*} + */ + getSeckillActivity: (id) => { + return request({ + url: 'promotion/seckill-activity/get-detail', + method: 'GET', + params: { id } + }); + } +} + +export default SeckillApi; diff --git a/yudao-mall-uniapp-master/sheep/api/system/area.js b/yudao-mall-uniapp-master/sheep/api/system/area.js new file mode 100644 index 0000000..7c41eff --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/system/area.js @@ -0,0 +1,13 @@ +import request from '@/sheep/request'; + +const AreaApi = { + // 获得地区树 + getAreaTree: () => { + return request({ + url: '/system/area/tree', + method: 'GET' + }); + }, +}; + +export default AreaApi; diff --git a/yudao-mall-uniapp-master/sheep/api/trade/afterSale.js b/yudao-mall-uniapp-master/sheep/api/trade/afterSale.js new file mode 100644 index 0000000..44c4dd3 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/afterSale.js @@ -0,0 +1,63 @@ +import request from '@/sheep/request'; + +const AfterSaleApi = { + // 获得售后分页 + getAfterSalePage: (params) => { + return request({ + url: `/trade/after-sale/page`, + method: 'GET', + params, + custom: { + showLoading: false, + }, + }); + }, + // 创建售后 + createAfterSale: (data) => { + return request({ + url: `/trade/after-sale/create`, + method: 'POST', + data, + }); + }, + // 获得售后 + getAfterSale: (id) => { + return request({ + url: `/trade/after-sale/get`, + method: 'GET', + params: { + id, + }, + }); + }, + // 取消售后 + cancelAfterSale: (id) => { + return request({ + url: `/trade/after-sale/cancel`, + method: 'DELETE', + params: { + id, + }, + }); + }, + // 获得售后日志列表 + getAfterSaleLogList: (afterSaleId) => { + return request({ + url: `/trade/after-sale-log/list`, + method: 'GET', + params: { + afterSaleId, + }, + }); + }, + // 退回货物 + deliveryAfterSale: (data) => { + return request({ + url: `/trade/after-sale/delivery`, + method: 'PUT', + data, + }); + } +}; + +export default AfterSaleApi; diff --git a/yudao-mall-uniapp-master/sheep/api/trade/brokerage.js b/yudao-mall-uniapp-master/sheep/api/trade/brokerage.js new file mode 100644 index 0000000..bc948cf --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/brokerage.js @@ -0,0 +1,93 @@ +import request from '@/sheep/request'; + +const BrokerageApi = { + // 绑定推广员 + bindBrokerageUser: (data)=>{ + return request({ + url: '/trade/brokerage-user/bind', + method: 'PUT', + data + }); + }, + // 获得个人分销信息 + getBrokerageUser: () => { + return request({ + url: '/trade/brokerage-user/get', + method: 'GET' + }); + }, + // 获得个人分销统计 + getBrokerageUserSummary: () => { + return request({ + url: '/trade/brokerage-user/get-summary', + method: 'GET', + }); + }, + // 获得分销记录分页 + getBrokerageRecordPage: params => { + if (params.status === undefined) { + delete params.status + } + const queryString = Object.keys(params) + .map(key => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/trade/brokerage-record/page?${queryString}`, + method: 'GET', + }); + }, + // 创建分销提现 + createBrokerageWithdraw: data => { + return request({ + url: '/trade/brokerage-withdraw/create', + method: 'POST', + data, + }); + }, + // 获得商品的分销金额 + getProductBrokeragePrice: spuId => { + return request({ + url: '/trade/brokerage-record/get-product-brokerage-price', + method: 'GET', + params: { spuId } + }); + }, + // 获得分销用户排行(基于佣金) + getRankByPrice: params => { + const queryString = `times=${params.times[0]}×=${params.times[1]}`; + return request({ + url: `/trade/brokerage-user/get-rank-by-price?${queryString}`, + method: 'GET', + }); + }, + // 获得分销用户排行分页(基于佣金) + getBrokerageUserChildSummaryPageByPrice: params => { + const queryString = Object.keys(params) + .map(key => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/trade/brokerage-user/rank-page-by-price?${queryString}`, + method: 'GET', + }); + }, + // 获得分销用户排行分页(基于用户量) + getBrokerageUserRankPageByUserCount: params => { + const queryString = Object.keys(params) + .map(key => encodeURIComponent(key) + '=' + params[key]) + .join('&'); + return request({ + url: `/trade/brokerage-user/rank-page-by-user-count?${queryString}`, + method: 'GET', + }); + }, + // 获得下级分销统计分页 + getBrokerageUserChildSummaryPage: params => { + return request({ + url: '/trade/brokerage-user/child-summary-page', + method: 'GET', + params, + }) + } +} + +export default BrokerageApi diff --git a/yudao-mall-uniapp-master/sheep/api/trade/cart.js b/yudao-mall-uniapp-master/sheep/api/trade/cart.js new file mode 100644 index 0000000..63cea18 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/cart.js @@ -0,0 +1,50 @@ +import request from '@/sheep/request'; + +const CartApi = { + addCart: (data) => { + return request({ + url: '/trade/cart/add', + method: 'POST', + data: data, + custom: { + showSuccess: true, + successMsg: '已添加到购物车~', + } + }); + }, + updateCartCount: (data) => { + return request({ + url: '/trade/cart/update-count', + method: 'PUT', + data: data + }); + }, + updateCartSelected: (data) => { + return request({ + url: '/trade/cart/update-selected', + method: 'PUT', + data: data + }); + }, + deleteCart: (ids) => { + return request({ + url: '/trade/cart/delete', + method: 'DELETE', + params: { + ids + } + }); + }, + getCartList: () => { + return request({ + url: '/trade/cart/list', + method: 'GET', + custom: { + showLoading: false, + auth: true, + }, + }); + }, +}; + +export default CartApi; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/api/trade/config.js b/yudao-mall-uniapp-master/sheep/api/trade/config.js new file mode 100644 index 0000000..16806ed --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/config.js @@ -0,0 +1,13 @@ +import request from '@/sheep/request'; + +const TradeConfigApi = { + // 获得交易配置 + getTradeConfig: () => { + return request({ + url: `/trade/config/get`, + method: 'GET', + }); + }, +}; + +export default TradeConfigApi; diff --git a/yudao-mall-uniapp-master/sheep/api/trade/delivery.js b/yudao-mall-uniapp-master/sheep/api/trade/delivery.js new file mode 100644 index 0000000..27a08d9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/delivery.js @@ -0,0 +1,13 @@ +import request from '@/sheep/request'; + +const DeliveryApi = { + // 获得快递公司列表 + getDeliveryExpressList: () => { + return request({ + url: `/trade/delivery/express/list`, + method: 'get', + }); + } +}; + +export default DeliveryApi; diff --git a/yudao-mall-uniapp-master/sheep/api/trade/order.js b/yudao-mall-uniapp-master/sheep/api/trade/order.js new file mode 100644 index 0000000..4d57125 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/api/trade/order.js @@ -0,0 +1,139 @@ +import request from '@/sheep/request'; + +const OrderApi = { + // 计算订单信息 + settlementOrder: (data) => { + const data2 = { + ...data, + }; + // 移除多余字段 + if (!(data.couponId > 0)) { + delete data2.couponId; + } + if (!(data.addressId > 0)) { + delete data2.addressId; + } + if (!(data.combinationActivityId > 0)) { + delete data2.combinationActivityId; + } + if (!(data.combinationHeadId > 0)) { + delete data2.combinationHeadId; + } + if (!(data.seckillActivityId > 0)) { + delete data2.seckillActivityId; + } + // 解决 SpringMVC 接受 List 参数的问题 + delete data2.items; + for (let i = 0; i < data.items.length; i++) { + data2[encodeURIComponent('items[' + i + '' + '].skuId')] = data.items[i].skuId + ''; + data2[encodeURIComponent('items[' + i + '' + '].count')] = data.items[i].count + ''; + if (data.items[i].cartId) { + data2[encodeURIComponent('items[' + i + '' + '].cartId')] = data.items[i].cartId + ''; + } + } + const queryString = Object.keys(data2) + .map((key) => key + '=' + data2[key]) + .join('&'); + return request({ + url: `/trade/order/settlement?${queryString}`, + method: 'GET', + custom: { + showError: true, + showLoading: true, + }, + }); + }, + // 创建订单 + createOrder: (data) => { + return request({ + url: `/trade/order/create`, + method: 'POST', + data, + }); + }, + // 获得订单 + getOrder: (id) => { + return request({ + url: `/trade/order/get-detail`, + method: 'GET', + params: { + id, + }, + custom: { + showLoading: false, + }, + }); + }, + // 订单列表 + getOrderPage: (params) => { + return request({ + url: '/trade/order/page', + method: 'GET', + params, + custom: { + showLoading: false, + }, + }); + }, + // 确认收货 + receiveOrder: (id) => { + return request({ + url: `/trade/order/receive`, + method: 'PUT', + params: { + id, + }, + }); + }, + // 取消订单 + cancelOrder: (id) => { + return request({ + url: `/trade/order/cancel`, + method: 'DELETE', + params: { + id, + }, + }); + }, + // 删除订单 + deleteOrder: (id) => { + return request({ + url: `/trade/order/delete`, + method: 'DELETE', + params: { + id, + }, + }); + }, + // 获得交易订单的物流轨迹 + getOrderExpressTrackList: (id) => { + return request({ + url: `/trade/order/get-express-track-list`, + method: 'GET', + params: { + id, + }, + }); + }, + // 获得交易订单数量 + getOrderCount: () => { + return request({ + url: '/trade/order/get-count', + method: 'GET', + custom: { + showLoading: false, + auth: true, + }, + }); + }, + // 创建单个评论 + createOrderItemComment: (data) => { + return request({ + url: `/trade/order/item/create-comment`, + method: 'POST', + data, + }); + }, +}; + +export default OrderApi; diff --git a/yudao-mall-uniapp-master/sheep/components/s-activity-pop/s-activity-pop.vue b/yudao-mall-uniapp-master/sheep/components/s-activity-pop/s-activity-pop.vue new file mode 100644 index 0000000..432dc45 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-activity-pop/s-activity-pop.vue @@ -0,0 +1,105 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-address-item/s-address-item.vue b/yudao-mall-uniapp-master/sheep/components/s-address-item/s-address-item.vue new file mode 100644 index 0000000..f1b54b3 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-address-item/s-address-item.vue @@ -0,0 +1,112 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/account-login.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/account-login.vue new file mode 100644 index 0000000..579614c --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/account-login.vue @@ -0,0 +1,107 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-mobile.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-mobile.vue new file mode 100644 index 0000000..f4dd5f1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-mobile.vue @@ -0,0 +1,127 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-password.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-password.vue new file mode 100644 index 0000000..b02ea02 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/change-password.vue @@ -0,0 +1,106 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/mp-authorization.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/mp-authorization.vue new file mode 100644 index 0000000..df5867f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/mp-authorization.vue @@ -0,0 +1,152 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/reset-password.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/reset-password.vue new file mode 100644 index 0000000..bc1be8b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/reset-password.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/sms-login.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/sms-login.vue new file mode 100644 index 0000000..0651b78 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/components/sms-login.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/index.scss b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/index.scss new file mode 100644 index 0000000..c4424e7 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/index.scss @@ -0,0 +1,151 @@ +@keyframes title-animation { + 0% { + font-size: 32rpx; + } + 100% { + font-size: 36rpx; + } +} + +.login-wrap { + padding: 50rpx 34rpx; + min-height: 500rpx; + background-color: #fff; + border-radius: 20rpx 20rpx 0 0; +} + +.head-box { + .head-title { + min-width: 160rpx; + font-size: 36rpx; + font-weight: bold; + color: #333333; + line-height: 36rpx; + } + .head-title-active { + width: 160rpx; + font-size: 32rpx; + font-weight: 600; + color: #999; + line-height: 36rpx; + } + .head-title-animation { + animation-name: title-animation; + animation-duration: 0.1s; + animation-timing-function: ease-out; + animation-fill-mode: forwards; + } + .head-title-line { + position: relative; + &::before { + content: ''; + width: 1rpx; + height: 34rpx; + background-color: #e4e7ed; + position: absolute; + left: -30rpx; + top: 50%; + transform: translateY(-50%); + } + } + .head-subtitle { + font-size: 26rpx; + font-weight: 400; + color: #afb6c0; + text-align: left; + display: flex; + } +} + +// .code-btn[disabled] { +// background-color: #fff; +// } +.code-btn-start { + width: 160rpx; + height: 56rpx; + line-height: normal; + border: 2rpx solid var(--ui-BG-Main); + border-radius: 28rpx; + font-size: 26rpx; + font-weight: 400; + color: var(--ui-BG-Main); + opacity: 1; +} + +.forgot-btn { + width: 160rpx; + line-height: 56rpx; + font-size: 30rpx; + font-weight: 500; + color: #999; +} + +.login-btn-start { + width: 158rpx; + height: 56rpx; + line-height: normal; + background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); + border-radius: 28rpx; + font-size: 26rpx; + font-weight: 500; + color: #fff; +} + +.type-btn { + padding: 20rpx; + margin: 40rpx auto; + width: 200rpx; + font-size: 30rpx; + font-weight: 500; + color: #999999; +} + +.auto-login-box { + width: 100%; + .auto-login-btn { + width: 68rpx; + height: 68rpx; + border-radius: 50%; + margin: 0 30rpx; + } + .auto-login-img { + width: 68rpx; + height: 68rpx; + border-radius: 50%; + } +} + +.agreement-box { + margin: 80rpx auto 0; + .protocol-check { + transform: scale(0.7); + } + .agreement-text { + font-size: 26rpx; + font-weight: 500; + color: #999999; + .tcp-text { + color: var(--ui-BG-Main); + } + } +} + +// 修改密码 +.editPwd-btn-box { + .save-btn { + width: 690rpx; + line-height: 70rpx; + background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); + border-radius: 35rpx; + font-size: 28rpx; + font-weight: 500; + color: #ffffff; + } + .forgot-btn { + width: 690rpx; + line-height: 70rpx; + font-size: 28rpx; + font-weight: 500; + color: #999999; + } +} diff --git a/yudao-mall-uniapp-master/sheep/components/s-auth-modal/s-auth-modal.vue b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/s-auth-modal.vue new file mode 100644 index 0000000..cf6a6ff --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-auth-modal/s-auth-modal.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-block-item/s-block-item.vue b/yudao-mall-uniapp-master/sheep/components/s-block-item/s-block-item.vue new file mode 100644 index 0000000..9cd6007 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-block-item/s-block-item.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-block/s-block.vue b/yudao-mall-uniapp-master/sheep/components/s-block/s-block.vue new file mode 100644 index 0000000..152b8a6 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-block/s-block.vue @@ -0,0 +1,54 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-count-down/s-count-down.vue b/yudao-mall-uniapp-master/sheep/components/s-count-down/s-count-down.vue new file mode 100644 index 0000000..98b3a1f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-count-down/s-count-down.vue @@ -0,0 +1,173 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/components/s-coupon-block/s-coupon-block.vue b/yudao-mall-uniapp-master/sheep/components/s-coupon-block/s-coupon-block.vue new file mode 100644 index 0000000..6250b4b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-coupon-block/s-coupon-block.vue @@ -0,0 +1,152 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-coupon-card/s-coupon-card.vue b/yudao-mall-uniapp-master/sheep/components/s-coupon-card/s-coupon-card.vue new file mode 100644 index 0000000..bd5705b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-coupon-card/s-coupon-card.vue @@ -0,0 +1,79 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/components/s-coupon-get/s-coupon-get.vue b/yudao-mall-uniapp-master/sheep/components/s-coupon-get/s-coupon-get.vue new file mode 100644 index 0000000..6df6b55 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-coupon-get/s-coupon-get.vue @@ -0,0 +1,109 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-coupon-list/s-coupon-list.vue b/yudao-mall-uniapp-master/sheep/components/s-coupon-list/s-coupon-list.vue new file mode 100644 index 0000000..411a4c0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-coupon-list/s-coupon-list.vue @@ -0,0 +1,205 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/components/s-coupon-select/s-coupon-select.vue b/yudao-mall-uniapp-master/sheep/components/s-coupon-select/s-coupon-select.vue new file mode 100644 index 0000000..e1a9db4 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-coupon-select/s-coupon-select.vue @@ -0,0 +1,138 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar-item.vue b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar-item.vue new file mode 100644 index 0000000..fce7ce7 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar-item.vue @@ -0,0 +1,66 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar.vue b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar.vue new file mode 100644 index 0000000..36050ec --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/components/navbar.vue @@ -0,0 +1,314 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/s-custom-navbar.vue b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/s-custom-navbar.vue new file mode 100644 index 0000000..d5f2418 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-custom-navbar/s-custom-navbar.vue @@ -0,0 +1,196 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-discount-list/s-discount-list.vue b/yudao-mall-uniapp-master/sheep/components/s-discount-list/s-discount-list.vue new file mode 100644 index 0000000..22fbd43 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-discount-list/s-discount-list.vue @@ -0,0 +1,114 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-empty/s-empty.vue b/yudao-mall-uniapp-master/sheep/components/s-empty/s-empty.vue new file mode 100644 index 0000000..27f8c4a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-empty/s-empty.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-float-menu/s-float-menu.vue b/yudao-mall-uniapp-master/sheep/components/s-float-menu/s-float-menu.vue new file mode 100644 index 0000000..b53db00 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-float-menu/s-float-menu.vue @@ -0,0 +1,88 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-goods-card/s-goods-card.vue b/yudao-mall-uniapp-master/sheep/components/s-goods-card/s-goods-card.vue new file mode 100644 index 0000000..59f2bf1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-goods-card/s-goods-card.vue @@ -0,0 +1,286 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-goods-column/s-goods-column.vue b/yudao-mall-uniapp-master/sheep/components/s-goods-column/s-goods-column.vue new file mode 100644 index 0000000..8939254 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-goods-column/s-goods-column.vue @@ -0,0 +1,721 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-goods-item/s-goods-item.vue b/yudao-mall-uniapp-master/sheep/components/s-goods-item/s-goods-item.vue new file mode 100644 index 0000000..456bb16 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-goods-item/s-goods-item.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-goods-scroll/s-goods-scroll.vue b/yudao-mall-uniapp-master/sheep/components/s-goods-scroll/s-goods-scroll.vue new file mode 100644 index 0000000..175cc66 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-goods-scroll/s-goods-scroll.vue @@ -0,0 +1,33 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-goods-shelves/s-goods-shelves.vue b/yudao-mall-uniapp-master/sheep/components/s-goods-shelves/s-goods-shelves.vue new file mode 100644 index 0000000..e2ce60a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-goods-shelves/s-goods-shelves.vue @@ -0,0 +1,147 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-groupon-block/s-groupon-block.vue b/yudao-mall-uniapp-master/sheep/components/s-groupon-block/s-groupon-block.vue new file mode 100644 index 0000000..2c32d60 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-groupon-block/s-groupon-block.vue @@ -0,0 +1,154 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-hotzone-block/s-hotzone-block.vue b/yudao-mall-uniapp-master/sheep/components/s-hotzone-block/s-hotzone-block.vue new file mode 100644 index 0000000..246d6d4 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-hotzone-block/s-hotzone-block.vue @@ -0,0 +1,46 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-image-banner/s-image-banner.vue b/yudao-mall-uniapp-master/sheep/components/s-image-banner/s-image-banner.vue new file mode 100644 index 0000000..478e7af --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-image-banner/s-image-banner.vue @@ -0,0 +1,44 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-image-block/s-image-block.vue b/yudao-mall-uniapp-master/sheep/components/s-image-block/s-image-block.vue new file mode 100644 index 0000000..c898749 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-image-block/s-image-block.vue @@ -0,0 +1,27 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-image-cube/s-image-cube.vue b/yudao-mall-uniapp-master/sheep/components/s-image-cube/s-image-cube.vue new file mode 100644 index 0000000..9794d8f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-image-cube/s-image-cube.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-layout/s-layout.vue b/yudao-mall-uniapp-master/sheep/components/s-layout/s-layout.vue new file mode 100644 index 0000000..541abea --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-layout/s-layout.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-line-block/s-line-block.vue b/yudao-mall-uniapp-master/sheep/components/s-line-block/s-line-block.vue new file mode 100644 index 0000000..c0628f9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-line-block/s-line-block.vue @@ -0,0 +1,15 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-live-block/s-live-block.vue b/yudao-mall-uniapp-master/sheep/components/s-live-block/s-live-block.vue new file mode 100644 index 0000000..9d1ad03 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-live-block/s-live-block.vue @@ -0,0 +1,144 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-live-card/s-live-card.vue b/yudao-mall-uniapp-master/sheep/components/s-live-card/s-live-card.vue new file mode 100644 index 0000000..9cefee0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-live-card/s-live-card.vue @@ -0,0 +1,234 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-menu-button/s-menu-button.vue b/yudao-mall-uniapp-master/sheep/components/s-menu-button/s-menu-button.vue new file mode 100644 index 0000000..375a591 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-menu-button/s-menu-button.vue @@ -0,0 +1,363 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-menu-grid/s-menu-grid.vue b/yudao-mall-uniapp-master/sheep/components/s-menu-grid/s-menu-grid.vue new file mode 100644 index 0000000..518d6ed --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-menu-grid/s-menu-grid.vue @@ -0,0 +1,82 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-menu-list/s-menu-list.vue b/yudao-mall-uniapp-master/sheep/components/s-menu-list/s-menu-list.vue new file mode 100644 index 0000000..ecbb396 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-menu-list/s-menu-list.vue @@ -0,0 +1,66 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-menu-tools/s-menu-tools.vue b/yudao-mall-uniapp-master/sheep/components/s-menu-tools/s-menu-tools.vue new file mode 100644 index 0000000..ee2058c --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-menu-tools/s-menu-tools.vue @@ -0,0 +1,118 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-notice-block/s-notice-block.vue b/yudao-mall-uniapp-master/sheep/components/s-notice-block/s-notice-block.vue new file mode 100644 index 0000000..e7d74a0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-notice-block/s-notice-block.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-order-card/s-order-card.vue b/yudao-mall-uniapp-master/sheep/components/s-order-card/s-order-card.vue new file mode 100644 index 0000000..095e6cf --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-order-card/s-order-card.vue @@ -0,0 +1,108 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-popup-image/s-popup-image.vue b/yudao-mall-uniapp-master/sheep/components/s-popup-image/s-popup-image.vue new file mode 100644 index 0000000..b10f477 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-popup-image/s-popup-image.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-richtext-block/s-richtext-block.vue b/yudao-mall-uniapp-master/sheep/components/s-richtext-block/s-richtext-block.vue new file mode 100644 index 0000000..4daa264 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-richtext-block/s-richtext-block.vue @@ -0,0 +1,40 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-search-block/s-search-block.vue b/yudao-mall-uniapp-master/sheep/components/s-search-block/s-search-block.vue new file mode 100644 index 0000000..1e9c2b5 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-search-block/s-search-block.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-seckill-block/s-seckill-block.vue b/yudao-mall-uniapp-master/sheep/components/s-seckill-block/s-seckill-block.vue new file mode 100644 index 0000000..09c2613 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-seckill-block/s-seckill-block.vue @@ -0,0 +1,160 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue b/yudao-mall-uniapp-master/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue new file mode 100644 index 0000000..e2a2950 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue @@ -0,0 +1,472 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue b/yudao-mall-uniapp-master/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue new file mode 100644 index 0000000..1764035 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue @@ -0,0 +1,432 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-select-sku/s-select-sku.vue b/yudao-mall-uniapp-master/sheep/components/s-select-sku/s-select-sku.vue new file mode 100644 index 0000000..b339d4a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-select-sku/s-select-sku.vue @@ -0,0 +1,406 @@ + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/index.vue b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/index.vue new file mode 100644 index 0000000..87ee562 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/index.vue @@ -0,0 +1,168 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/goods.js b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/goods.js new file mode 100644 index 0000000..883e4be --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/goods.js @@ -0,0 +1,125 @@ +import sheep from '@/sheep'; +import { formatImageUrlProtocol, getWxaQrcode } from './index'; + +const goods = async (poster) => { + const width = poster.width; + const userInfo = sheep.$store('user').userInfo; + const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query); + return [ + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.goods_bg)), + css: { + width, + position: 'fixed', + 'object-fit': 'contain', + top: '0', + left: '0', + zIndex: -1, + }, + }, + { + type: 'text', + text: userInfo.nickname, + css: { + color: '#333', + fontSize: 16, + fontFamily: 'sans-serif', + position: 'fixed', + top: width * 0.06, + left: width * 0.22, + }, + }, + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)), + css: { + position: 'fixed', + left: width * 0.04, + top: width * 0.04, + width: width * 0.14, + height: width * 0.14, + }, + }, + { + type: 'image', + src: formatImageUrlProtocol(poster.shareInfo.poster.image), + css: { + position: 'fixed', + left: width * 0.03, + top: width * 0.21, + width: width * 0.94, + height: width * 0.94, + }, + }, + { + type: 'text', + text: poster.shareInfo.poster.title, + css: { + position: 'fixed', + left: width * 0.04, + top: width * 1.18, + color: '#333', + fontSize: 14, + lineHeight: 15, + maxWidth: width * 0.91, + }, + }, + { + type: 'text', + text: '¥' + poster.shareInfo.poster.price, + css: { + position: 'fixed', + left: width * 0.04, + top: width * 1.31, + fontSize: 20, + fontFamily: 'OPPOSANS', + color: '#333', + }, + }, + { + type: 'text', + text: + poster.shareInfo.poster.original_price > 0 + ? '¥' + poster.shareInfo.poster.original_price + : '', + css: { + position: 'fixed', + left: width * 0.3, + top: width * 1.33, + color: '#999', + fontSize: 10, + fontFamily: 'OPPOSANS', + textDecoration: 'line-through', + }, + }, + // #ifndef MP-WEIXIN + { + type: 'qrcode', + text: poster.shareInfo.link, + css: { + position: 'fixed', + left: width * 0.75, + top: width * 1.3, + width: width * 0.2, + height: width * 0.2, + }, + }, + // #endif + // #ifdef MP-WEIXIN + { + type: 'image', + src: wxa_qrcode, + css: { + position: 'fixed', + left: width * 0.75, + top: width * 1.3, + width: width * 0.2, + height: width * 0.2, + }, + }, + // #endif + ]; +}; + +export default goods; diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/groupon.js b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/groupon.js new file mode 100644 index 0000000..d1b6b78 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/groupon.js @@ -0,0 +1,122 @@ +import sheep from '@/sheep'; +import { formatImageUrlProtocol, getWxaQrcode } from './index'; + +const groupon = async (poster) => { + const width = poster.width; + const userInfo = sheep.$store('user').userInfo; + const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query); + return [ + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.groupon_bg)), + css: { + width, + position: 'fixed', + 'object-fit': 'contain', + top: '0', + left: '0', + zIndex: -1, + }, + }, + { + type: 'text', + text: userInfo.nickname, + css: { + color: '#333', + fontSize: 16, + fontFamily: 'sans-serif', + position: 'fixed', + top: width * 0.06, + left: width * 0.22, + }, + }, + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)), + css: { + position: 'fixed', + left: width * 0.04, + top: width * 0.04, + width: width * 0.14, + height: width * 0.14, + }, + }, + { + type: 'image', + src: formatImageUrlProtocol(poster.shareInfo.poster.image), + css: { + position: 'fixed', + left: width * 0.03, + top: width * 0.21, + width: width * 0.94, + height: width * 0.94, + borderRadius: 10, + }, + }, + { + type: 'text', + text: poster.shareInfo.poster.title, + css: { + color: '#333', + fontSize: 14, + position: 'fixed', + top: width * 1.18, + left: width * 0.04, + maxWidth: width * 0.91, + lineHeight: 5, + }, + }, + { + type: 'text', + text: '¥' + poster.shareInfo.poster.price, + css: { + color: '#ff0000', + fontSize: 20, + fontFamily: 'OPPOSANS', + position: 'fixed', + top: width * 1.3, + left: width * 0.04, + }, + }, + { + type: 'text', + text: '2人团', + css: { + color: '#ff0000', + fontSize: 30, + fontFamily: 'OPPOSANS', + position: 'fixed', + left: width * 0.3, + top: width * 1.32, + }, + }, + // #ifndef MP-WEIXIN + { + type: 'qrcode', + text: poster.shareInfo.link, + css: { + position: 'fixed', + left: width * 0.75, + top: width * 1.3, + width: width * 0.2, + height: width * 0.2, + }, + }, + // #endif + // #ifdef MP-WEIXIN + { + type: 'image', + src: wxa_qrcode, + css: { + position: 'fixed', + left: width * 0.75, + top: width * 1.3, + width: width * 0.2, + height: width * 0.2, + }, + }, + // #endif + ]; +}; + +export default groupon; diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/index.js b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/index.js new file mode 100644 index 0000000..55d79c9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/index.js @@ -0,0 +1,39 @@ +import user from './user'; +import goods from './goods'; +import groupon from './groupon'; +import third from '@/sheep/api/migration/third'; + +export function getPosterData(options) { + switch (options.shareInfo.poster.type) { + case 'user': + return user(options); + case 'goods': + return goods(options); + case 'groupon': + return groupon(options); + } +} + +export function formatImageUrlProtocol(url) { + // #ifdef H5 + // H5平台 https协议下需要转换 + if (window.location.protocol === 'https:' && url.indexOf('http:') === 0) { + url = url.replace('http:', 'https:'); + } + // #endif + + // #ifdef MP-WEIXIN + // 小程序平台 需要强制转换为https协议 + if (url.indexOf('http:') === 0) { + url = url.replace('http:', 'https:'); + } + // #endif + + return url; +} + +// 获得微信小程序码 (Base64 image) +export async function getWxaQrcode(path, query) { + const res = await third.wechat.getWxacode(path, query); + return 'data:image/png;base64,' + res.data; +} diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/user.js b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/user.js new file mode 100644 index 0000000..5c4d3b9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/canvas-poster/poster/user.js @@ -0,0 +1,74 @@ +import sheep from '@/sheep'; +import { formatImageUrlProtocol, getWxaQrcode } from './index'; + +const user = async (poster) => { + const width = poster.width; + const userInfo = sheep.$store('user').userInfo; + const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query); + return [ + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.user_bg)), + css: { + width, + position: 'fixed', + 'object-fit': 'contain', + top: '0', + left: '0', + zIndex: -1, + }, + }, + { + type: 'text', + text: userInfo.nickname, + css: { + color: '#333', + fontSize: 14, + textAlign: 'center', + fontFamily: 'sans-serif', + position: 'fixed', + top: width * 0.4, + left: width / 2, + }, + }, + { + type: 'image', + src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)), + css: { + position: 'fixed', + left: width * 0.4, + top: width * 0.16, + width: width * 0.2, + height: width * 0.2, + }, + }, + // #ifndef MP-WEIXIN + { + type: 'qrcode', + text: poster.shareInfo.link, + css: { + position: 'fixed', + left: width * 0.35, + top: width * 0.84, + width: width * 0.3, + height: width * 0.3, + }, + }, + // #endif + // #ifdef MP-WEIXIN + { + type: 'image', + src: wxa_qrcode, + css: { + position: 'fixed', + left: width * 0.35, + top: width * 0.84, + width: width * 0.3, + height: width * 0.3, + }, + }, + // #endif + ]; +}; + +export default user; diff --git a/yudao-mall-uniapp-master/sheep/components/s-share-modal/s-share-modal.vue b/yudao-mall-uniapp-master/sheep/components/s-share-modal/s-share-modal.vue new file mode 100644 index 0000000..717940e --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-share-modal/s-share-modal.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-statusbar/s-statusbar.vue b/yudao-mall-uniapp-master/sheep/components/s-statusbar/s-statusbar.vue new file mode 100644 index 0000000..8b58c97 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-statusbar/s-statusbar.vue @@ -0,0 +1,10 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-tabbar/s-tabbar.vue b/yudao-mall-uniapp-master/sheep/components/s-tabbar/s-tabbar.vue new file mode 100644 index 0000000..369a823 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-tabbar/s-tabbar.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-title-block/s-title-block.vue b/yudao-mall-uniapp-master/sheep/components/s-title-block/s-title-block.vue new file mode 100644 index 0000000..513a3cc --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-title-block/s-title-block.vue @@ -0,0 +1,100 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-uploader/choose-and-upload-file.js b/yudao-mall-uniapp-master/sheep/components/s-uploader/choose-and-upload-file.js new file mode 100644 index 0000000..604ff9d --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-uploader/choose-and-upload-file.js @@ -0,0 +1,213 @@ +'use strict'; +import FileApi from '@/sheep/api/infra/file'; + +const ERR_MSG_OK = 'chooseAndUploadFile:ok'; +const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; + +function chooseImage(opts) { + const { + count, + sizeType = ['original', 'compressed'], + sourceType = ['album', 'camera'], + extension, + } = opts; + return new Promise((resolve, reject) => { + uni.chooseImage({ + count, + sizeType, + sourceType, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function chooseVideo(opts) { + const { camera, compressed, maxDuration, sourceType = ['album', 'camera'], extension } = opts; + return new Promise((resolve, reject) => { + uni.chooseVideo({ + camera, + compressed, + maxDuration, + sourceType, + extension, + success(res) { + const { tempFilePath, duration, size, height, width } = res; + resolve( + normalizeChooseAndUploadFileRes( + { + errMsg: 'chooseVideo:ok', + tempFilePaths: [tempFilePath], + tempFiles: [ + { + name: (res.tempFile && res.tempFile.name) || '', + path: tempFilePath, + size, + type: (res.tempFile && res.tempFile.type) || '', + width, + height, + duration, + fileType: 'video', + cloudPath: '', + }, + ], + }, + 'video', + ), + ); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function chooseAll(opts) { + const { count, extension } = opts; + return new Promise((resolve, reject) => { + let chooseFile = uni.chooseFile; + if (typeof wx !== 'undefined' && typeof wx.chooseMessageFile === 'function') { + chooseFile = wx.chooseMessageFile; + } + if (typeof chooseFile !== 'function') { + return reject({ + errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。', + }); + } + chooseFile({ + type: 'all', + count, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res)); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function normalizeChooseAndUploadFileRes(res, fileType) { + res.tempFiles.forEach((item, index) => { + if (!item.name) { + item.name = item.path.substring(item.path.lastIndexOf('/') + 1); + } + if (fileType) { + item.fileType = fileType; + } + item.cloudPath = Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.')); + }); + if (!res.tempFilePaths) { + res.tempFilePaths = res.tempFiles.map((file) => file.path); + } + return res; +} + +function uploadCloudFiles(files, max = 5, onUploadProgress) { + files = JSON.parse(JSON.stringify(files)); + const len = files.length; + let count = 0; + let self = this; + return new Promise((resolve) => { + while (count < max) { + next(); + } + + function next() { + let cur = count++; + if (cur >= len) { + !files.find((item) => !item.url && !item.errMsg) && resolve(files); + return; + } + const fileItem = files[cur]; + const index = self.files.findIndex((v) => v.uuid === fileItem.uuid); + fileItem.url = ''; + delete fileItem.errMsg; + + uniCloud + .uploadFile({ + filePath: fileItem.path, + cloudPath: fileItem.cloudPath, + fileType: fileItem.fileType, + onUploadProgress: (res) => { + res.index = index; + onUploadProgress && onUploadProgress(res); + }, + }) + .then((res) => { + fileItem.url = res.fileID; + fileItem.index = index; + if (cur < len) { + next(); + } + }) + .catch((res) => { + fileItem.errMsg = res.errMsg || res.message; + fileItem.index = index; + if (cur < len) { + next(); + } + }); + } + }); +} + +function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) { + return choosePromise + .then((res) => { + if (onChooseFile) { + const customChooseRes = onChooseFile(res); + if (typeof customChooseRes !== 'undefined') { + return Promise.resolve(customChooseRes).then((chooseRes) => + typeof chooseRes === 'undefined' ? res : chooseRes, + ); + } + } + return res; + }) + .then((res) => { + if (res === false) { + return { + errMsg: ERR_MSG_OK, + tempFilePaths: [], + tempFiles: [], + }; + } + return res; + }) + .then(async (files) => { + for (let file of files.tempFiles) { + const { data } = await FileApi.uploadFile(file.path); + file.url = data; + } + return files; + }); +} + +function chooseAndUploadFile( + opts = { + type: 'all', + }, +) { + if (opts.type === 'image') { + return uploadFiles(chooseImage(opts), opts); + } else if (opts.type === 'video') { + return uploadFiles(chooseVideo(opts), opts); + } + return uploadFiles(chooseAll(opts), opts); +} + +export { chooseAndUploadFile, uploadCloudFiles }; diff --git a/yudao-mall-uniapp-master/sheep/components/s-uploader/s-uploader.vue b/yudao-mall-uniapp-master/sheep/components/s-uploader/s-uploader.vue new file mode 100644 index 0000000..95cfb05 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-uploader/s-uploader.vue @@ -0,0 +1,675 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-file.vue b/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-file.vue new file mode 100644 index 0000000..233d281 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-file.vue @@ -0,0 +1,335 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-image.vue b/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-image.vue new file mode 100644 index 0000000..b66956a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-uploader/upload-image.vue @@ -0,0 +1,306 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-uploader/utils.js b/yudao-mall-uniapp-master/sheep/components/s-uploader/utils.js new file mode 100644 index 0000000..c1e8073 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-uploader/utils.js @@ -0,0 +1,110 @@ +/** + * 获取文件名和后缀 + * @param {String} name + */ +export const get_file_ext = (name) => { + const last_len = name.lastIndexOf('.'); + const len = name.length; + return { + name: name.substring(0, last_len), + ext: name.substring(last_len + 1, len), + }; +}; + +/** + * 获取扩展名 + * @param {Array} fileExtname + */ +export const get_extname = (fileExtname) => { + if (!Array.isArray(fileExtname)) { + let extname = fileExtname.replace(/(\[|\])/g, ''); + return extname.split(','); + } else { + return fileExtname; + } + return []; +}; + +/** + * 获取文件和检测是否可选 + */ +export const get_files_and_is_max = (res, _extname) => { + let filePaths = []; + let files = []; + if (!_extname || _extname.length === 0) { + return { + filePaths, + files, + }; + } + res.tempFiles.forEach((v) => { + let fileFullName = get_file_ext(v.name); + const extname = fileFullName.ext.toLowerCase(); + if (_extname.indexOf(extname) !== -1) { + files.push(v); + filePaths.push(v.path); + } + }); + if (files.length !== res.tempFiles.length) { + uni.showToast({ + title: `当前选择了${res.tempFiles.length}个文件 ,${ + res.tempFiles.length - files.length + } 个文件格式不正确`, + icon: 'none', + duration: 5000, + }); + } + + return { + filePaths, + files, + }; +}; + +/** + * 获取图片信息 + * @param {Object} filepath + */ +export const get_file_info = (filepath) => { + return new Promise((resolve, reject) => { + uni.getImageInfo({ + src: filepath, + success(res) { + resolve(res); + }, + fail(err) { + reject(err); + }, + }); + }); +}; +/** + * 获取封装数据 + */ +export const get_file_data = async (files, type = 'image') => { + // 最终需要上传数据库的数据 + let fileFullName = get_file_ext(files.name); + const extname = fileFullName.ext.toLowerCase(); + let filedata = { + name: files.name, + uuid: files.uuid, + extname: extname || '', + cloudPath: files.cloudPath, + fileType: files.fileType, + url: files.path || files.path, + size: files.size, //单位是字节 + image: {}, + path: files.path, + video: {}, + }; + if (type === 'image') { + const imageinfo = await get_file_info(files.path); + delete filedata.video; + filedata.image.width = imageinfo.width; + filedata.image.height = imageinfo.height; + filedata.image.location = imageinfo.path; + } else { + delete filedata.image; + } + return filedata; +}; diff --git a/yudao-mall-uniapp-master/sheep/components/s-user-card/s-user-card.vue b/yudao-mall-uniapp-master/sheep/components/s-user-card/s-user-card.vue new file mode 100644 index 0000000..d234098 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-user-card/s-user-card.vue @@ -0,0 +1,167 @@ + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/components/s-video-block/s-video-block.vue b/yudao-mall-uniapp-master/sheep/components/s-video-block/s-video-block.vue new file mode 100644 index 0000000..38e5b84 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-video-block/s-video-block.vue @@ -0,0 +1,32 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/components/s-wallet-card/s-wallet-card.vue b/yudao-mall-uniapp-master/sheep/components/s-wallet-card/s-wallet-card.vue new file mode 100644 index 0000000..54348e9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/components/s-wallet-card/s-wallet-card.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/config/index.js b/yudao-mall-uniapp-master/sheep/config/index.js new file mode 100644 index 0000000..209a9dc --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/config/index.js @@ -0,0 +1,19 @@ +// 开发环境配置 +export let baseUrl; +export let version; +if (process.env.NODE_ENV === 'development') { + baseUrl = import.meta.env.SHOPRO_DEV_BASE_URL; +} else { + baseUrl = import.meta.env.SHOPRO_BASE_URL; +} +version = import.meta.env.SHOPRO_VERSION; +console.log(`[芋道商城 ${version}] http://doc.iocoder.cn`); + +export const apiPath = import.meta.env.SHOPRO_API_PATH; +export const staticUrl = import.meta.env.SHOPRO_STATIC_URL; + +export default { + baseUrl, + apiPath, + staticUrl, +}; diff --git a/yudao-mall-uniapp-master/sheep/config/zIndex.js b/yudao-mall-uniapp-master/sheep/config/zIndex.js new file mode 100644 index 0000000..6652d48 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/config/zIndex.js @@ -0,0 +1,20 @@ +// uniapp在H5中各API的z-index值如下: +/** + * actionsheet: 999 + * modal: 999 + * navigate: 998 + * tabbar: 998 + * toast: 999 + */ + +export default { + toast: 10090, + noNetwork: 10080, + popup: 10075, // popup包含popup,actionsheet,keyboard,picker的值 + mask: 10070, + navbar: 980, + topTips: 975, + sticky: 970, + indexListSticky: 965, + popover: 960, +}; diff --git a/yudao-mall-uniapp-master/sheep/helper/digit.js b/yudao-mall-uniapp-master/sheep/helper/digit.js new file mode 100644 index 0000000..be50b32 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/digit.js @@ -0,0 +1,168 @@ +let _boundaryCheckingState = true; // 是否进行越界检查的全局开关 + +/** + * 把错误的数据转正 + * @private + * @example strip(0.09999999999999998)=0.1 + */ +function strip(num, precision = 15) { + return +parseFloat(Number(num).toPrecision(precision)); +} + +/** + * Return digits length of a number + * @private + * @param {*number} num Input number + */ +function digitLength(num) { + // Get digit length of e + const eSplit = num.toString().split(/[eE]/); + const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0); + return len > 0 ? len : 0; +} + +/** + * 把小数转成整数,如果是小数则放大成整数 + * @private + * @param {*number} num 输入数 + */ +function float2Fixed(num) { + if (num.toString().indexOf('e') === -1) { + return Number(num.toString().replace('.', '')); + } + const dLen = digitLength(num); + return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num); +} + +/** + * 检测数字是否越界,如果越界给出提示 + * @private + * @param {*number} num 输入数 + */ +function checkBoundary(num) { + if (_boundaryCheckingState) { + if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) { + console.warn(`${num} 超出了精度限制,结果可能不正确`); + } + } +} + +/** + * 把递归操作扁平迭代化 + * @param {number[]} arr 要操作的数字数组 + * @param {function} operation 迭代操作 + * @private + */ +function iteratorOperation(arr, operation) { + const [num1, num2, ...others] = arr; + let res = operation(num1, num2); + + others.forEach((num) => { + res = operation(res, num); + }); + + return res; +} + +/** + * 高精度乘法 + * @export + */ +export function times(...nums) { + if (nums.length > 2) { + return iteratorOperation(nums, times); + } + + const [num1, num2] = nums; + const num1Changed = float2Fixed(num1); + const num2Changed = float2Fixed(num2); + const baseNum = digitLength(num1) + digitLength(num2); + const leftValue = num1Changed * num2Changed; + + checkBoundary(leftValue); + + return leftValue / Math.pow(10, baseNum); +} + +/** + * 高精度加法 + * @export + */ +export function plus(...nums) { + if (nums.length > 2) { + return iteratorOperation(nums, plus); + } + + const [num1, num2] = nums; + // 取最大的小数位 + const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2))); + // 把小数都转为整数然后再计算 + return (times(num1, baseNum) + times(num2, baseNum)) / baseNum; +} + +/** + * 高精度减法 + * @export + */ +export function minus(...nums) { + if (nums.length > 2) { + return iteratorOperation(nums, minus); + } + + const [num1, num2] = nums; + const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2))); + return (times(num1, baseNum) - times(num2, baseNum)) / baseNum; +} + +/** + * 高精度除法 + * @export + */ +export function divide(...nums) { + if (nums.length > 2) { + return iteratorOperation(nums, divide); + } + + const [num1, num2] = nums; + const num1Changed = float2Fixed(num1); + const num2Changed = float2Fixed(num2); + checkBoundary(num1Changed); + checkBoundary(num2Changed); + // 重要,这里必须用strip进行修正 + return times( + num1Changed / num2Changed, + strip(Math.pow(10, digitLength(num2) - digitLength(num1))), + ); +} + +/** + * 四舍五入 + * @export + */ +export function round(num, ratio) { + const base = Math.pow(10, ratio); + let result = divide(Math.round(Math.abs(times(num, base))), base); + if (num < 0 && result !== 0) { + result = times(result, -1); + } + // 位数不足则补0 + return result; +} + +/** + * 是否进行边界检查,默认开启 + * @param flag 标记开关,true 为开启,false 为关闭,默认为 true + * @export + */ +export function enableBoundaryChecking(flag = true) { + _boundaryCheckingState = flag; +} + +export default { + times, + plus, + minus, + divide, + round, + enableBoundaryChecking, +}; diff --git a/yudao-mall-uniapp-master/sheep/helper/index.js b/yudao-mall-uniapp-master/sheep/helper/index.js new file mode 100644 index 0000000..38e6afe --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/index.js @@ -0,0 +1,708 @@ +import test from './test.js'; +import { round } from './digit.js'; +/** + * @description 如果value小于min,取min;如果value大于max,取max + * @param {number} min + * @param {number} max + * @param {number} value + */ +function range(min = 0, max = 0, value = 0) { + return Math.max(min, Math.min(max, Number(value))); +} + +/** + * @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.upx2px进行转换 + * @param {number|string} value 用户传递值的px值 + * @param {boolean} unit + * @returns {number|string} + */ +export function getPx(value, unit = false) { + if (test.number(value)) { + return unit ? `${value}px` : Number(value); + } + // 如果带有rpx,先取出其数值部分,再转为px值 + if (/(rpx|upx)$/.test(value)) { + return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value))); + } + return unit ? `${parseInt(value)}px` : parseInt(value); +} + +/** + * @description 进行延时,以达到可以简写代码的目的 + * @param {number} value 堵塞时间 单位ms 毫秒 + * @returns {Promise} 返回promise + */ +export function sleep(value = 30) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, value); + }); +} +/** + * @description 运行期判断平台 + * @returns {string} 返回所在平台(小写) + * @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台 + */ +export function os() { + return uni.getSystemInfoSync().platform.toLowerCase(); +} +/** + * @description 获取系统信息同步接口 + * @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync + */ +export function sys() { + return uni.getSystemInfoSync(); +} + +/** + * @description 取一个区间数 + * @param {Number} min 最小值 + * @param {Number} max 最大值 + */ +function random(min, max) { + if (min >= 0 && max > 0 && max >= min) { + const gab = max - min + 1; + return Math.floor(Math.random() * gab + min); + } + return 0; +} + +/** + * @param {Number} len uuid的长度 + * @param {Boolean} firstU 将返回的首字母置为"u" + * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制 + */ +export function guid(len = 32, firstU = true, radix = null) { + const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + const uuid = []; + radix = radix || chars.length; + + if (len) { + // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位 + for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]; + } else { + let r; + // rfc4122标准要求返回的uuid中,某些位为固定的字符 + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + for (let i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | (Math.random() * 16); + uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r]; + } + } + } + // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class + if (firstU) { + uuid.shift(); + return `u${uuid.join('')}`; + } + return uuid.join(''); +} + +/** +* @description 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法 + this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx + 这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name + 值(默认为undefined),就是查找最顶层的$parent +* @param {string|undefined} name 父组件的参数名 +*/ +export function $parent(name = undefined) { + let parent = this.$parent; + // 通过while历遍,这里主要是为了H5需要多层解析的问题 + while (parent) { + // 父组件 + if (parent.$options && parent.$options.name !== name) { + // 如果组件的name不相等,继续上一级寻找 + parent = parent.$parent; + } else { + return parent; + } + } + return false; +} + +/** + * @description 样式转换 + * 对象转字符串,或者字符串转对象 + * @param {object | string} customStyle 需要转换的目标 + * @param {String} target 转换的目的,object-转为对象,string-转为字符串 + * @returns {object|string} + */ +export function addStyle(customStyle, target = 'object') { + // 字符串转字符串,对象转对象情形,直接返回 + if ( + test.empty(customStyle) || + (typeof customStyle === 'object' && target === 'object') || + (target === 'string' && typeof customStyle === 'string') + ) { + return customStyle; + } + // 字符串转对象 + if (target === 'object') { + // 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的 + customStyle = trim(customStyle); + // 根据";"将字符串转为数组形式 + const styleArray = customStyle.split(';'); + const style = {}; + // 历遍数组,拼接成对象 + for (let i = 0; i < styleArray.length; i++) { + // 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤 + if (styleArray[i]) { + const item = styleArray[i].split(':'); + style[trim(item[0])] = trim(item[1]); + } + } + return style; + } + // 这里为对象转字符串形式 + let string = ''; + for (const i in customStyle) { + // 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名 + const key = i.replace(/([A-Z])/g, '-$1').toLowerCase(); + string += `${key}:${customStyle[i]};`; + } + // 去除两端空格 + return trim(string); +} + +/** + * @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾 + * @param {string|number} value 需要添加单位的值 + * @param {string} unit 添加的单位名 比如px + */ +export function addUnit(value = 'auto', unit = 'px') { + value = String(value); + return test.number(value) ? `${value}${unit}` : value; +} + +/** + * @description 深度克隆 + * @param {object} obj 需要深度克隆的对象 + * @returns {*} 克隆后的对象或者原值(不是对象) + */ +function deepClone(obj) { + // 对常见的“非”值,直接返回原来值 + if ([null, undefined, NaN, false].includes(obj)) return obj; + if (typeof obj !== 'object' && typeof obj !== 'function') { + // 原始类型直接返回 + return obj; + } + const o = test.array(obj) ? [] : {}; + for (const i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]; + } + } + return o; +} + +/** + * @description JS对象深度合并 + * @param {object} target 需要拷贝的对象 + * @param {object} source 拷贝的来源对象 + * @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象) + */ +export function deepMerge(target = {}, source = {}) { + target = deepClone(target); + if (typeof target !== 'object' || typeof source !== 'object') return false; + for (const prop in source) { + if (!source.hasOwnProperty(prop)) continue; + if (prop in target) { + if (typeof target[prop] !== 'object') { + target[prop] = source[prop]; + } else if (typeof source[prop] !== 'object') { + target[prop] = source[prop]; + } else if (target[prop].concat && source[prop].concat) { + target[prop] = target[prop].concat(source[prop]); + } else { + target[prop] = deepMerge(target[prop], source[prop]); + } + } else { + target[prop] = source[prop]; + } + } + return target; +} + +/** + * @description error提示 + * @param {*} err 错误内容 + */ +function error(err) { + // 开发环境才提示,生产环境不会提示 + if (process.env.NODE_ENV === 'development') { + console.error(`SheepJS:${err}`); + } +} + +/** + * @description 打乱数组 + * @param {array} array 需要打乱的数组 + * @returns {array} 打乱后的数组 + */ +function randomArray(array = []) { + // 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0 + return array.sort(() => Math.random() - 0.5); +} + +// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序 +// 所以这里做一个兼容polyfill的兼容处理 +if (!String.prototype.padStart) { + // 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解 + String.prototype.padStart = function (maxLength, fillString = ' ') { + if (Object.prototype.toString.call(fillString) !== '[object String]') { + throw new TypeError('fillString must be String'); + } + const str = this; + // 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉 + if (str.length >= maxLength) return String(str); + + const fillLength = maxLength - str.length; + let times = Math.ceil(fillLength / fillString.length); + while ((times >>= 1)) { + fillString += fillString; + if (times === 1) { + fillString += fillString; + } + } + return fillString.slice(0, fillLength) + str; + }; +} + +/** + * @description 格式化时间 + * @param {String|Number} dateTime 需要格式化的时间戳 + * @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd + * @returns {string} 返回格式化后的字符串 + */ +function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') { + let date; + // 若传入时间为假值,则取当前时间 + if (!dateTime) { + date = new Date(); + } + // 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容) + else if (/^\d{10}$/.test(dateTime?.toString().trim())) { + date = new Date(dateTime * 1000); + } + // 若用户传入字符串格式时间戳,new Date无法解析,需做兼容 + else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) { + date = new Date(Number(dateTime)); + } + // 其他都认为符合 RFC 2822 规范 + else { + // 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间 + date = new Date(typeof dateTime === 'string' ? dateTime.replace(/-/g, '/') : dateTime); + } + + const timeSource = { + y: date.getFullYear().toString(), // 年 + m: (date.getMonth() + 1).toString().padStart(2, '0'), // 月 + d: date.getDate().toString().padStart(2, '0'), // 日 + h: date.getHours().toString().padStart(2, '0'), // 时 + M: date.getMinutes().toString().padStart(2, '0'), // 分 + s: date.getSeconds().toString().padStart(2, '0'), // 秒 + // 有其他格式化字符需求可以继续添加,必须转化成字符串 + }; + + for (const key in timeSource) { + const [ret] = new RegExp(`${key}+`).exec(formatStr) || []; + if (ret) { + // 年可能只需展示两位 + const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0; + formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex)); + } + } + + return formatStr; +} + +/** + * @description 时间戳转为多久之前 + * @param {String|Number} timestamp 时间戳 + * @param {String|Boolean} format + * 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式; + * 如果为布尔值false,无论什么时间,都返回多久以前的格式 + * @returns {string} 转化后的内容 + */ +function timeFrom(timestamp = null, format = 'yyyy-mm-dd') { + if (timestamp == null) timestamp = Number(new Date()); + timestamp = parseInt(timestamp); + // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位) + if (timestamp.toString().length == 10) timestamp *= 1000; + let timer = new Date().getTime() - timestamp; + timer = parseInt(timer / 1000); + // 如果小于5分钟,则返回"刚刚",其他以此类推 + let tips = ''; + switch (true) { + case timer < 300: + tips = '刚刚'; + break; + case timer >= 300 && timer < 3600: + tips = `${parseInt(timer / 60)}分钟前`; + break; + case timer >= 3600 && timer < 86400: + tips = `${parseInt(timer / 3600)}小时前`; + break; + case timer >= 86400 && timer < 2592000: + tips = `${parseInt(timer / 86400)}天前`; + break; + default: + // 如果format为false,则无论什么时间戳,都显示xx之前 + if (format === false) { + if (timer >= 2592000 && timer < 365 * 86400) { + tips = `${parseInt(timer / (86400 * 30))}个月前`; + } else { + tips = `${parseInt(timer / (86400 * 365))}年前`; + } + } else { + tips = timeFormat(timestamp, format); + } + } + return tips; +} + +/** + * @description 去除空格 + * @param String str 需要去除空格的字符串 + * @param String pos both(左右)|left|right|all 默认both + */ +function trim(str, pos = 'both') { + str = String(str); + if (pos == 'both') { + return str.replace(/^\s+|\s+$/g, ''); + } + if (pos == 'left') { + return str.replace(/^\s*/, ''); + } + if (pos == 'right') { + return str.replace(/(\s*$)/g, ''); + } + if (pos == 'all') { + return str.replace(/\s+/g, ''); + } + return str; +} + +/** + * @description 对象转url参数 + * @param {object} data,对象 + * @param {Boolean} isPrefix,是否自动加上"?" + * @param {string} arrayFormat 规则 indices|brackets|repeat|comma + */ +function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') { + const prefix = isPrefix ? '?' : ''; + const _result = []; + if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) + arrayFormat = 'brackets'; + for (const key in data) { + const value = data[key]; + // 去掉为空的参数 + if (['', undefined, null].indexOf(value) >= 0) { + continue; + } + // 如果值为数组,另行处理 + if (value.constructor === Array) { + // e.g. {ids: [1, 2, 3]} + switch (arrayFormat) { + case 'indices': + // 结果: ids[0]=1&ids[1]=2&ids[2]=3 + for (let i = 0; i < value.length; i++) { + _result.push(`${key}[${i}]=${value[i]}`); + } + break; + case 'brackets': + // 结果: ids[]=1&ids[]=2&ids[]=3 + value.forEach((_value) => { + _result.push(`${key}[]=${_value}`); + }); + break; + case 'repeat': + // 结果: ids=1&ids=2&ids=3 + value.forEach((_value) => { + _result.push(`${key}=${_value}`); + }); + break; + case 'comma': + // 结果: ids=1,2,3 + let commaStr = ''; + value.forEach((_value) => { + commaStr += (commaStr ? ',' : '') + _value; + }); + _result.push(`${key}=${commaStr}`); + break; + default: + value.forEach((_value) => { + _result.push(`${key}[]=${_value}`); + }); + } + } else { + _result.push(`${key}=${value}`); + } + } + return _result.length ? prefix + _result.join('&') : ''; +} + +/** + * 显示消息提示框 + * @param {String} title 提示的内容,长度与 icon 取值有关。 + * @param {Number} duration 提示的延迟时间,单位毫秒,默认:2000 + */ +function toast(title, duration = 2000) { + uni.showToast({ + title: String(title), + icon: 'none', + duration, + }); +} + +/** + * @description 根据主题type值,获取对应的图标 + * @param {String} type 主题名称,primary|info|error|warning|success + * @param {boolean} fill 是否使用fill填充实体的图标 + */ +function type2icon(type = 'success', fill = false) { + // 如果非预置值,默认为success + if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'; + let iconName = ''; + // 目前(2019-12-12),info和primary使用同一个图标 + switch (type) { + case 'primary': + iconName = 'info-circle'; + break; + case 'info': + iconName = 'info-circle'; + break; + case 'error': + iconName = 'close-circle'; + break; + case 'warning': + iconName = 'error-circle'; + break; + case 'success': + iconName = 'checkmark-circle'; + break; + default: + iconName = 'checkmark-circle'; + } + // 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的 + if (fill) iconName += '-fill'; + return iconName; +} + +/** + * @description 数字格式化 + * @param {number|string} number 要格式化的数字 + * @param {number} decimals 保留几位小数 + * @param {string} decimalPoint 小数点符号 + * @param {string} thousandsSeparator 千分位符号 + * @returns {string} 格式化后的数字 + */ +function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') { + number = `${number}`.replace(/[^0-9+-Ee.]/g, ''); + const n = !isFinite(+number) ? 0 : +number; + const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals); + const sep = typeof thousandsSeparator === 'undefined' ? ',' : thousandsSeparator; + const dec = typeof decimalPoint === 'undefined' ? '.' : decimalPoint; + let s = ''; + + s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.'); + const re = /(-?\d+)(\d{3})/; + while (re.test(s[0])) { + s[0] = s[0].replace(re, `$1${sep}$2`); + } + + if ((s[1] || '').length < prec) { + s[1] = s[1] || ''; + s[1] += new Array(prec - s[1].length + 1).join('0'); + } + return s.join(dec); +} + +/** + * @description 获取duration值 + * 如果带有ms或者s直接返回,如果大于一定值,认为是ms单位,小于一定值,认为是s单位 + * 比如以30位阈值,那么300大于30,可以理解为用户想要的是300ms,而不是想花300s去执行一个动画 + * @param {String|number} value 比如: "1s"|"100ms"|1|100 + * @param {boolean} unit 提示: 如果是false 默认返回number + * @return {string|number} + */ +function getDuration(value, unit = true) { + const valueNum = parseInt(value); + if (unit) { + if (/s$/.test(value)) return value; + return value > 30 ? `${value}ms` : `${value}s`; + } + if (/ms$/.test(value)) return valueNum; + if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000; + return valueNum; +} + +/** + * @description 日期的月或日补零操作 + * @param {String} value 需要补零的值 + */ +function padZero(value) { + return `00${value}`.slice(-2); +} + +/** + * @description 获取某个对象下的属性,用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式 + * @param {object} obj 对象 + * @param {string} key 需要获取的属性字段 + * @returns {*} + */ +function getProperty(obj, key) { + if (!obj) { + return; + } + if (typeof key !== 'string' || key === '') { + return ''; + } + if (key.indexOf('.') !== -1) { + const keys = key.split('.'); + let firstObj = obj[keys[0]] || {}; + + for (let i = 1; i < keys.length; i++) { + if (firstObj) { + firstObj = firstObj[keys[i]]; + } + } + return firstObj; + } + return obj[key]; +} + +/** + * @description 设置对象的属性值,如果'a.b.c'的形式进行设置 + * @param {object} obj 对象 + * @param {string} key 需要设置的属性 + * @param {string} value 设置的值 + */ +function setProperty(obj, key, value) { + if (!obj) { + return; + } + // 递归赋值 + const inFn = function (_obj, keys, v) { + // 最后一个属性key + if (keys.length === 1) { + _obj[keys[0]] = v; + return; + } + // 0~length-1个key + while (keys.length > 1) { + const k = keys[0]; + if (!_obj[k] || typeof _obj[k] !== 'object') { + _obj[k] = {}; + } + const key = keys.shift(); + // 自调用判断是否存在属性,不存在则自动创建对象 + inFn(_obj[k], keys, v); + } + }; + + if (typeof key !== 'string' || key === '') { + } else if (key.indexOf('.') !== -1) { + // 支持多层级赋值操作 + const keys = key.split('.'); + inFn(obj, keys, value); + } else { + obj[key] = value; + } +} + +/** + * @description 获取当前页面路径 + */ +function page() { + const pages = getCurrentPages(); + // 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组 + return `/${pages[pages.length - 1]?.route ?? ''}`; +} + +/** + * @description 获取当前路由栈实例数组 + */ +function pages() { + const pages = getCurrentPages(); + return pages; +} + +/** + * 获取H5-真实根地址 兼容hash+history模式 + */ +export function getRootUrl() { + let url = ''; + // #ifdef H5 + url = location.origin + '/'; + + if (location.hash !== '') { + url += '#/'; + } + // #endif + return url; +} + +/** + * copyText 多端复制文本 + */ +export function copyText(text) { + // #ifndef H5 + uni.setClipboardData({ + data: text, + success: function () { + toast('复制成功!'); + }, + fail: function () { + toast('复制失败!'); + }, + }); + // #endif + // #ifdef H5 + var createInput = document.createElement('textarea'); + createInput.value = text; + document.body.appendChild(createInput); + createInput.select(); + document.execCommand('Copy'); + createInput.className = 'createInput'; + createInput.style.display = 'none'; + toast('复制成功'); + // #endif +} + +export default { + range, + getPx, + sleep, + os, + sys, + random, + guid, + $parent, + addStyle, + addUnit, + deepClone, + deepMerge, + error, + randomArray, + timeFormat, + timeFrom, + trim, + queryParams, + toast, + type2icon, + priceFormat, + getDuration, + padZero, + getProperty, + setProperty, + page, + pages, + test, + getRootUrl, + copyText, +}; diff --git a/yudao-mall-uniapp-master/sheep/helper/test.js b/yudao-mall-uniapp-master/sheep/helper/test.js new file mode 100644 index 0000000..ca550a1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/test.js @@ -0,0 +1,285 @@ +/** + * 验证电子邮箱格式 + */ +function email(value) { + return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value); +} + +/** + * 验证手机格式 + */ +function mobile(value) { + return /^1[23456789]\d{9}$/.test(value); +} + +/** + * 验证URL格式 + */ +function url(value) { + return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/.test( + value, + ); +} + +/** + * 验证日期格式 + */ +function date(value) { + if (!value) return false; + // 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳 + if (number(value)) value = +value; + return !/Invalid|NaN/.test(new Date(value).toString()); +} + +/** + * 验证ISO类型的日期格式 + */ +function dateISO(value) { + return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value); +} + +/** + * 验证十进制数字 + */ +function number(value) { + return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value); +} + +/** + * 验证字符串 + */ +function string(value) { + return typeof value === 'string'; +} + +/** + * 验证整数 + */ +function digits(value) { + return /^\d+$/.test(value); +} + +/** + * 验证身份证号码 + */ +function idCard(value) { + return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value); +} + +/** + * 是否车牌号 + */ +function carNo(value) { + // 新能源车牌 + const xreg = + /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/; + // 旧车牌 + const creg = + /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/; + if (value.length === 7) { + return creg.test(value); + } + if (value.length === 8) { + return xreg.test(value); + } + return false; +} + +/** + * 金额,只允许2位小数 + */ +function amount(value) { + // 金额,只允许保留两位小数 + return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value); +} + +/** + * 中文 + */ +function chinese(value) { + const reg = /^[\u4e00-\u9fa5]+$/gi; + return reg.test(value); +} + +/** + * 只能输入字母 + */ +function letter(value) { + return /^[a-zA-Z]*$/.test(value); +} + +/** + * 只能是字母或者数字 + */ +function enOrNum(value) { + // 英文或者数字 + const reg = /^[0-9a-zA-Z]*$/g; + return reg.test(value); +} + +/** + * 验证是否包含某个值 + */ +function contains(value, param) { + return value.indexOf(param) >= 0; +} + +/** + * 验证一个值范围[min, max] + */ +function range(value, param) { + return value >= param[0] && value <= param[1]; +} + +/** + * 验证一个长度范围[min, max] + */ +function rangeLength(value, param) { + return value.length >= param[0] && value.length <= param[1]; +} + +/** + * 是否固定电话 + */ +function landline(value) { + const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/; + return reg.test(value); +} + +/** + * 判断是否为空 + */ +function empty(value) { + switch (typeof value) { + case 'undefined': + return true; + case 'string': + if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true; + break; + case 'boolean': + if (!value) return true; + break; + case 'number': + if (value === 0 || isNaN(value)) return true; + break; + case 'object': + if (value === null || value.length === 0) return true; + for (const i in value) { + return false; + } + return true; + } + return false; +} + +/** + * 是否json字符串 + */ +function jsonString(value) { + if (typeof value === 'string') { + try { + const obj = JSON.parse(value); + if (typeof obj === 'object' && obj) { + return true; + } + return false; + } catch (e) { + return false; + } + } + return false; +} + +/** + * 是否数组 + */ +function array(value) { + if (typeof Array.isArray === 'function') { + return Array.isArray(value); + } + return Object.prototype.toString.call(value) === '[object Array]'; +} + +/** + * 是否对象 + */ +function object(value) { + return Object.prototype.toString.call(value) === '[object Object]'; +} + +/** + * 是否短信验证码 + */ +function code(value, len = 6) { + return new RegExp(`^\\d{${len}}$`).test(value); +} + +/** + * 是否函数方法 + * @param {Object} value + */ +function func(value) { + return typeof value === 'function'; +} + +/** + * 是否promise对象 + * @param {Object} value + */ +function promise(value) { + return object(value) && func(value.then) && func(value.catch); +} + +/** 是否图片格式 + * @param {Object} value + */ +function image(value) { + const newValue = value.split('?')[0]; + const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i; + return IMAGE_REGEXP.test(newValue); +} + +/** + * 是否视频格式 + * @param {Object} value + */ +function video(value) { + const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i; + return VIDEO_REGEXP.test(value); +} + +/** + * 是否为正则对象 + * @param {Object} + * @return {Boolean} + */ +function regExp(o) { + return o && Object.prototype.toString.call(o) === '[object RegExp]'; +} + +export default { + email, + mobile, + url, + date, + dateISO, + number, + digits, + idCard, + carNo, + amount, + chinese, + letter, + enOrNum, + contains, + range, + rangeLength, + empty, + isEmpty: empty, + isNumber: number, + jsonString, + landline, + object, + array, + code, +}; diff --git a/yudao-mall-uniapp-master/sheep/helper/throttle.js b/yudao-mall-uniapp-master/sheep/helper/throttle.js new file mode 100644 index 0000000..c318127 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/throttle.js @@ -0,0 +1,31 @@ +let timer; +let flag; +/** + * 节流原理:在一定时间内,只能触发一次 + * + * @param {Function} func 要执行的回调函数 + * @param {Number} wait 延时的时间 + * @param {Boolean} immediate 是否立即执行 + * @return null + */ +function throttle(func, wait = 500, immediate = true) { + if (immediate) { + if (!flag) { + flag = true; + // 如果是立即执行,则在wait毫秒内开始时执行 + typeof func === 'function' && func(); + timer = setTimeout(() => { + flag = false; + }, wait); + } else { + } + } else if (!flag) { + flag = true; + // 如果是非立即执行,则在wait毫秒内的结束处执行 + timer = setTimeout(() => { + flag = false; + typeof func === 'function' && func(); + }, wait); + } +} +export default throttle; diff --git a/yudao-mall-uniapp-master/sheep/helper/tools.js b/yudao-mall-uniapp-master/sheep/helper/tools.js new file mode 100644 index 0000000..49efcec --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/tools.js @@ -0,0 +1,67 @@ +import router from '@/sheep/router'; +export default { + /** + * 打电话 + * @param {String} phoneNumber - 数字字符串 + */ + callPhone(phoneNumber = '') { + let num = phoneNumber.toString(); + uni.makePhoneCall({ + phoneNumber: num, + fail(err) { + console.log('makePhoneCall出错', err); + }, + }); + }, + + /** + * 微信头像 + * @param {String} url -图片地址 + */ + checkMPUrl(url) { + // #ifdef MP + if ( + url.substring(0, 4) === 'http' && + url.substring(0, 5) !== 'https' && + url.substring(0, 12) !== 'http://store' && + url.substring(0, 10) !== 'http://tmp' && + url.substring(0, 10) !== 'http://usr' + ) { + url = 'https' + url.substring(4, url.length); + } + // #endif + return url; + }, + + /** + * getUuid 生成唯一id + */ + getUuid(len = 32, firstU = true, radix = null) { + const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + const uuid = []; + radix = radix || chars.length; + + if (len) { + // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位 + for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]; + } else { + let r; + // rfc4122标准要求返回的uuid中,某些位为固定的字符 + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + + for (let i = 0; i < 36; i++) { + if (!uuid[i]) { + r = 0 | (Math.random() * 16); + uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r]; + } + } + } + // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class + if (firstU) { + uuid.shift(); + return `u${uuid.join('')}`; + } + return uuid.join(''); + }, +}; diff --git a/yudao-mall-uniapp-master/sheep/helper/utils.js b/yudao-mall-uniapp-master/sheep/helper/utils.js new file mode 100644 index 0000000..bcb5d25 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/helper/utils.js @@ -0,0 +1,168 @@ +export function isArray(value) { + if (typeof Array.isArray === 'function') { + return Array.isArray(value); + } else { + return Object.prototype.toString.call(value) === '[object Array]'; + } +} + +export function isObject(value) { + return Object.prototype.toString.call(value) === '[object Object]'; +} + +export function isNumber(value) { + return !isNaN(Number(value)); +} + +export function isFunction(value) { + return typeof value == 'function'; +} + +export function isString(value) { + return typeof value == 'string'; +} + +export function isEmpty(value) { + if (isArray(value)) { + return value.length === 0; + } + + if (isObject(value)) { + return Object.keys(value).length === 0; + } + + return value === '' || value === undefined || value === null; +} + +export function isBoolean(value) { + return typeof value === 'boolean'; +} + +export function last(data) { + if (isArray(data) || isString(data)) { + return data[data.length - 1]; + } +} + +export function cloneDeep(obj) { + const d = isArray(obj) ? obj : {}; + + if (isObject(obj)) { + for (const key in obj) { + if (obj[key]) { + if (obj[key] && typeof obj[key] === 'object') { + d[key] = cloneDeep(obj[key]); + } else { + d[key] = obj[key]; + } + } + } + } + + return d; +} + +export function clone(obj) { + return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); +} + +export function deepMerge(a, b) { + let k; + for (k in b) { + a[k] = a[k] && a[k].toString() === '[object Object]' ? deepMerge(a[k], b[k]) : (a[k] = b[k]); + } + return a; +} + +export function contains(parent, node) { + while (node && (node = node.parentNode)) if (node === parent) return true; + return false; +} + +export function orderBy(list, key) { + return list.sort((a, b) => a[key] - b[key]); +} + +export function deepTree(list) { + const newList = []; + const map = {}; + + list.forEach((e) => (map[e.id] = e)); + + list.forEach((e) => { + const parent = map[e.parentId]; + + if (parent) { + (parent.children || (parent.children = [])).push(e); + } else { + newList.push(e); + } + }); + + const fn = (list) => { + list.map((e) => { + if (e.children instanceof Array) { + e.children = orderBy(e.children, 'orderNum'); + + fn(e.children); + } + }); + }; + + fn(newList); + + return orderBy(newList, 'orderNum'); +} + +export function revDeepTree(list = []) { + const d = []; + let id = 0; + + const deep = (list, parentId) => { + list.forEach((e) => { + if (!e.id) { + e.id = id++; + } + + e.parentId = parentId; + + d.push(e); + + if (e.children && isArray(e.children)) { + deep(e.children, e.id); + } + }); + }; + + deep(list || [], null); + + return d; +} + +export function basename(path) { + let index = path.lastIndexOf('/'); + index = index > -1 ? index : path.lastIndexOf('\\'); + if (index < 0) { + return path; + } + return path.substring(index + 1); +} + +export function isWxBrowser() { + const ua = navigator.userAgent.toLowerCase(); + if (ua.match(/MicroMessenger/i) == 'micromessenger') { + return true; + } else { + return false; + } +} + +/** + * @description 如果value小于min,取min;如果value大于max,取max + * @param {number} min + * @param {number} max + * @param {number} value + */ +export function range(min = 0, max = 0, value = 0) { + return Math.max(min, Math.min(max, Number(value))); +} diff --git a/yudao-mall-uniapp-master/sheep/hooks/useApp.js b/yudao-mall-uniapp-master/sheep/hooks/useApp.js new file mode 100644 index 0000000..e69de29 diff --git a/yudao-mall-uniapp-master/sheep/hooks/useGoods.js b/yudao-mall-uniapp-master/sheep/hooks/useGoods.js new file mode 100644 index 0000000..5627447 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/hooks/useGoods.js @@ -0,0 +1,389 @@ +import { ref } from 'vue'; +import dayjs from 'dayjs'; +import $url from '@/sheep/url'; +import { formatDate } from '@/sheep/util'; + +/** + * 格式化销量 + * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量 + * @param {number} num 销量 + * @return {string} 格式化后的销量字符串 + */ +export function formatSales(type, num) { + let prefix = type !== 'exact' && num < 10 ? '销量' : '已售'; + return formatNum(prefix, type, num) +} + +/** + * 格式化兑换量 + * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量 + * @param {number} num 销量 + * @return {string} 格式化后的销量字符串 + */ +export function formatExchange(type, num) { + return formatNum('已兑换', type, num) +} + + +/** + * 格式化库存 + * @param {'exact' | any} type 格式类型:exact=精确值,其它=大致数量 + * @param {number} num 销量 + * @return {string} 格式化后的销量字符串 + */ +export function formatStock(type, num) { + return formatNum('库存', type, num) +} + +/** + * 格式化数字 + * @param {string} prefix 前缀 + * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量 + * @param {number} num 销量 + * @return {string} 格式化后的销量字符串 + */ +export function formatNum(prefix, type, num) { + num = (num || 0); + // 情况一:精确数值 + if (type === 'exact') { + return prefix + num; + } + // 情况二:小于等于 10 + if (num < 10) { + return `${prefix}≤10`; + } + // 情况三:大于 10,除第一位外,其它位都显示为0 + // 例如:100 - 199 显示为 100+ + // 9000 - 9999 显示为 9000+ + const numStr = num.toString(); + const first = numStr[0]; + const other = '0'.repeat(numStr.length - 1); + return `${prefix}${first}${other}+`; +} + +// 格式化价格 +export function formatPrice(e) { + return e.length === 1 ? e[0] : e.join('~'); +} + +// 视频格式后缀列表 +const VIDEO_SUFFIX_LIST = ['.avi', '.mp4'] + +/** + * 转换商品轮播的链接列表:根据链接的后缀,判断是视频链接还是图片链接 + * + * @param {string[]} urlList 链接列表 + * @return {{src: string, type: 'video' | 'image' }[]} 转换后的链接列表 + */ +export function formatGoodsSwiper(urlList) { + return urlList?.filter(url => url).map((url, key) => { + const isVideo = VIDEO_SUFFIX_LIST.some(suffix => url.includes(suffix)); + const type = isVideo ? 'video' : 'image' + const src = $url.cdn(url); + return { type, src } + }) || []; +} + +/** + * 格式化订单状态的颜色 + * + * @param order 订单 + * @return {string} 颜色的 class 名称 + */ +export function formatOrderColor(order) { + if (order.status === 0) { + return 'info-color'; + } + if (order.status === 10 + || order.status === 20 + || (order.status === 30 && !order.commentStatus)) { + return 'warning-color'; + } + if (order.status === 30 && order.commentStatus) { + return 'success-color'; + } + return 'danger-color'; +} + +/** + * 格式化订单状态 + * + * @param order 订单 + */ +export function formatOrderStatus(order) { + if (order.status === 0) { + return '待付款'; + } + if (order.status === 10 && order.deliveryType === 1) { + return '待发货'; + } + if (order.status === 10 && order.deliveryType === 2) { + return '待核销'; + } + if (order.status === 20) { + return '待收货'; + } + if (order.status === 30 && !order.commentStatus) { + return '待评价'; + } + if (order.status === 30 && order.commentStatus) { + return '已完成'; + } + return '已关闭'; +} + +/** + * 格式化订单状态的描述 + * + * @param order 订单 + */ +export function formatOrderStatusDescription(order) { + if (order.status === 0) { + return `请在 ${ formatDate(order.payExpireTime) } 前完成支付`; + } + if (order.status === 10) { + return '商家未发货,请耐心等待'; + } + if (order.status === 20) { + return '商家已发货,请耐心等待'; + } + if (order.status === 30 && !order.commentStatus) { + return '已收货,快去评价一下吧'; + } + if (order.status === 30 && order.commentStatus) { + return '交易完成,感谢您的支持'; + } + return '交易关闭'; +} + +/** + * 处理订单的 button 操作按钮数组 + * + * @param order 订单 + */ +export function handleOrderButtons(order) { + order.buttons = [] + if (order.type === 3) { // 查看拼团 + order.buttons.push('combination'); + } + if (order.status === 20) { // 确认收货 + order.buttons.push('confirm'); + } + if (order.logisticsId > 0) { // 查看物流 + order.buttons.push('express'); + } + if (order.status === 0) { // 取消订单 / 发起支付 + order.buttons.push('cancel'); + order.buttons.push('pay'); + } + if (order.status === 30 && !order.commentStatus) { // 发起评价 + order.buttons.push('comment'); + } + if (order.status === 40) { // 删除订单 + order.buttons.push('delete'); + } +} + +/** + * 格式化售后状态 + * + * @param afterSale 售后 + */ +export function formatAfterSaleStatus(afterSale) { + if (afterSale.status === 10) { + return '申请售后'; + } + if (afterSale.status === 20) { + return '商品待退货'; + } + if (afterSale.status === 30) { + return '商家待收货'; + } + if (afterSale.status === 40) { + return '等待退款'; + } + if (afterSale.status === 50) { + return '退款成功'; + } + if (afterSale.status === 61) { + return '买家取消'; + } + if (afterSale.status === 62) { + return '商家拒绝'; + } + if (afterSale.status === 63) { + return '商家拒收货'; + } + return '未知状态'; +} + +/** + * 格式化售后状态的描述 + * + * @param afterSale 售后 + */ +export function formatAfterSaleStatusDescription(afterSale) { + if (afterSale.status === 10) { + return '退款申请待商家处理'; + } + if (afterSale.status === 20) { + return '请退货并填写物流信息'; + } + if (afterSale.status === 30) { + return '退货退款申请待商家处理'; + } + if (afterSale.status === 40) { + return '等待退款'; + } + if (afterSale.status === 50) { + return '退款成功'; + } + if (afterSale.status === 61) { + return '退款关闭'; + } + if (afterSale.status === 62) { + return `商家不同意退款申请,拒绝原因:${afterSale.auditReason}`; + } + if (afterSale.status === 63) { + return `商家拒绝收货,不同意退款,拒绝原因:${afterSale.auditReason}`; + } + return '未知状态'; +} + +/** + * 处理售后的 button 操作按钮数组 + * + * @param afterSale 售后 + */ +export function handleAfterSaleButtons(afterSale) { + afterSale.buttons = []; + if ([10, 20, 30].includes(afterSale.status)) { // 取消订单 + afterSale.buttons.push('cancel'); + } + if (afterSale.status === 20) { // 退货信息 + afterSale.buttons.push('delivery'); + } +} + +/** + * 倒计时 + * @param toTime 截止时间 + * @param fromTime 起始时间,默认当前时间 + * @return {{s: string, ms: number, h: string, m: string}} 持续时间 + */ +export function useDurationTime(toTime, fromTime = '') { + toTime = getDayjsTime(toTime); + if (fromTime === '') { + fromTime = dayjs(); + } + let duration = ref(toTime - fromTime); + if (duration.value > 0) { + setTimeout(() => { + if (duration.value > 0) { + duration.value -= 1000; + } + }, 1000); + } + + let durationTime = dayjs.duration(duration.value); + return { + h: (durationTime.months() * 30 * 24 + durationTime.days() * 24 + durationTime.hours()) + .toString() + .padStart(2, '0'), + m: durationTime.minutes().toString().padStart(2, '0'), + s: durationTime.seconds().toString().padStart(2, '0'), + ms: durationTime.$ms, + }; +} + +/** + * 转换为 Dayjs + * @param {any} time 时间 + * @return {dayjs.Dayjs} + */ +function getDayjsTime(time) { + time = time.toString(); + if (time.indexOf('-') > 0) { + // 'date' + return dayjs(time); + } + if (time.length > 10) { + // 'timestamp' + return dayjs(parseInt(time)); + } + if (time.length === 10) { + // 'unixTime' + return dayjs.unix(parseInt(time)); + } +} + +/** + * 将分转成元 + * + * @param price 分,例如说 100 分 + * @returns {string} 元,例如说 1.00 元 + */ +export function fen2yuan(price) { + return (price / 100.0).toFixed(2) +} + +/** + * 从商品 SKU 数组中,转换出商品属性的数组 + * + * 类似结构:[{ + * id: // 属性的编号 + * name: // 属性的名字 + * values: [{ + * id: // 属性值的编号 + * name: // 属性值的名字 + * }] + * }] + * + * @param skus 商品 SKU 数组 + */ +export function convertProductPropertyList(skus) { + let result = []; + for (const sku of skus) { + if (!sku.properties) { + continue + } + for (const property of sku.properties) { + // ① 先处理属性 + let resultProperty = result.find(item => item.id === property.propertyId) + if (!resultProperty) { + resultProperty = { + id: property.propertyId, + name: property.propertyName, + values: [] + } + result.push(resultProperty) + } + // ② 再处理属性值 + let resultValue = resultProperty.values.find(item => item.id === property.valueId) + if (!resultValue) { + resultProperty.values.push({ + id: property.valueId, + name: property.valueName + }) + } + } + } + return result; +} + +/** + * 格式化满减送活动的规则 + * + * @param activity 活动信息 + * @param rule 优惠规格 + * @returns {string} 规格字符串 + */ +export function formatRewardActivityRule(activity, rule) { + if (activity.conditionType === 10) { + return `满 ${fen2yuan(rule.limit)} 元减 ${fen2yuan(rule.discountPrice)} 元`; + } + if (activity.conditionType === 20) { + return `满 ${rule.limit} 件减 ${fen2yuan(rule.discountPrice)} 元`; + } + return ''; +} diff --git a/yudao-mall-uniapp-master/sheep/hooks/useModal.js b/yudao-mall-uniapp-master/sheep/hooks/useModal.js new file mode 100644 index 0000000..e9d5b94 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/hooks/useModal.js @@ -0,0 +1,140 @@ +import $store from '@/sheep/store'; +import $helper from '@/sheep/helper'; +import dayjs from 'dayjs'; +import { ref } from 'vue'; +import test from '@/sheep/helper/test.js'; +import AuthUtil from '@/sheep/api/member/auth'; + +// 打开授权弹框 +export function showAuthModal(type = 'smsLogin') { + const modal = $store('modal'); + if (modal.auth !== '') { + closeAuthModal(); + setTimeout(() => { + modal.$patch((state) => { + state.auth = type; + }); + }, 100); + } else { + modal.$patch((state) => { + state.auth = type; + }); + } +} + +// 关闭授权弹框 +export function closeAuthModal() { + $store('modal').$patch((state) => { + state.auth = ''; + }); +} + +// 打开分享弹框 +export function showShareModal() { + $store('modal').$patch((state) => { + state.share = true; + }); +} + +// 关闭分享弹框 +export function closeShareModal() { + $store('modal').$patch((state) => { + state.share = false; + }); +} + +// 打开快捷菜单 +export function showMenuTools() { + $store('modal').$patch((state) => { + state.menu = true; + }); +} + +// 关闭快捷菜单 +export function closeMenuTools() { + $store('modal').$patch((state) => { + state.menu = false; + }); +} + +// 发送短信验证码 60秒 +export function getSmsCode(event, mobile) { + const modalStore = $store('modal'); + const lastSendTimer = modalStore.lastTimer[event]; + if (typeof lastSendTimer === 'undefined') { + $helper.toast('短信发送事件错误'); + return; + } + + const duration = dayjs().unix() - lastSendTimer; + const canSend = duration >= 60; + if (!canSend) { + $helper.toast('请稍后再试'); + return; + } + // 只有 mobile 非空时才校验。因为部分场景(修改密码),不需要输入手机 + if (mobile && !test.mobile(mobile)) { + $helper.toast('手机号码格式不正确'); + return; + } + + // 发送验证码 + 更新上次发送验证码时间 + let scene = -1; + switch (event) { + case 'resetPassword': + scene = 4; + break; + case 'changePassword': + scene = 3; + break; + case 'changeMobile': + scene = 2; + break; + case 'smsLogin': + scene = 1; + break; + } + AuthUtil.sendSmsCode(mobile, scene).then((res) => { + if (res.code === 0) { + modalStore.$patch((state) => { + state.lastTimer[event] = dayjs().unix(); + }); + } + }); +} + +// 获取短信验证码倒计时 -- 60秒 +export function getSmsTimer(event, mobile = '') { + const modalStore = $store('modal'); + const lastSendTimer = modalStore.lastTimer[event]; + + if (typeof lastSendTimer === 'undefined') { + $helper.toast('短信发送事件错误'); + return; + } + + const duration = ref(dayjs().unix() - lastSendTimer - 60); + const canSend = duration.value >= 0; + + if (canSend) { + return '获取验证码'; + } + + if (!canSend) { + setTimeout(() => { + duration.value++; + }, 1000); + return -duration.value.toString() + ' 秒'; + } +} + +// 记录广告弹框历史 +export function saveAdvHistory(adv) { + const modal = $store('modal'); + + modal.$patch((state) => { + if (!state.advHistory.includes(adv.imgUrl)) { + state.advHistory.push(adv.imgUrl); + } + }); +} diff --git a/yudao-mall-uniapp-master/sheep/index.js b/yudao-mall-uniapp-master/sheep/index.js new file mode 100644 index 0000000..9af8f08 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/index.js @@ -0,0 +1,52 @@ +import $url from '@/sheep/url'; +import $router from '@/sheep/router'; +import $platform from '@/sheep/platform'; +import $helper from '@/sheep/helper'; +import zIndex from '@/sheep/config/zIndex.js'; +import $store from '@/sheep/store'; +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; +import duration from 'dayjs/plugin/duration'; +import 'dayjs/locale/zh-cn'; + +dayjs.locale('zh-cn'); +dayjs.extend(relativeTime); +dayjs.extend(duration); + +const sheep = { + $store, + $url, + $router, + $platform, + $helper, + $zIndex: zIndex, +}; + +// 加载Shopro底层依赖 +export async function ShoproInit() { + // 应用初始化 + await $store('app').init(); + + // 平台初始化加载(各平台provider提供不同的加载流程) + $platform.load(); + + if (process.env.NODE_ENV === 'development') { + ShoproDebug(); + } +} + +// 开发模式 +function ShoproDebug() { + // 开发环境引入vconsole调试 + // #ifdef H5 + // import("vconsole").then(vconsole => { + // new vconsole.default(); + // }); + // #endif + + // TODO 芋艿:可以打印路由 + // 同步前端页面到后端 + // console.log(ROUTES) +} + +export default sheep; diff --git a/yudao-mall-uniapp-master/sheep/libs/mplive-manifest-plugin.js b/yudao-mall-uniapp-master/sheep/libs/mplive-manifest-plugin.js new file mode 100644 index 0000000..d1df9bf --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/libs/mplive-manifest-plugin.js @@ -0,0 +1,32 @@ +const fs = require('fs'); + +const manifestPath = process.env.UNI_INPUT_DIR + '/manifest.json'; + +let Manifest = fs.readFileSync(manifestPath, { + encoding: 'utf-8' +}); + +function mpliveMainfestPlugin(isOpen) { + if (process.env.UNI_PLATFORM !== 'mp-weixin') return; + + const manifestData = JSON.parse(Manifest) + + if (isOpen === '0') { + delete manifestData['mp-weixin'].plugins['live-player-plugin']; + } + + if (isOpen === '1') { + manifestData['mp-weixin'].plugins['live-player-plugin'] = { + "version": "1.3.5", + "provider": "wx2b03c6e691cd7370" + } + } + + Manifest = JSON.stringify(manifestData, null, 2) + + fs.writeFileSync(manifestPath, Manifest, { + "flag": "w" + }) +} + +export default mpliveMainfestPlugin diff --git a/yudao-mall-uniapp-master/sheep/libs/permission.js b/yudao-mall-uniapp-master/sheep/libs/permission.js new file mode 100644 index 0000000..59f9413 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/libs/permission.js @@ -0,0 +1,246 @@ +/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启 + +var isIOS; + +function album() { + var result = 0; + var PHPhotoLibrary = plus.ios.import('PHPhotoLibrary'); + var authStatus = PHPhotoLibrary.authorizationStatus(); + if (authStatus === 0) { + result = null; + } else if (authStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(PHPhotoLibrary); + return result; +} + +function camera() { + var result = 0; + var AVCaptureDevice = plus.ios.import('AVCaptureDevice'); + var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); + if (authStatus === 0) { + result = null; + } else if (authStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(AVCaptureDevice); + return result; +} + +function location() { + var result = 0; + var cllocationManger = plus.ios.import('CLLocationManager'); + var enable = cllocationManger.locationServicesEnabled(); + var status = cllocationManger.authorizationStatus(); + if (!enable) { + result = 2; + } else if (status === 0) { + result = null; + } else if (status === 3 || status === 4) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(cllocationManger); + return result; +} + +function push() { + var result = 0; + var UIApplication = plus.ios.import('UIApplication'); + var app = UIApplication.sharedApplication(); + var enabledTypes = 0; + if (app.currentUserNotificationSettings) { + var settings = app.currentUserNotificationSettings(); + enabledTypes = settings.plusGetAttribute('types'); + if (enabledTypes == 0) { + result = 0; + console.log('推送权限没有开启'); + } else { + result = 1; + console.log('已经开启推送功能!'); + } + plus.ios.deleteObject(settings); + } else { + enabledTypes = app.enabledRemoteNotificationTypes(); + if (enabledTypes == 0) { + result = 3; + console.log('推送权限没有开启!'); + } else { + result = 4; + console.log('已经开启推送功能!'); + } + } + plus.ios.deleteObject(app); + plus.ios.deleteObject(UIApplication); + return result; +} + +function contact() { + var result = 0; + var CNContactStore = plus.ios.import('CNContactStore'); + var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0); + if (cnAuthStatus === 0) { + result = null; + } else if (cnAuthStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(CNContactStore); + return result; +} + +function record() { + var result = null; + var avaudiosession = plus.ios.import('AVAudioSession'); + var avaudio = avaudiosession.sharedInstance(); + var status = avaudio.recordPermission(); + console.log('permissionStatus:' + status); + if (status === 1970168948) { + result = null; + } else if (status === 1735552628) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(avaudiosession); + return result; +} + +function calendar() { + var result = null; + var EKEventStore = plus.ios.import('EKEventStore'); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0); + if (ekAuthStatus == 3) { + result = 1; + console.log('日历权限已经开启'); + } else { + console.log('日历权限没有开启'); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + +function memo() { + var result = null; + var EKEventStore = plus.ios.import('EKEventStore'); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1); + if (ekAuthStatus == 3) { + result = 1; + console.log('备忘录权限已经开启'); + } else { + console.log('备忘录权限没有开启'); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + +function requestIOS(permissionID) { + return new Promise((resolve, reject) => { + switch (permissionID) { + case 'push': + resolve(push()); + break; + case 'location': + resolve(location()); + break; + case 'record': + resolve(record()); + break; + case 'camera': + resolve(camera()); + break; + case 'album': + resolve(album()); + break; + case 'contact': + resolve(contact()); + break; + case 'calendar': + resolve(calendar()); + break; + case 'memo': + resolve(memo()); + break; + default: + resolve(0); + break; + } + }); +} + +function requestAndroid(permissionID) { + return new Promise((resolve, reject) => { + plus.android.requestPermissions( + [permissionID], + function (resultObj) { + var result = 0; + for (var i = 0; i < resultObj.granted.length; i++) { + var grantedPermission = resultObj.granted[i]; + console.log('已获取的权限:' + grantedPermission); + result = 1; + } + for (var i = 0; i < resultObj.deniedPresent.length; i++) { + var deniedPresentPermission = resultObj.deniedPresent[i]; + console.log('拒绝本次申请的权限:' + deniedPresentPermission); + result = 0; + } + for (var i = 0; i < resultObj.deniedAlways.length; i++) { + var deniedAlwaysPermission = resultObj.deniedAlways[i]; + console.log('永久拒绝申请的权限:' + deniedAlwaysPermission); + result = -1; + } + resolve(result); + }, + function (error) { + console.log('result error: ' + error.message); + resolve({ + code: error.code, + message: error.message, + }); + }, + ); + }); +} + +function gotoAppPermissionSetting() { + if (permission.isIOS) { + var UIApplication = plus.ios.import('UIApplication'); + var application2 = UIApplication.sharedApplication(); + var NSURL2 = plus.ios.import('NSURL'); + var setting2 = NSURL2.URLWithString('app-settings:'); + application2.openURL(setting2); + plus.ios.deleteObject(setting2); + plus.ios.deleteObject(NSURL2); + plus.ios.deleteObject(application2); + } else { + var Intent = plus.android.importClass('android.content.Intent'); + var Settings = plus.android.importClass('android.provider.Settings'); + var Uri = plus.android.importClass('android.net.Uri'); + var mainActivity = plus.android.runtimeMainActivity(); + var intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + var uri = Uri.fromParts('package', mainActivity.getPackageName(), null); + intent.setData(uri); + mainActivity.startActivity(intent); + } +} + +const permission = { + get isIOS() { + return typeof isIOS === 'boolean' + ? isIOS + : (isIOS = uni.getSystemInfoSync().platform === 'ios'); + }, + requestIOS: requestIOS, + requestAndroid: requestAndroid, + gotoAppSetting: gotoAppPermissionSetting, +}; + +export default permission; diff --git a/yudao-mall-uniapp-master/sheep/libs/sdk-h5-weixin.js b/yudao-mall-uniapp-master/sheep/libs/sdk-h5-weixin.js new file mode 100644 index 0000000..a71b951 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/libs/sdk-h5-weixin.js @@ -0,0 +1,182 @@ +/** + * 本模块封装微信浏览器下的一些方法。 + * 更多微信网页开发sdk方法,详见:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html + */ + +import jweixin, { ready } from 'weixin-js-sdk'; +import $helper from '@/sheep/helper'; +import AuthUtil from '@/sheep/api/member/auth'; + +let configSuccess = false; + +export default { + // 判断是否在微信中 + isWechat() { + const ua = window.navigator.userAgent.toLowerCase(); + // noinspection EqualityComparisonWithCoercionJS + return ua.match(/micromessenger/i) == 'micromessenger'; + }, + + isReady(api) { + jweixin.ready(api); + }, + + // 初始化 JSSDK + async init(callback) { + if (!this.isWechat()) { + $helper.toast('请使用微信网页浏览器打开'); + return; + } + + // 调用后端接口,获得 JSSDK 初始化所需的签名 + const url = location.href.split('#')[0]; + const { code, data } = await AuthUtil.createWeixinMpJsapiSignature(url); + if (code === 0) { + jweixin.config({ + debug: false, + appId: data.appId, + timestamp: data.timestamp, + nonceStr: data.nonceStr, + signature: data.signature, + jsApiList: ['chooseWXPay'], // TODO 芋艿:后续可以设置更多权限; + openTagList: data.openTagList + }); + } + + // 监听结果 + configSuccess = true; + jweixin.error((err) => { + configSuccess = false; + console.error('微信 JSSDK 初始化失败', err); + // $helper.toast('微信JSSDK:' + err.errMsg); + }); + jweixin.ready(() => { + if (configSuccess) { + console.log('微信 JSSDK 初始化成功'); + } + }) + + // 回调 + if (callback) { + callback(data); + } + }, + + //在需要定位页面调用 TODO 芋艿:未测试 + getLocation(callback) { + this.isReady(() => { + jweixin.getLocation({ + type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' + success: function (res) { + callback(res); + }, + fail: function (res) { + console.log('%c微信H5sdk,getLocation失败:', 'color:green;background:yellow'); + }, + }); + }); + }, + + //获取微信收货地址 TODO 芋艿:未测试 + openAddress(callback) { + this.isReady(() => { + jweixin.openAddress({ + success: function (res) { + callback.success && callback.success(res); + }, + fail: function (err) { + callback.error && callback.error(err); + console.log('%c微信H5sdk,openAddress失败:', 'color:green;background:yellow'); + }, + complete: function (res) {}, + }); + }); + }, + + // 微信扫码 TODO 芋艿:未测试 + scanQRCode(callback) { + this.isReady(() => { + jweixin.scanQRCode({ + needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果, + scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有 + success: function (res) { + callback(res); + }, + fail: function (res) { + console.log('%c微信H5sdk,scanQRCode失败:', 'color:green;background:yellow'); + }, + }); + }); + }, + + // 更新微信分享信息 TODO 芋艿:未测试 + updateShareInfo(data, callback = null) { + this.isReady(() => { + const shareData = { + title: data.title, + desc: data.desc, + link: data.link, + imgUrl: data.image, + success: function (res) { + if (callback) { + callback(res); + } + // 分享后的一些操作,比如分享统计等等 + }, + cancel: function (res) {}, + }; + + // 新版 分享聊天api + jweixin.updateAppMessageShareData(shareData); + // 新版 分享到朋友圈api + jweixin.updateTimelineShareData(shareData); + }); + }, + + // 打开坐标位置 TODO 芋艿:未测试 + openLocation(data, callback) { + this.isReady(() => { + jweixin.openLocation({ + //根据传入的坐标打开地图 + latitude: data.latitude, + longitude: data.longitude, + }); + }); + }, + + // 选择图片 TODO 芋艿:未测试 + chooseImage(callback) { + this.isReady(() => { + jweixin.chooseImage({ + count: 1, + sizeType: ['compressed'], + sourceType: ['album'], + success: function (rs) { + callback(rs); + }, + }); + }); + }, + + // 微信支付 + wxpay(data, callback) { + this.isReady(() => { + jweixin.chooseWXPay({ + timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 + nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位 + package: data.packageValue, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*) + signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' + paySign: data.paySign, // 支付签名 + success: function (res) { + callback.success && callback.success(res); + }, + fail: function (err) { + callback.fail && callback.fail(err); + }, + cancel: function (err) { + callback.cancel && callback.cancel(err); + }, + }); + }); + }, +}; diff --git a/yudao-mall-uniapp-master/sheep/platform/index.js b/yudao-mall-uniapp-master/sheep/platform/index.js new file mode 100644 index 0000000..36a54fc --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/index.js @@ -0,0 +1,175 @@ +/** + * Shopro 第三方平台功能聚合 + * @version 1.0.3 + * @author lidongtony + * @param {String} name - 厂商+平台名称 + * @param {String} provider - 厂商 + * @param {String} platform - 平台名称 + * @param {String} os - 系统型号 + * @param {Object} device - 设备信息 + */ + +import { isEmpty } from 'lodash'; +// #ifdef H5 +import { isWxBrowser } from '@/sheep/helper/utils'; +// #endif +import wechat from './provider/wechat/index.js'; +import apple from './provider/apple'; +import share from './share'; +import Pay from './pay'; + +const device = uni.getSystemInfoSync(); + +const os = device.platform; + +let name = ''; +let provider = ''; +let platform = ''; +let isWechatInstalled = true; + +// #ifdef H5 +if (isWxBrowser()) { + name = 'WechatOfficialAccount'; + provider = 'wechat'; + platform = 'officialAccount'; +} else { + name = 'H5'; + platform = 'h5'; +} +// #endif + +// #ifdef APP-PLUS +name = 'App'; +platform = 'openPlatform'; +// 检查微信客户端是否安装,否则AppleStore会因此拒绝上架 +if (os === 'ios') { + isWechatInstalled = plus.ios.import('WXApi').isWXAppInstalled(); +} +// #endif + +// #ifdef MP-WEIXIN +name = 'WechatMiniProgram'; +platform = 'miniProgram'; +provider = 'wechat'; +// #endif + +if (isEmpty(name)) { + uni.showToast({ + title: '暂不支持该平台', + icon: 'none', + }); +} + +// 加载当前平台前置行为 +const load = () => { + if (provider === 'wechat') { + wechat.load(); + } +}; + +// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple' +const useProvider = (_provider = '') => { + if (_provider === '') _provider = provider; + if (_provider === 'wechat') return wechat; + if (_provider === 'apple') return apple; +}; + +// 支付服务转发 +const pay = (payment, orderType, orderSN) => { + return new Pay(payment, orderType, orderSN); +}; + +/** + * 检查更新 (只检查小程序和App) + * @param {Boolean} silence - 静默检查 + */ +const checkUpdate = (silence = false) => { + let canUpdate; + // #ifdef MP-WEIXIN + useProvider().checkUpdate(silence); + // #endif + + // #ifdef APP-PLUS + // TODO: 热更新 + // #endif +}; + +/** + * 检查网络 + * @param {Boolean} silence - 静默检查 + */ +async function checkNetwork() { + const networkStatus = await uni.getNetworkType(); + if (networkStatus.networkType == 'none') { + return Promise.resolve(false); + } + return Promise.resolve(true); +} + +// 获取小程序胶囊信息 +const getCapsule = () => { + // #ifdef MP + let capsule = uni.getMenuButtonBoundingClientRect(); + if (!capsule) { + capsule = { + bottom: 56, + height: 32, + left: 278, + right: 365, + top: 24, + width: 87, + }; + } + return capsule; + // #endif + + // #ifndef MP + return { + bottom: 56, + height: 32, + left: 278, + right: 365, + top: 24, + width: 87, + }; + // #endif +}; + +const capsule = getCapsule(); + +// 标题栏高度 +const getNavBar = () => { + return device.statusBarHeight + 44; +}; +const navbar = getNavBar(); + +function getLandingPage() { + let page = ''; + // #ifdef H5 + page = location.href.split('?')[0]; + // #endif + return page; +} + +// 设置ios+公众号网页落地页 解决微信sdk签名问题 +const landingPage = getLandingPage(); + +const _platform = { + name, + device, + os, + provider, + platform, + useProvider, + checkUpdate, + checkNetwork, + pay, + share, + load, + capsule, + navbar, + landingPage, + isWechatInstalled, +}; + +export default _platform; diff --git a/yudao-mall-uniapp-master/sheep/platform/pay.js b/yudao-mall-uniapp-master/sheep/platform/pay.js new file mode 100644 index 0000000..447b64a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/pay.js @@ -0,0 +1,351 @@ +import sheep from '@/sheep'; +// #ifdef H5 +import $wxsdk from '@/sheep/libs/sdk-h5-weixin'; +// #endif +import { getRootUrl } from '@/sheep/helper'; +import PayOrderApi from '@/sheep/api/pay/order'; + +/** + * 支付 + * + * @param {String} payment = ['wechat','alipay','wallet','mock'] - 支付方式 + * @param {String} orderType = ['goods','recharge','groupon'] - 订单类型 + * @param {String} id - 订单号 + */ + +export default class SheepPay { + constructor(payment, orderType, id) { + this.payment = payment; + this.id = id; + this.orderType = orderType; + this.payAction(); + } + + payAction() { + const payAction = { + WechatOfficialAccount: { + wechat: () => { + this.wechatOfficialAccountPay(); + }, + alipay: () => { + this.redirectPay(); // 现在公众号可以直接跳转支付宝页面 + }, + wallet: () => { + this.walletPay(); + }, + mock: () => { + this.mockPay(); + } + }, + WechatMiniProgram: { + wechat: () => { + this.wechatMiniProgramPay(); + }, + alipay: () => { + this.copyPayLink(); + }, + wallet: () => { + this.walletPay(); + }, + mock: () => { + this.mockPay(); + } + }, + App: { + wechat: () => { + this.wechatAppPay(); + }, + alipay: () => { + this.alipay(); + }, + wallet: () => { + this.walletPay(); + }, + mock: () => { + this.mockPay(); + } + }, + H5: { + wechat: () => { + this.wechatWapPay(); + }, + alipay: () => { + this.redirectPay(); + }, + wallet: () => { + this.walletPay(); + }, + mock: () => { + this.mockPay(); + } + }, + }; + return payAction[sheep.$platform.name][this.payment](); + } + + // 预支付 + prepay(channel) { + return new Promise(async (resolve, reject) => { + let data = { + id: this.id, + channelCode: channel, + channelExtras: {} + }; + // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid + if (['wx_pub', 'wx_lite'].includes(channel)) { + const openid = await sheep.$platform.useProvider('wechat').getOpenid(); + // 如果获取不到 openid,微信无法发起支付,此时需要引导 + if (!openid) { + this.bindWeixin(); + return; + } + data.channelExtras.openid = openid; + } + // 发起预支付 API 调用 + PayOrderApi.submitOrder(data).then((res) => { + // 成功时 + res.code === 0 && resolve(res); + // 失败时 + if (res.code !== 0 && res.msg.indexOf('无效的openid') >= 0) { + // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid 不正确的情况 + if (res.msg.indexOf('无效的openid') >= 0 // 获取的 openid 不正确时,或者随便输入了个 openid + || res.msg.indexOf('下单账号与支付账号不一致') >= 0) { // https://developers.weixin.qq.com/community/develop/doc/00008c53c347804beec82aed051c00 + this.bindWeixin(); + } + } + }); + }); + } + // #ifdef H5 + // 微信公众号 JSSDK 支付 + async wechatOfficialAccountPay() { + let { code, data } = await this.prepay('wx_pub'); + if (code !== 0) { + return; + } + const payConfig = JSON.parse(data.displayContent); + $wxsdk.wxpay(payConfig, { + success: () => { + this.payResult('success'); + }, + cancel: () => { + sheep.$helper.toast('支付已手动取消'); + }, + fail: (error) => { + if (error.errMsg.indexOf('chooseWXPay:没有此SDK或暂不支持此SDK模拟') >= 0) { + sheep.$helper.toast('发起微信支付失败,原因:可能是微信开发者工具不支持,建议使用微信打开网页后支付'); + return + } + this.payResult('fail'); + }, + }); + } + + // 浏览器微信 H5 支付 TODO 芋艿:待接入 + async wechatWapPay() { + const { error, data } = await this.prepay(); + if (error === 0) { + const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`; + location.href = `${data.pay_data.h5_url}&redirect_url=${encodeURIComponent(redirect_url)}`; + } + } + + // 支付链接 TODO 芋艿:待接入 + async redirectPay() { + let { error, data } = await this.prepay(); + if (error === 0) { + const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`; + location.href = data.pay_data + encodeURIComponent(redirect_url); + } + } + + // #endif + + // 微信小程序支付 + async wechatMiniProgramPay() { + // let that = this; + let { code, data } = await this.prepay('wx_lite'); + if (code !== 0) { + return; + } + // 调用微信小程序支付 + const payConfig = JSON.parse(data.displayContent); + uni.requestPayment({ + provider: 'wxpay', + timeStamp: payConfig.timeStamp, + nonceStr: payConfig.nonceStr, + package: payConfig.packageValue, + signType: payConfig.signType, + paySign: payConfig.paySign, + success: (res) => { + this.payResult('success'); + }, + fail: (err) => { + if (err.errMsg === 'requestPayment:fail cancel') { + sheep.$helper.toast('支付已手动取消'); + } else { + this.payResult('fail'); + } + }, + }); + } + + // 余额支付 + async walletPay() { + const { code } = await this.prepay('wallet'); + code === 0 && this.payResult('success'); + } + + // 模拟支付 + async mockPay() { + const { code } = await this.prepay('mock'); + code === 0 && this.payResult('success'); + } + + // 支付宝复制链接支付 TODO 芋艿:待接入 + async copyPayLink() { + let that = this; + let { error, data } = await this.prepay(); + if (error === 0) { + // 引入showModal 点击确认 复制链接; + uni.showModal({ + title: '支付宝支付', + content: '复制链接到外部浏览器', + confirmText: '复制链接', + success: (res) => { + if (res.confirm) { + sheep.$helper.copyText(data.pay_data); + } + }, + }); + } + } + + // 支付宝支付 TODO 芋艿:待接入 + async alipay() { + let that = this; + const { error, data } = await this.prepay(); + if (error === 0) { + uni.requestPayment({ + provider: 'alipay', + orderInfo: data.pay_data, //支付宝订单数据 + success: (res) => { + that.payResult('success'); + }, + fail: (err) => { + if (err.errMsg === 'requestPayment:fail [paymentAlipay:62001]user cancel') { + sheep.$helper.toast('支付已手动取消'); + } else { + that.payResult('fail'); + } + }, + }); + } + } + + // 微信支付 TODO 芋艿:待接入 + async wechatAppPay() { + let that = this; + let { error, data } = await this.prepay(); + if (error === 0) { + uni.requestPayment({ + provider: 'wxpay', + orderInfo: data.pay_data, //微信订单数据(官方说是string。实测为object) + success: (res) => { + that.payResult('success'); + }, + fail: (err) => { + err.errMsg !== 'requestPayment:fail cancel' && that.payResult('fail'); + }, + }); + } + } + + // 支付结果跳转,success:成功,fail:失败 + payResult(resultType) { + sheep.$router.redirect('/pages/pay/result', { + id: this.id, + orderType: this.orderType, + payState: resultType + }); + } + + // 引导绑定微信 + bindWeixin() { + uni.showModal({ + title: '微信支付', + content: '请先绑定微信再使用微信支付', + success: function (res) { + if (res.confirm) { + sheep.$platform.useProvider('wechat').bind(); + } + }, + }); + } + +} + +export function getPayMethods(channels) { + const payMethods = [ + { + icon: '/static/img/shop/pay/wechat.png', + title: '微信支付', + value: 'wechat', + disabled: true, + }, + { + icon: '/static/img/shop/pay/alipay.png', + title: '支付宝支付', + value: 'alipay', + disabled: true, + }, + { + icon: '/static/img/shop/pay/wallet.png', + title: '余额支付', + value: 'wallet', + disabled: true, + }, + { + icon: '/static/img/shop/pay/apple.png', + title: 'Apple Pay', + value: 'apple', + disabled: true, + }, + { + icon: '/static/img/shop/pay/wallet.png', + title: '模拟支付', + value: 'mock', + disabled: true, + } + ]; + const platform = sheep.$platform.name + + // 1. 处理【微信支付】 + const wechatMethod = payMethods[0]; + if ((platform === 'WechatOfficialAccount' && channels.includes('wx_pub')) + || (platform === 'WechatMiniProgram' && channels.includes('wx_lite')) + || (platform === 'App' && channels.includes('wx_app'))) { + wechatMethod.disabled = false; + } + wechatMethod.disabled = false; // TODO 芋艿:临时测试 + + // 2. 处理【支付宝支付】 + const alipayMethod = payMethods[1]; + if ((platform === 'WechatOfficialAccount' && channels.includes('alipay_wap')) + || platform === 'WechatMiniProgram' && channels.includes('alipay_wap') + || platform === 'App' && channels.includes('alipay_app')) { + alipayMethod.disabled = false; + } + // 3. 处理【余额支付】 + const walletMethod = payMethods[2]; + if (channels.includes('wallet')) { + walletMethod.disabled = false; + } + // 4. 处理【苹果支付】TODO 芋艿:未来接入 + // 5. 处理【模拟支付】 + const mockMethod = payMethods[4]; + if (channels.includes('mock')) { + mockMethod.disabled = false; + } + return payMethods; +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/apple/app.js b/yudao-mall-uniapp-master/sheep/platform/provider/apple/app.js new file mode 100644 index 0000000..c1c9149 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/apple/app.js @@ -0,0 +1,36 @@ +// import third from '@/sheep/api/third'; +// TODO 芋艿:等后面搞 App 再弄 + +const login = () => { + return new Promise(async (resolve, reject) => { + const loginRes = await uni.login({ + provider: 'apple', + success: () => { + uni.getUserInfo({ + provider: 'apple', + success: async (res) => { + if (res.errMsg === 'getUserInfo:ok') { + const payload = res.userInfo; + const { error } = await third.apple.login({ + payload, + shareInfo: uni.getStorageSync('shareLog') || {}, + }); + if (error === 0) { + resolve(true); + } else { + resolve(false); + } + } + }, + }); + }, + fail: (err) => { + resolve(false); + }, + }); + }); +}; + +export default { + login, +}; diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/apple/index.js b/yudao-mall-uniapp-master/sheep/platform/provider/apple/index.js new file mode 100644 index 0000000..388c093 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/apple/index.js @@ -0,0 +1,9 @@ +// #ifdef APP-PLUS +import service from './app'; +// #endif + +let apple = {}; +if (typeof service !== 'undefined') { + apple = service; +} +export default apple; diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/wechat/index.js b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/index.js new file mode 100644 index 0000000..3bb2c7f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/index.js @@ -0,0 +1,15 @@ +// #ifdef H5 +import service from './officialAccount'; +// #endif + +// #ifdef MP-WEIXIN +import service from './miniProgram'; +// #endif + +// #ifdef APP-PLUS +import service from './openPlatform'; +// #endif + +const wechat = service; + +export default wechat; diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/wechat/miniProgram.js b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/miniProgram.js new file mode 100644 index 0000000..a5b64b0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/miniProgram.js @@ -0,0 +1,205 @@ +import third from '@/sheep/api/migration/third' +import AuthUtil from '@/sheep/api/member/auth'; +import SocialApi from '@/sheep/api/member/social'; +import UserApi from '@/sheep/api/member/user'; + +const socialType = 34; // 社交类型 - 微信小程序 + +let subscribeEventList = []; + +// 加载微信小程序 +function load() { + checkUpdate(); + getSubscribeTemplate(); +} + +// 微信小程序静默授权登陆 +const login = async () => { + return new Promise(async (resolve, reject) => { + // 1. 获得微信 code + const codeResult = await uni.login(); + if (codeResult.errMsg !== 'login:ok') { + return resolve(false); + } + + // 2. 社交登录 + const loginResult = await AuthUtil.socialLogin(socialType, codeResult.code, 'default'); + if (loginResult.code === 0) { + setOpenid(loginResult.data.openid); + return resolve(true); + } else { + return resolve(false); + } + }); +}; + +// 微信小程序手机号授权登陆 +const mobileLogin = async (e) => { + return new Promise(async (resolve, reject) => { + if (e.errMsg !== 'getPhoneNumber:ok') { + return resolve(false); + } + + // 1. 获得微信 code + const codeResult = await uni.login(); + if (codeResult.errMsg !== 'login:ok') { + return resolve(false); + } + + // 2. 一键登录 + const loginResult = await AuthUtil.weixinMiniAppLogin(e.code, codeResult.code, 'default'); + if (loginResult.code === 0) { + setOpenid(loginResult.data.openid); + return resolve(true); + } else { + return resolve(false); + } + // TODO 芋艿:shareInfo: uni.getStorageSync('shareLog') || {}, + }); +}; + +// 微信小程序绑定 +const bind = () => { + return new Promise(async (resolve, reject) => { + // 1. 获得微信 code + const codeResult = await uni.login(); + if (codeResult.errMsg !== 'login:ok') { + return resolve(false); + } + + // 2. 绑定账号 + const bindResult = await SocialApi.socialBind(socialType, codeResult.code, 'default'); + if (bindResult.code === 0) { + setOpenid(bindResult.data); + return resolve(true); + } else { + return resolve(false); + } + }); +}; + +// 微信小程序解除绑定 +const unbind = async (openid) => { + const { code } = await SocialApi.socialUnbind(socialType, openid); + return code === 0; +}; + +// 绑定用户手机号 +const bindUserPhoneNumber = (e) => { + return new Promise(async (resolve, reject) => { + const { code } = await UserApi.updateUserMobileByWeixin(e.code); + if (code === 0) { + resolve(true); + } + resolve(false); + }); +}; + +// 设置 openid 到本地存储,目前只有 pay 支付时会使用 +function setOpenid(openid) { + uni.setStorageSync('openid', openid); +} + +// 获得 openid +async function getOpenid(force = false) { + let openid = uni.getStorageSync('openid'); + if (!openid && force) { + const info = await getInfo(); + if (info && info.openid) { + openid = info.openid; + setOpenid(openid); + } + } + return openid; +} + +// 获得社交信息 +async function getInfo() { + const { code, data } = await SocialApi.getSocialUser(socialType); + if (code !== 0) { + return undefined; + } + return data; +} + +// ========== 非登录相关的逻辑 ========== + +// 小程序更新 +const checkUpdate = async (silence = true) => { + if (uni.canIUse('getUpdateManager')) { + const updateManager = uni.getUpdateManager(); + updateManager.onCheckForUpdate(function (res) { + // 请求完新版本信息的回调 + if (res.hasUpdate) { + updateManager.onUpdateReady(function () { + uni.showModal({ + title: '更新提示', + content: '新版本已经准备好,是否重启应用?', + success: function (res) { + if (res.confirm) { + // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 + updateManager.applyUpdate(); + } + }, + }); + }); + updateManager.onUpdateFailed(function () { + // 新的版本下载失败 + // uni.showModal({ + // title: '已经有新版本了哟~', + // content: '新版本已经上线啦,请您删除当前小程序,重新搜索打开~', + // }); + }); + } else { + if (!silence) { + uni.showModal({ + title: '当前为最新版本', + showCancel: false, + }); + } + } + }); + } +}; + +// 获取订阅消息模板 +async function getSubscribeTemplate() { + const { error, data } = await third.wechat.subscribeTemplate(); + if (error === 0) { + subscribeEventList = data; + } +} + +// 订阅消息 +function subscribeMessage(event) { + let tmplIds = []; + if (typeof event === 'string') { + tmplIds.push(subscribeEventList[event]); + } + if (typeof event === 'object') { + event.forEach((item) => { + if (typeof subscribeEventList[item] !== 'undefined') tmplIds.push(subscribeEventList[item]); + }); + } + if (tmplIds.length === 0) return; + + uni.requestSubscribeMessage({ + tmplIds, + fail: (err) => { + console.log(err); + }, + }); +} + +export default { + load, + login, + bind, + unbind, + bindUserPhoneNumber, + mobileLogin, + getInfo, + getOpenid, + subscribeMessage, + checkUpdate +}; diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/wechat/officialAccount.js b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/officialAccount.js new file mode 100644 index 0000000..2d3e5dd --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/officialAccount.js @@ -0,0 +1,107 @@ +import $wxsdk from '@/sheep/libs/sdk-h5-weixin'; +import { getRootUrl } from '@/sheep/helper'; +import AuthUtil from '@/sheep/api/member/auth'; +import SocialApi from '@/sheep/api/member/social'; + +const socialType = 31; // 社交类型 - 微信公众号 + +// 加载微信公众号JSSDK +async function load() { + $wxsdk.init(); +} + +// 微信公众号登陆 +async function login(code = '', state = '') { + // 情况一:没有 code 时,去获取 code + if (!code) { + const loginUrl = await getLoginUrl(); + if (loginUrl) { + uni.setStorageSync('returnUrl', location.href); + window.location = loginUrl; + } + // 情况二:有 code 时,使用 code 去自动登录 + } else { + // 解密 code 发起登陆 + const loginResult = await AuthUtil.socialLogin(socialType, code, state); + if (loginResult.code === 0) { + // TODO 芋艿:shareLog + setOpenid(loginResult.data.openid); + return loginResult; + } + } + return false; +} + +// 微信公众号绑定 +async function bind(code = '', state = '') { + // 情况一:没有 code 时,去获取 code + if (code === '') { + const loginUrl = await getLoginUrl('bind'); + if (loginUrl) { + uni.setStorageSync('returnUrl', location.href); + window.location = loginUrl; + } + } else { + // 情况二:有 code 时,使用 code 去自动绑定 + const loginResult = await SocialApi.socialBind(socialType, code, state); + if (loginResult.code === 0) { + setOpenid(loginResult.data); + return loginResult; + } + } + return false; +} + +// 微信公众号解除绑定 +const unbind = async (openid) => { + const { code } = await SocialApi.socialUnbind(socialType, openid); + return code === 0; +}; + +// 获取公众号登陆地址 +async function getLoginUrl(event = 'login') { + const page = getRootUrl() + 'pages/index/login' + + '?event=' + event; // event 目的,区分是 login 还是 bind + const { code, data } = await AuthUtil.socialAuthRedirect(socialType, page); + if (code !== 0) { + return undefined; + } + return data; +} + +// 设置 openid 到本地存储,目前只有 pay 支付时会使用 +function setOpenid(openid) { + uni.setStorageSync('openid', openid); +} + +// 获得 openid +async function getOpenid(force = false) { + let openid = uni.getStorageSync('openid'); + if (!openid && force) { + const info = await getInfo(); + if (info && info.openid) { + openid = info.openid; + setOpenid(openid); + } + } + return openid; +} + +// 获得社交信息 +async function getInfo() { + const { code, data } = await SocialApi.getSocialUser(socialType); + if (code !== 0) { + return undefined; + } + return data; +} + +export default { + load, + login, + bind, + unbind, + getInfo, + getOpenid, + jssdk: $wxsdk, +}; diff --git a/yudao-mall-uniapp-master/sheep/platform/provider/wechat/openPlatform.js b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/openPlatform.js new file mode 100644 index 0000000..a80f0d7 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/provider/wechat/openPlatform.js @@ -0,0 +1,64 @@ +// 登录 +import third from '@/sheep/api/migration/third'; +import SocialApi from '@/sheep/api/member/social'; +import $share from '@/sheep/platform/share'; + +// TODO 芋艿:等后面搞 App 再弄 +const socialType = 32; // 社交类型 - 微信开放平台 + +const load = async () => {}; + +// 微信开放平台移动应用授权登陆 +const login = () => { + return new Promise(async (resolve, reject) => { + const loginRes = await uni.login({ + provider: 'weixin', + onlyAuthorize: true, + }); + debugger + if (loginRes.errMsg == 'login:ok') { + // TODO third.wechat.login 函数未实现 + const res = await third.wechat.login({ + platform: 'openPlatform', + shareInfo: uni.getStorageSync('shareLog') || {}, + payload: encodeURIComponent( + JSON.stringify({ + code: loginRes.code, + }), + ), + }); + + if (res.error === 0) { + $share.bindBrokerageUser() + resolve(true); + } + } else { + uni.showToast({ + icon: 'none', + title: loginRes.errMsg, + }); + } + resolve(false); + }); +}; + +// 微信 App 解除绑定 +const unbind = async (openid) => { + const { code } = await SocialApi.socialUnbind(socialType, openid); + return code === 0; +}; + +// 获得社交信息 +async function getInfo() { + const { code, data } = await SocialApi.getSocialUser(socialType); + if (code !== 0) { + return undefined; + } + return data; +} + +export default { + load, + login, + getInfo +}; diff --git a/yudao-mall-uniapp-master/sheep/platform/share.js b/yudao-mall-uniapp-master/sheep/platform/share.js new file mode 100644 index 0000000..a5d1b0a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/platform/share.js @@ -0,0 +1,202 @@ +import $store from '@/sheep/store'; +import $platform from '@/sheep/platform'; +import $router from '@/sheep/router'; +import $url from '@/sheep/url'; +import BrokerageApi from '@/sheep/api/trade/brokerage'; +// #ifdef H5 +import $wxsdk from '@/sheep/libs/sdk-h5-weixin'; +// #endif + +// 设置分享的平台渠道: 1=H5,2=微信公众号网页,3=微信小程序,4=App,...按需扩展 +const platformMap = ['H5', 'WechatOfficialAccount', 'WechatMiniProgram', 'App']; + +// 设置分享方式: 1=直接转发,2=海报,3=复制链接,...按需扩展 +const fromMap = ['forward', 'poster', 'link']; + +// TODO 芋艿:分享的接入 +// 设置分享信息参数 +const getShareInfo = ( + scene = { + title: '', // 自定义分享标题 + desc: '', // 自定义描述 + image: '', // 自定义分享图片 + params: {}, // 自定义分享参数 + }, + poster = { + // 自定义海报数据 + type: 'user', + }, +) => { + const shareInfo = { + title: '', // 分享标题 + desc: '', // 描述 + image: '', // 分享图片 + path: '', // 分享页面+参数 + link: '', // 分享Url+参数 + query: '', // 分享参数 + poster, // 海报所需数据 + }; + + const app = $store('app'); + const shareConfig = app.platform.share; + + // 自动拼接分享用户参数 + const query = buildSpmQuery(scene.params); + shareInfo.query = query; + + // 配置分享链接地址 + shareInfo.link = buildSpmLink(query, shareConfig.linkAddress); + // 配置页面地址带参数 + shareInfo.path = buildSpmPath(query); + + // 配置转发参数 + if (shareConfig.methods.includes('forward')) { + // TODO puhui999: forward 这块有点问题 + if (shareConfig.forwardInfo.title === '' || shareConfig.forwardInfo.image === '') { + console.log('请在平台设置中配置转发信息'); + } + // 设置自定义分享信息 + shareInfo.title = scene.title || shareConfig.forwardInfo.title; + shareInfo.image = $url.cdn(scene.image || shareConfig.forwardInfo.image); + shareInfo.desc = scene.desc || shareConfig.forwardInfo.subtitle; + shareInfo.path = buildSpmPath(scene.path, query); + } + + return shareInfo; +}; + +// 构造spm分享参数 +const buildSpmQuery = (params) => { + const user = $store('user'); + let shareId = '0'; // 设置分享者用户ID + if (typeof params.shareId === 'undefined') { + if (user.isLogin) { + shareId = user.userInfo.id; + } + } + let page = '1'; // 页面类型: 1=首页(默认),2=商品,3=拼团商品,4=秒杀商品,5=邀请参团,6=分销邀请...按需扩展 + if (typeof params.page !== 'undefined') { + page = params.page; + } + let query = '0'; // 设置页面ID: 如商品ID、拼团ID等 + if (typeof params.query !== 'undefined') { + query = params.query; + } + let platform = platformMap.indexOf($platform.name) + 1; + let from = '1'; + if (typeof params.from !== 'undefined') { + from = platformMap.indexOf(params.from) + 1; + } + //spmParams = ... 可按需扩展 + return `spm=${shareId}.${page}.${query}.${platform}.${from}`; +}; + +// 构造页面分享参数: 所有的分享都先到首页进行 spm 参数解析 +const buildSpmPath = (query) => { + // 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /, + // 不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置 + return `pages/index/index`; +}; + +// 构造分享链接 +const buildSpmLink = (query, linkAddress = '') => { + return `${linkAddress}?${query}`; +}; + +// 解析Spm +const decryptSpm = (spm) => { + const user = $store('user'); + let shareParamsArray = spm.split('.'); + let shareParams = { + spm, + shareId: 0, + page: '', + query: {}, + platform: '', + from: '', + }; + let query; + shareParams.shareId = shareParamsArray[0]; + switch (shareParamsArray[1]) { + case '1': + // 默认首页不跳转 + shareParams.page = '/pages/index/index'; + break; + case '2': + // 普通商品 + shareParams.page = '/pages/goods/index'; + shareParams.query = { + id: shareParamsArray[2], + }; + break; + case '3': + // 拼团商品 + shareParams.page = '/pages/goods/groupon'; + query = shareParamsArray[2].split(','); + shareParams.query = { + id: query[0], + activity_id: query[1], // TODO 芋艿:接入分享后,应该统一成 id 参数 + }; + break; + case '4': + // 秒杀商品 + shareParams.page = '/pages/goods/seckill'; + query = shareParamsArray[2].split(','); + shareParams.query = { + id: query[1], + }; + break; + case '5': + // 参与拼团 + shareParams.page = '/pages/activity/groupon/detail'; + shareParams.query = { + id: shareParamsArray[2], + }; + break; + } + shareParams.platform = platformMap[shareParamsArray[3] - 1]; + shareParams.from = fromMap[shareParamsArray[4] - 1]; + if (shareParams.shareId !== 0) { + // 已登录 绑定推广员 + if (user.isLogin) { + bindBrokerageUser(shareParams.shareId); + } else { + // 记录分享者编号 + uni.setStorageSync('shareId', shareParams.shareId); + } + } + + if (shareParams.page !== '/pages/index/index') { + $router.go(shareParams.page, shareParams.query); + } + return shareParams; +}; + +// 绑定推广员 +const bindBrokerageUser = async (val= undefined) => { + try { + const shareId = val || uni.getStorageSync('shareId'); + if (!shareId) { + return; + } + await BrokerageApi.bindBrokerageUser({ bindUserId: shareId }); + uni.removeStorageSync('shareId'); + } catch { + } +}; + +// 更新公众号分享sdk +const updateShareInfo = (shareInfo) => { + // #ifdef H5 + if ($platform.name === 'WechatOfficialAccount') { + $wxsdk.updateShareInfo(shareInfo); + } + // #endif +}; + +export default { + getShareInfo, + updateShareInfo, + decryptSpm, + bindBrokerageUser, +}; diff --git a/yudao-mall-uniapp-master/sheep/request/index.js b/yudao-mall-uniapp-master/sheep/request/index.js new file mode 100644 index 0000000..99c38a4 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/request/index.js @@ -0,0 +1,302 @@ +/** + * Shopro-request + * @description api模块管理,loading配置,请求拦截,错误处理 + */ + +import Request from 'luch-request'; +import { baseUrl, apiPath } from '@/sheep/config'; +import $store from '@/sheep/store'; +import $platform from '@/sheep/platform'; +import { + showAuthModal +} from '@/sheep/hooks/useModal'; +import AuthUtil from '@/sheep/api/member/auth'; + +const options = { + // 显示操作成功消息 默认不显示 + showSuccess: false, + // 成功提醒 默认使用后端返回值 + successMsg: '', + // 显示失败消息 默认显示 + showError: true, + // 失败提醒 默认使用后端返回信息 + errorMsg: '', + // 显示请求时loading模态框 默认显示 + showLoading: true, + // loading提醒文字 + loadingMsg: '加载中', + // 需要授权才能请求 默认放开 + auth: false, + // ... +}; + +// Loading全局实例 +let LoadingInstance = { + target: null, + count: 0, +}; + +/** + * 关闭loading + */ +function closeLoading() { + if (LoadingInstance.count > 0) LoadingInstance.count--; + if (LoadingInstance.count === 0) uni.hideLoading(); +} + +/** + * @description 请求基础配置 可直接使用访问自定义请求 + */ +const http = new Request({ + baseURL: baseUrl + apiPath, + timeout: 8000, + method: 'GET', + header: { + Accept: 'text/json', + 'Content-Type': 'application/json;charset=UTF-8', + platform: $platform.name, + }, + // #ifdef APP-PLUS + sslVerify: false, + // #endif + // #ifdef H5 + // 跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+) + withCredentials: false, + // #endif + custom: options, +}); + +/** + * @description 请求拦截器 + */ +http.interceptors.request.use( + (config) => { + // 自定义处理【auth 授权】:必须登录的接口,则跳出 AuthModal 登录弹窗 + if (config.custom.auth && !$store('user').isLogin) { + showAuthModal(); + return Promise.reject(); + } + + // 自定义处理【loading 加载中】:如果需要显示 loading,则显示 loading + if (config.custom.showLoading) { + LoadingInstance.count++; + LoadingInstance.count === 1 && + uni.showLoading({ + title: config.custom.loadingMsg, + mask: true, + fail: () => { + uni.hideLoading(); + }, + }); + } + + // 增加 token 令牌、terminal 终端、tenant 租户的请求头 + const token = getAccessToken(); + if (token) { + config.header['Authorization'] = token; + } + // TODO 芋艿:特殊处理 + config.header['Accept'] = '*/*' + config.header['tenant-id'] = '1'; + config.header['terminal'] = '20'; + // config.header['Authorization'] = 'Bearer test247'; + return config; + }, + (error) => { + return Promise.reject(error); + }, +); + +/** + * @description 响应拦截器 + */ +http.interceptors.response.use( + (response) => { + // 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌 + if (response.config.url.indexOf('/member/auth/') >= 0 && response.data?.data?.accessToken) { + $store('user').setToken(response.data.data.accessToken, response.data.data.refreshToken); + } + + // 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading + response.config.custom.showLoading && closeLoading(); + + // 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示 + if (response.data.code !== 0) { + // 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌 + if (response.data.code === 401) { + return refreshToken(response.config); + } + + // 错误提示 + if (response.config.custom.showError) { + uni.showToast({ + title: response.data.msg || '服务器开小差啦,请稍后再试~', + icon: 'none', + mask: true, + }); + } + } + + // 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示 + if (response.config.custom.showSuccess + && response.config.custom.successMsg !== '' + && response.data.code === 0) { + uni.showToast({ + title: response.config.custom.successMsg, + icon: 'none', + }); + } + + // 返回结果:包括 code + data + msg + return Promise.resolve(response.data); + }, + (error) => { + const userStore = $store('user'); + const isLogin = userStore.isLogin; + let errorMessage = '网络请求出错'; + if (error !== undefined) { + switch (error.statusCode) { + case 400: + errorMessage = '请求错误'; + break; + case 401: + errorMessage = isLogin ? '您的登陆已过期' : '请先登录'; + // 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized + break; + case 403: + errorMessage = '拒绝访问'; + break; + case 404: + errorMessage = '请求出错'; + break; + case 408: + errorMessage = '请求超时'; + break; + case 429: + errorMessage = '请求频繁, 请稍后再访问'; + break; + case 500: + errorMessage = '服务器开小差啦,请稍后再试~'; + break; + case 501: + errorMessage = '服务未实现'; + break; + case 502: + errorMessage = '网络错误'; + break; + case 503: + errorMessage = '服务不可用'; + break; + case 504: + errorMessage = '网络超时'; + break; + case 505: + errorMessage = 'HTTP 版本不受支持'; + break; + } + if (error.errMsg.includes('timeout')) errorMessage = '请求超时'; + // #ifdef H5 + if (error.errMsg.includes('Network')) + errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接'; + // #endif + } + + if (error && error.config) { + if (error.config.custom.showError === false) { + uni.showToast({ + title: error.data?.msg || errorMessage, + icon: 'none', + mask: true, + }); + } + error.config.custom.showLoading && closeLoading(); + } + + return false; + }, +); + +// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现 +let requestList = [] // 请求队列 +let isRefreshToken = false // 是否正在刷新中 +const refreshToken = async (config) => { + // 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error) + if (config.url.indexOf('/member/auth/refresh-token') >= 0) { + return Promise.reject('error') + } + + // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 + if (!isRefreshToken) { + isRefreshToken = true + // 1. 如果获取不到刷新令牌,则只能执行登出操作 + const refreshToken = getRefreshToken() + if (!refreshToken) { + return handleAuthorized() + } + // 2. 进行刷新访问令牌 + try { + const refreshTokenResult = await AuthUtil.refreshToken(refreshToken); + if (refreshTokenResult.code !== 0) { + // 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑 + // noinspection ExceptionCaughtLocallyJS + throw new Error('刷新令牌失败'); + } + // 2.1 刷新成功,则回放队列的请求 + 当前请求 + config.header.Authorization = 'Bearer ' + getAccessToken() + requestList.forEach((cb) => { + cb() + }) + requestList = [] + return request(config) + } catch (e) { + // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 + // 2.2 刷新失败,只回放队列的请求 + requestList.forEach((cb) => { + cb() + }) + // 提示是否要登出。即不回放当前请求!不然会形成递归 + return handleAuthorized() + } finally { + requestList = [] + isRefreshToken = false + } + } else { + // 添加到队列,等待刷新获取到新的令牌 + return new Promise((resolve) => { + requestList.push(() => { + config.header.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改 + resolve(request(config)) + }) + }) + } +} + +/** + * 处理 401 未登录的错误 + */ +const handleAuthorized = () => { + const userStore = $store('user'); + userStore.logout(true); + showAuthModal(); + // 登录超时 + return Promise.reject({ + code: 401, + msg: userStore.isLogin ? '您的登陆已过期' : '请先登录' + }) +} + +/** 获得访问令牌 */ +const getAccessToken = () => { + return uni.getStorageSync('token'); +} + +/** 获得刷新令牌 */ +const getRefreshToken = () => { + return uni.getStorageSync('refresh-token'); +} + +const request = (config) => { + return http.middleware(config); +}; + +export default request; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/router/index.js b/yudao-mall-uniapp-master/sheep/router/index.js new file mode 100644 index 0000000..86796e5 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/router/index.js @@ -0,0 +1,185 @@ +import $store from '@/sheep/store'; +import { showAuthModal, showShareModal } from '@/sheep/hooks/useModal'; +import { isNumber, isString, isEmpty, startsWith, isObject, isNil, clone } from 'lodash'; +import throttle from '@/sheep/helper/throttle'; + +const _go = ( + path, + params = {}, + options = { + redirect: false, + }, +) => { + let page = ''; // 跳转页面 + let query = ''; // 页面参数 + let url = ''; // 跳转页面完整路径 + + if (isString(path)) { + // 判断跳转类型是 path | 还是http + if (startsWith(path, 'http')) { + // #ifdef H5 + window.location = path; + return; + // #endif + // #ifndef H5 + page = `/pages/public/webview`; + query = `url=${encodeURIComponent(path)}`; + // #endif + } else if (startsWith(path, 'action:')) { + handleAction(path); + return; + } else { + [page, query] = path.split('?'); + } + if (!isEmpty(params)) { + let query2 = paramsToQuery(params); + if (isEmpty(query)) { + query = query2; + } else { + query += '&' + query2; + } + } + } + + if (isObject(path)) { + page = path.url; + if (!isNil(path.params)) { + query = paramsToQuery(path.params); + } + } + + const nextRoute = ROUTES_MAP[page]; + + // 未找到指定跳转页面 + // mark: 跳转404页 + if (!nextRoute) { + console.log(`%c跳转路径参数错误<${page || 'EMPTY'}>`, 'color:red;background:yellow'); + return; + } + + // 页面登录拦截 + if (nextRoute.meta?.auth && !$store('user').isLogin) { + showAuthModal(); + return; + } + + url = page; + if (!isEmpty(query)) { + url += `?${query}`; + } + + // 跳转底部导航 + if (TABBAR.includes(page)) { + uni.switchTab({ + url, + }); + return; + } + + // 使用redirect跳转 + if (options.redirect) { + uni.redirectTo({ + url, + }); + return; + } + + uni.navigateTo({ + url, + }); +}; + +// 限流 防止重复点击跳转 +function go(...args) { + throttle(() => { + _go(...args); + }); +} + +function paramsToQuery(params) { + if (isEmpty(params)) { + return ''; + } + // return new URLSearchParams(Object.entries(params)).toString(); + let query = []; + for (let key in params) { + query.push(key + '=' + params[key]); + } + + return query.join('&'); +} + +function back() { + // #ifdef H5 + history.back(); + // #endif + + // #ifndef H5 + uni.navigateBack(); + // #endif +} + +function redirect(path, params = {}) { + go(path, params, { + redirect: true, + }); +} + +// 检测是否有浏览器历史 +function hasHistory() { + // #ifndef H5 + const pages = getCurrentPages(); + if (pages.length > 1) { + return true; + } + return false; + // #endif + + // #ifdef H5 + return !!history.state.back; + // #endif +} + +function getCurrentRoute(field = '') { + let currentPage = getCurrentPage(); + // #ifdef MP + currentPage.$page['route'] = currentPage.route; + currentPage.$page['options'] = currentPage.options; + // #endif + if (field !== '') { + return currentPage.$page[field]; + } else { + return currentPage.$page; + } +} + +function getCurrentPage() { + let pages = getCurrentPages(); + return pages[pages.length - 1]; +} + +function handleAction(path) { + const action = path.split(':'); + switch (action[1]) { + case 'showShareModal': + showShareModal(); + break; + } +} + +function error(errCode, errMsg = '') { + redirect('/pages/public/error', { + errCode, + errMsg, + }); +} + +export default { + go, + back, + hasHistory, + redirect, + getCurrentPage, + getCurrentRoute, + error, +}; diff --git a/yudao-mall-uniapp-master/sheep/router/utils/strip-json-comments.js b/yudao-mall-uniapp-master/sheep/router/utils/strip-json-comments.js new file mode 100644 index 0000000..5995992 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/router/utils/strip-json-comments.js @@ -0,0 +1,79 @@ +const singleComment = Symbol('singleComment'); +const multiComment = Symbol('multiComment'); + +const stripWithoutWhitespace = () => ''; +const stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/\S/g, ' '); + +const isEscaped = (jsonString, quotePosition) => { + let index = quotePosition - 1; + let backslashCount = 0; + + while (jsonString[index] === '\\') { + index -= 1; + backslashCount += 1; + } + + return Boolean(backslashCount % 2); +}; + +export default function stripJsonComments(jsonString, { whitespace = true } = {}) { + if (typeof jsonString !== 'string') { + throw new TypeError( + `Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``, + ); + } + + const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace; + + let isInsideString = false; + let isInsideComment = false; + let offset = 0; + let result = ''; + + for (let index = 0; index < jsonString.length; index++) { + const currentCharacter = jsonString[index]; + const nextCharacter = jsonString[index + 1]; + + if (!isInsideComment && currentCharacter === '"') { + const escaped = isEscaped(jsonString, index); + if (!escaped) { + isInsideString = !isInsideString; + } + } + + if (isInsideString) { + continue; + } + + if (!isInsideComment && currentCharacter + nextCharacter === '//') { + result += jsonString.slice(offset, index); + offset = index; + isInsideComment = singleComment; + index++; + } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === '\r\n') { + index++; + isInsideComment = false; + result += strip(jsonString, offset, index); + offset = index; + continue; + } else if (isInsideComment === singleComment && currentCharacter === '\n') { + isInsideComment = false; + result += strip(jsonString, offset, index); + offset = index; + } else if (!isInsideComment && currentCharacter + nextCharacter === '/*') { + result += jsonString.slice(offset, index); + offset = index; + isInsideComment = multiComment; + index++; + continue; + } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === '*/') { + index++; + isInsideComment = false; + result += strip(jsonString, offset, index + 1); + offset = index + 1; + continue; + } + } + + return result + (isInsideComment ? strip(jsonString.slice(offset)) : jsonString.slice(offset)); +} diff --git a/yudao-mall-uniapp-master/sheep/router/utils/uni-read-pages-v3.js b/yudao-mall-uniapp-master/sheep/router/utils/uni-read-pages-v3.js new file mode 100644 index 0000000..303f10a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/router/utils/uni-read-pages-v3.js @@ -0,0 +1,103 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { + value: true, +}); +const fs = require('fs'); +import stripJsonComments from './strip-json-comments'; +import { isArray, isEmpty } from 'lodash'; + +class TransformPages { + constructor({ includes, pagesJsonDir }) { + this.includes = includes; + this.uniPagesJSON = JSON.parse(stripJsonComments(fs.readFileSync(pagesJsonDir, 'utf-8'))); + this.routes = this.getPagesRoutes().concat(this.getSubPackagesRoutes()); + this.tabbar = this.getTabbarRoutes(); + this.routesMap = this.transformPathToKey(this.routes); + } + /** + * 通过读取pages.json文件 生成直接可用的routes + */ + getPagesRoutes(pages = this.uniPagesJSON.pages, rootPath = null) { + let routes = []; + for (let i = 0; i < pages.length; i++) { + const item = pages[i]; + let route = {}; + for (let j = 0; j < this.includes.length; j++) { + const key = this.includes[j]; + let value = item[key]; + if (key === 'path') { + value = rootPath ? `/${rootPath}/${value}` : `/${value}`; + } + if (key === 'aliasPath' && i == 0 && rootPath == null) { + route[key] = route[key] || '/'; + } else if (value !== undefined) { + route[key] = value; + } + } + routes.push(route); + } + return routes; + } + /** + * 解析小程序分包路径 + */ + getSubPackagesRoutes() { + if (!(this.uniPagesJSON && this.uniPagesJSON.subPackages)) { + return []; + } + const subPackages = this.uniPagesJSON.subPackages; + let routes = []; + for (let i = 0; i < subPackages.length; i++) { + const subPages = subPackages[i].pages; + const root = subPackages[i].root; + const subRoutes = this.getPagesRoutes(subPages, root); + routes = routes.concat(subRoutes); + } + return routes; + } + + getTabbarRoutes() { + if (!(this.uniPagesJSON && this.uniPagesJSON.tabBar && this.uniPagesJSON.tabBar.list)) { + return []; + } + const tabbar = this.uniPagesJSON.tabBar.list; + let tabbarMap = []; + tabbar.forEach((bar) => { + tabbarMap.push('/' + bar.pagePath); + }); + return tabbarMap; + } + + transformPathToKey(list) { + if (!isArray(list) || isEmpty(list)) { + return []; + } + let map = {}; + list.forEach((i) => { + map[i.path] = i; + }); + return map; + } +} + +function uniReadPagesV3Plugin({ pagesJsonDir, includes }) { + let defaultIncludes = ['path', 'aliasPath', 'name']; + includes = [...defaultIncludes, ...includes]; + let pages = new TransformPages({ + pagesJsonDir, + includes, + }); + return { + name: 'uni-read-pages-v3', + config(config) { + return { + define: { + ROUTES: pages.routes, + ROUTES_MAP: pages.routesMap, + TABBAR: pages.tabbar, + }, + }; + }, + }; +} +exports.default = uniReadPagesV3Plugin; diff --git a/yudao-mall-uniapp-master/sheep/scss/_main.scss b/yudao-mall-uniapp-master/sheep/scss/_main.scss new file mode 100644 index 0000000..999513a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/_main.scss @@ -0,0 +1,354 @@ +body { + color: var(--text-a); + background-color: var(--ui-BG-1) !important; + font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +/* ================== + 初始化 + ==================== */ +.ui-link { + cursor: pointer; +} +navigator { + display: inline-flex; +} +navigator.navigator-hover { + background-color: inherit; + transform: translate(1rpx, 1rpx); + // opacity: 1; +} + +/* ================== + 辅助类 + ==================== */ +.none { + display: none !important; +} +.inline { + display: inline !important; +} +.inline-block { + display: inline-block !important; +} +.block { + display: block !important; +} +.touch-none { + pointer-events: none; +} +.touch-all { + pointer-events: all; +} +.flex { + display: flex !important; +} +.inline-flex { + display: inline-flex !important; +} +.w-100 { + width: 100%; +} +/* -- 浮动 -- */ +.cf::after, +.cf::before { + content: ''; + display: table; +} +.cf::after { + clear: both; +} +.fl { + float: left; +} +.fr { + float: right; +} +.position-center { + @include position-center; +} +.position-relative { + position: relative; +} +/* -- 工具类 -- */ +@function negativify-map($map) { + $result: (); + @each $key, $value in $map { + @if $key != 0 { + $result: map-merge($result, ('n' + $key: (-$value))); + } + } + @return $result; +} + +$utilities: () !default; +$utilities: map-merge( + ( + 'margin': ( + responsive: true, + property: margin, + class: m, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-x': ( + property: margin-right margin-left, + class: mx, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-y': ( + property: margin-top margin-bottom, + class: my, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-top': ( + property: margin-top, + class: mt, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-right': ( + property: margin-right, + class: mr, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-bottom': ( + property: margin-bottom, + class: mb, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'margin-left': ( + property: margin-left, + class: ml, + values: + map-merge( + $spacers, + ( + auto: auto, + ) + ), + ), + 'padding': ( + responsive: true, + property: padding, + class: p, + values: $spacers, + ), + 'padding-x': ( + property: padding-right padding-left, + class: px, + values: $spacers, + ), + 'padding-y': ( + property: padding-top padding-bottom, + class: py, + values: $spacers, + ), + 'padding-top': ( + property: padding-top, + class: pt, + values: $spacers, + ), + 'padding-right': ( + property: padding-right, + class: pr, + values: $spacers, + ), + 'padding-bottom': ( + property: padding-bottom, + class: pb, + values: $spacers, + ), + 'padding-left': ( + property: padding-left, + class: pl, + values: $spacers, + ), + 'font-weight': ( + property: font-weight, + class: text, + values: ( + light: $font-weight-light, + lighter: $font-weight-lighter, + normal: $font-weight-normal, + bold: $font-weight-bold, + bolder: $font-weight-bolder, + ), + ), + 'text-align': ( + property: text-align, + class: text, + values: left right center, + ), + 'font-color': ( + property: color, + class: text, + values: + map-merge( + $colors, + map-merge( + $grays, + map-merge( + $darks, + ( + 'reset': inherit, + ) + ) + ) + ), + ), + 'line-height': ( + property: line-height, + class: lh, + values: ( + 1: 1, + sm: $line-height-sm, + base: $line-height-base, + lg: $line-height-lg, + ), + ), + 'white-space': ( + property: white-space, + class: text, + values: ( + nowrap: nowrap, + ), + ), + 'radius': ( + property: border-radius, + class: radius, + values: ( + null: $radius, + sm: $radius-sm, + lg: $radius-lg, + 0: 0, + ), + ), + 'round': ( + property: border-radius, + class: round, + values: ( + null: $round-pill, + circle: 50%, + ), + ), + 'radius-top': ( + property: border-top-left-radius border-top-right-radius, + class: radius-top, + values: ( + null: $radius, + ), + ), + 'radius-right': ( + property: border-top-right-radius border-bottom-right-radius, + class: radius-right, + values: ( + null: $radius, + ), + ), + 'radius-bottom': ( + property: border-bottom-right-radius border-bottom-left-radius, + class: radius-bottom, + values: ( + null: $radius, + ), + ), + 'radius-left': ( + property: border-bottom-left-radius border-top-left-radius, + class: radius-left, + values: ( + null: $radius, + ), + ), + 'radius-lr': ( + property: border-top-left-radius border-bottom-right-radius, + class: radius-lr, + values: ( + null: $radius, + ), + ), + 'radius-lrs': ( + property: border-top-right-radius border-bottom-left-radius, + class: radius-lr, + values: ( + null: 0, + ), + ), + 'radius-rl': ( + property: border-top-right-radius border-bottom-left-radius, + class: radius-rl, + values: ( + null: $radius, + ), + ), + 'radius-rls': ( + property: border-top-left-radius border-bottom-right-radius, + class: radius-rl, + values: ( + null: 0, + ), + ), + ), + $utilities +); +@each $key, $utility in $utilities { + @if type-of($utility) == 'map' { + $values: map-get($utility, values); + @if type-of($values) == 'string' or type-of(nth($values, 1)) != 'list' { + $values: zip($values, $values); + } + @each $key, $value in $values { + $properties: map-get($utility, property); + @if type-of($properties) == 'string' { + $properties: append((), $properties); + } + $property-class: if( + map-has-key($utility, class), + map-get($utility, class), + nth($properties, 1) + ); + $property-class: if($property-class == null, '', $property-class); + $property-class-modifier: if($key, if($property-class == '', '', '-') + $key, ''); + .#{$property-class + $property-class-modifier} { + @each $property in $properties { + #{$property}: $value !important; + } + } + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/_mixins.scss b/yudao-mall-uniapp-master/sheep/scss/_mixins.scss new file mode 100644 index 0000000..299f7b1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/_mixins.scss @@ -0,0 +1,61 @@ +@mixin bg-square { + background: { + color: #fff; + image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%), + linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%); + size: 40rpx 40rpx; + position: 0 0, 20rpx 20rpx; + } +} + +@mixin flex($direction: row) { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: $direction; +} +@mixin flex-bar { + position: relative; + display: flex; + align-items: center; + justify-content: space-between; +} +@mixin flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +@mixin arrow { + content: ''; + height: 0; + width: 0; + position: absolute; +} +@mixin arrow-top { + @include arrow; + // border-color: transparent transparent $ui-BG; + border-style: none solid solid; + border-width: 0 20rpx 20rpx; +} + +@mixin arrow-right { + @include arrow; + // border-color: transparent $ui-BG transparent; + border-style: solid solid solid none; + border-width: 20rpx 20rpx 20rpx 0; +} +@mixin position-center { + position: absolute !important; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; +} + +@mixin blur { + -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + color: var(--ui-TC); +} diff --git a/yudao-mall-uniapp-master/sheep/scss/_tools.scss b/yudao-mall-uniapp-master/sheep/scss/_tools.scss new file mode 100644 index 0000000..e1fb636 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/_tools.scss @@ -0,0 +1,286 @@ +/* ================== + 常用工具 + ==================== */ + +.ss-bg-opactity-block { + background-color: rgba(#000, 0.2); + color: #fff; +} + +/* ================== + flex布局 + ==================== */ + +.ss-flex { + display: flex; + flex-direction: row; + align-items: center; +} + +.ss-flex-1 { + flex: 1; +} + +.ss-flex-col { + display: flex; + flex-direction: column; +} + +.ss-flex-wrap { + flex-wrap: wrap; +} + +.ss-flex-nowrap { + flex-wrap: nowrap; +} + +.ss-col-center { + align-items: center; +} + +.ss-col-top { + align-items: flex-start; +} + +.ss-col-bottom { + align-items: flex-end; +} + +.ss-col-stretch { + align-items: stretch; +} + +.ss-row-center { + justify-content: center; +} + +.ss-row-left { + justify-content: flex-start; +} + +.ss-row-right { + justify-content: flex-end; +} + +.ss-row-between { + justify-content: space-between; +} + +.ss-row-around { + justify-content: space-around; +} + +.ss-self-start { + align-self: flex-start; +} + +.ss-self-end { + align-self: flex-end; +} + +.ss-self-center { + align-self: center; +} +.ss-h-100 { + height: 100%; +} +.ss-w-100 { + width: 100%; +} + +/* ================== + + margin padding: 内外边距 + + ==================== */ +@for $i from 0 through 100 { + // 只要双数和能被5除尽的数 + @if $i % 2==0 or $i % 5==0 { + // 得出:u-margin-30或者u-m-30 + .ss-margin-#{$i}, + .ss-m-#{$i} { + margin: $i + rpx; + } + .ss-m-x-#{$i} { + margin-left: $i + rpx; + margin-right: $i + rpx; + } + .ss-m-y-#{$i} { + margin-top: $i + rpx; + margin-bottom: $i + rpx; + } + + // 得出:u-padding-30或者u-p-30 + .ss-padding-#{$i}, + .ss-p-#{$i} { + padding: $i + rpx; + } + .ss-p-x-#{$i} { + padding-left: $i + rpx; + padding-right: $i + rpx; + } + .ss-p-y-#{$i} { + padding-top: $i + rpx; + padding-bottom: $i + rpx; + } + + @each $short, $long in l left, t top, r right, b bottom { + // 缩写版,结果如: u-m-l-30 + // 定义外边距 + .ss-m-#{$short}-#{$i} { + margin-#{$long}: $i + rpx; + } + + // 定义内边距 + .ss-p-#{$short}-#{$i} { + padding-#{$long}: $i + rpx; + } + + // 完整版,结果如:u-margin-left-30 + // 定义外边距 + .ss-margin-#{$long}-#{$i} { + margin-#{$long}: $i + rpx; + } + + // 定义内边距 + .ss-padding-#{$long}-#{$i} { + padding-#{$long}: $i + rpx; + } + } + } +} + +/* ================== + + radius + + ==================== */ +@for $i from 0 through 100 { + // 只要双数和能被5除尽的数 + @if $i % 2==0 or $i % 5==0 { + .ss-radius-#{$i}, + .ss-r-#{$i} { + border-radius: $i + rpx; + } + + .ss-r-t-#{$i} { + border-top-left-radius: $i + rpx; + border-top-right-radius: $i + rpx; + } + + .ss-r-b-#{$i} { + border-bottom-left-radius: $i + rpx; + border-bottom-right-radius: $i + rpx; + } + + @each $short, $long in tl 'top-left', tr 'top-right', bl 'bottom-right', br 'bottom-right' { + // 定义外边距 + .ss-r-#{$short}-#{$i} { + border-#{$long}-radius: $i + rpx; + } + + // 定义内边距 + .ss-radius-#{$long}-#{$i} { + border-#{$long}-radius: $i + rpx; + } + } + } +} + +/* ================== + + 溢出省略号 + @param {Number} 行数 + + ==================== */ +@mixin ellipsis($rowCount: 1) { + // @if $rowCount <=1 { + // overflow: hidden; + // text-overflow: ellipsis; + // white-space: nowrap; + // } @else { + // min-width: 0; + // overflow: hidden; + // text-overflow: ellipsis; + // display: -webkit-box; + // -webkit-line-clamp: $rowCount; + // -webkit-box-orient: vertical; + // } + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: $rowCount; + -webkit-box-orient: vertical; +} + +@for $i from 1 through 6 { + .ss-line-#{$i} { + @include ellipsis($i); + } +} + +/* ================== + hover + ==================== */ +.ss-hover-class { + background-color: $gray-c; + opacity: 0.6; +} +.ss-hover-btn { + transform: translate(1px, 1px); +} + +/* ================== + 底部安全区域 + ==================== */ + +.ss-safe-bottom { + padding-bottom: 0; + padding-bottom: calc(constant(safe-area-inset-bottom) / 5 * 3); + padding-bottom: calc(env(safe-area-inset-bottom) / 5 * 3); +} + +/* ================== + + 字体大小 + + ==================== */ + +@for $i from 20 through 50 { + .ss-font-#{$i} { + font-size: $i + rpx; + } +} + +/* ================== + 按钮 + ==================== */ +.ss-reset-button { + padding: 0; + margin: 0; + font-size: inherit; + background-color: transparent; + color: inherit; + position: relative; + border: 0rpx; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + align-items: center; + justify-content: center; + box-sizing: border-box; + text-align: center; + text-decoration: none; + white-space: nowrap; + vertical-align: baseline; + transform: translate(0, 0); +} +.ss-reset-button.button-hover { + transform: translate(1px, 1px); + background: none; +} + +.ss-reset-button::after { + border: none; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/_var.scss b/yudao-mall-uniapp-master/sheep/scss/_var.scss new file mode 100644 index 0000000..b0d88c8 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/_var.scss @@ -0,0 +1,162 @@ +@import './mixins'; + +//颜色 ,渐变背景60% +$yellow: #ffc300; //ss-黄 +$orange: #ff6000; //ss-橘 +$red: #ff3000; //ss-红 +$pink: #e03997; +$mauve: #b745cb; +$purple: #652abf; //rgba(101, 42, 191, 1); // ss-紫 +$blue: #0081ff; +$cyan: #37c0fe; +$green: #2aae67; //ss-绿 +$olive: #8dc63f; +$grey: #8799a3; +$brown: #a5673f; +$black: #484848; //ss-黑 +$golden: #e9b461; //ss-金 + +$colors: (); +$colors: map-merge( + ( + 'yellow': $yellow, + 'orange': $orange, + 'red': $red, + 'pink': $pink, + 'mauve': $mauve, + 'purple': $purple, + 'violet': $purple, + 'blue': $blue, + 'cyan': $cyan, + 'green': $green, + 'olive': $olive, + 'grey': $grey, + 'brown': $brown, + 'black': $black, + 'golden': $golden, + ), + $colors +); + +//灰度 +$bg-page: #f6f6f6; +$white: #ffffff; +$gray-f: #f8f9fa; +$gray-e: #eeeeee; +$gray-d: #dddddd; +$gray-c: #cccccc; +$gray-b: #bbbbbb; +$gray-a: #aaaaaa; +$dark-9: #999999; +$dark-8: #888888; +$dark-7: #777777; +$dark-6: #666666; +$dark-5: #555555; +$dark-4: #484848; //ss-黑 +$dark-3: #333333; +$dark-2: #222222; +$dark-1: #111111; +$black: #000000; + +$grays: (); +$grays: map-merge( + ( + 'white': $white, + 'gray-f': $gray-f, + 'gray-e': $gray-e, + 'gray-d': $gray-d, + 'gray-c': $gray-c, + 'gray-b': $gray-b, + 'gray-a': $gray-a, + 'gray': $gray-a, + ), + $grays +); + +$darks: (); +$darks: map-merge( + ( + 'dark-9': $dark-9, + 'dark-8': $dark-8, + 'dark-7': $dark-7, + 'dark-6': $dark-6, + 'dark-5': $dark-5, + 'dark-4': $dark-4, + 'dark-3': $dark-3, + 'dark-2': $dark-2, + 'dark-1': $dark-1, + 'black': $black, + ), + $darks +); + +// 边框 +$border-width: 1rpx !default; // 边框大小 +$border-color: $gray-d !default; // 边框颜色 + +// 圆角 +$radius: 10rpx !default; // 默认圆角大小 +$radius-lg: 40rpx !default; // 大圆角 +$radius-sm: 6rpx !default; // 小圆角 +$round-pill: 1000rpx !default; // 半圆 + +// 动画过渡 +$transition-base: all 0.2s ease-in-out !default; // 默认过渡 +$transition-base-out: all 0.04s ease-in-out !default; // 进场过渡 +$transition-fade: opacity 0.15s linear !default; // 透明过渡 +$transition-collapse: height 0.35s ease !default; // 收缩过渡 + +// 间距 +$spacer: 20rpx !default; +$spacers: () !default; +$spacers: map-merge( + ( + 0: 0, + 1: $spacer * 0.25, + 2: $spacer * 0.5, + 3: $spacer, + 4: $spacer * 1.5, + 5: $spacer * 3, + 6: $spacer * 5, + ), + $spacers +); +// 字形 +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: 900 !default; +$fontsize: () !default; +$fontsize: map-merge( + ( + xs: 20, + sm: 24, + df: 28, + lg: 32, + xl: 36, + xxl: 44, + sl: 80, + xsl: 120, + ), + $fontsize +); +// 段落 +$line-height-base: 1.5 !default; +$line-height-lg: 2 !default; +$line-height-sm: 1.25 !default; +// 图标 +$iconsize: () !default; +$iconsize: map-merge( + ( + xs: 0.5, + sm: 0.75, + df: 1, + lg: 1.25, + xl: 1.5, + xxl: 2, + sl: 6, + xsl: 10, + ), + $iconsize +); diff --git a/yudao-mall-uniapp-master/sheep/scss/font/OPPOSANS-M-subfont.ttf b/yudao-mall-uniapp-master/sheep/scss/font/OPPOSANS-M-subfont.ttf new file mode 100644 index 0000000..88ff835 Binary files /dev/null and b/yudao-mall-uniapp-master/sheep/scss/font/OPPOSANS-M-subfont.ttf differ diff --git a/yudao-mall-uniapp-master/sheep/scss/icon/_coloricon.scss b/yudao-mall-uniapp-master/sheep/scss/icon/_coloricon.scss new file mode 100644 index 0000000..f391ca4 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/icon/_coloricon.scss @@ -0,0 +1,1340 @@ +@font-face { + font-family: 'coloricon'; + src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAJB0AAsAAAABT2gAAJAjAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgC2EAqEpFiDtnIBNgIkA41oC4Z2AAQgBYUFB6ZDW0MUcaXY+Rchm9sGAFyUefbfx8xAsHGggXE4nBkINg4AzP0LZv///5+cLMaY94fewyMalFrZ2ga5yULJUZe2LpVkI+Nw45t15DA3bZWGke2LGWi24f4YvmNgiXRNPyTiB06y8TyfitG1IxylZTxRDuTdZltIe+EMrNUGezNRT7j6BH0uGz5KPBxOJbIZrz905GlCkIxEiwJKk3WZsDHNRZuYNIPT4YJSRLtm5eKScbKb7NmZ82/KaUVkxN1piXVhjne77IFbJX7B2Wvyk7d4tkFifr9Uf99o5o6aHtMpxT+s8/7P7mUuC2wb9qLR0RMUgKNMJ/AnQunNJh449t770YvECqLpQEZR1DSwaJ3ILApoII0bDctGQMihH3gCXEEpgRMvlTSNAOCh1n5vINEZmoROL5RONEmXSKK3d19c9r7rQgBx86qRaLAb6Cbo+d6wbddLtJ1YeZ7jeIa+mauvUpFBzpNbdtwONODM9AeiJTjt7YDD83Pr/f/HWP4lPWBBxRhVS+gxGCNyEq0iSKnAQARmEUoJysA7RTBQMUEZVqIXeqGCkXeKnhclFLLzApXA6PbLf/7enXPX+2sWZmtwHljiA4QDDSShUCdrOMr6/TzZ5v+ZXarUXREIRYGlzlhWsAAWFpQu6wJzL1IUEAXsWHDXxlxsYHmKDVsKYN07KRTFsnzBkgr5UTNDmppWNaSbvDzvfTr9f6mVznmVIPeGHjr48DNWbPgAUALKrdxKK0rYsFoFyVbgokO2MztTlD8CBrdZIqFSKgwzv4J3AMAAxcFzYgfzxatbVWX/xXVYw1IssnlYzaCbU3tcggxQFyz7NdDkiiw5rpcqKc39X6qWuwDpsAsQJ8eqcFPbo4AFFDIV5oYXst7DhmpPrWMI3X/u7Px/bvYf2lD9c5I8g4hCiBiwEllL8kxm5ia+C+tOAy001bdWtBMRZFO1ulkzS95LTY1PTZ+KFhIhmWeI4ICUw/+o0166Ufqf9SRD4YOh8AFgWBMupZQia7FXew3aPQ7aBwjz3VRN/a9b8KF7ZpRUydYHpjiLEDsNsvVAYEcPWZeZa8+1QWLHT2Qp+CPJAdoN0kDt4bL+15omOs4UxjP+29VVQEIH3KVGdjxKBNeZBwVFwLa1HAIM4GDklqDpcJNuY7GOy/tRhCZeMGb+S9W8ApQo09YmodIqtyhPzmnL4WI7rZzzcopve0+b//8MMH8aODMAgRkAFAcgaQKgZAxAygBIUQAIMgOS8oLFDulKyfaWrm11BqBkAHQBSElLahtpO/uk9Lq1aFNKvedc6zW3nO79mH65X9I0MKLIIFFgR5JgABhOjiUWAIdZZdpS5zJX+eNMkCNCoifIFBKE0u5cX0mj0WL81uHcoUgvjF2dMLv7VP58xBMZn1FEzkUUqhaqKdcoupdISbJzcYBuj/lufVW92Oue7pmRQiRICBKCiPxaTsO9B9uUFmiZdgfDLKJNEKvJ7Xu3IdzWDwTrm1dQQFklt7rKjb3D2KzDzY80Zp0uGiMBswafp0fAcAwoL0A83b5UOCVeThUQyerIwcIzmVLl0FAjVAr3KCNSIdSEu3cLwEn8ls8/uIjBYJRFXqquvNRimMYf0H54+HL0KxtSTwGu7gmDg0EwBIbKLoaHTBX0ExskiMbD9/Zg2RHYWmMhTH0YwKPg4HHmxpOPIKHEspkVwIqVW2eTRu06dOmz3+G5JIMyImMyKTOyLi05mu/5jQXnXmILKmtjWzrUq9bJcv9DFYImDhHN5OF2XPHtfo8pkiGXhWhVptIGW+ywfff4e+1ywOTVa7Iph/ai1vpdx7//X6zCiimmmafs9eFHHXfWfvUxr7vrMXADv1UUTOnqWeHo7vFz2rHv6sWadfahdbK9/19nLl+/5jW/Cr/VZnc4XW4PgAiTFM2wHC+Ikqyomm6Ylu24nh+EUZykWV6UVd20XT+M07ys236c1/28RFNAOEFSTBabw+XxBUKRWNJUsEyuUKrUGq2O1huMJnMli9Vmdzhdbk/TIFAABkcgUWgMFocnEElkCpVGZ9TwZbE5XB5fIBQxLBSYYHBCEeFEUuIQJTsrqqYbxIUybjEPaE6JsqCe9nQ4DFWooCsoOMQZ65x1znTnXXDRJZddcdU1191w0y1h1Lhzx1333AcGODXDKA+BDdiBAziBC7jBmRfAC3zQ9QgCIAhCIAwiIApiIA4SIAlSIA0yIAtyIA8KoAhKoAwqoApqoA4aoAkdn8ACRzRY9RK0QQd0wbksb8GlbO/AAAx99MlnXxLOldljv8NyfHXcCRXNcso33/1w2gKzVbLKHM38NEZz5bTQUiut/dJGW+2Ut95Y4+Rqr4OOOqmtszq66Kqu3/74K083//wP86mv1GrdNdBDT2v00lsffdOkkKJxBQpF0aKNdkEpZR10ijZejFj99DdAnIEGibdRgk0SJdlsi2QpUqXZapvtdthpl90WJltrsSKLLDHYEHvtM9QwwxU74KBDKquiqmqqG2GkI0466pi5athgqWWWW6GmWiZYGZI1k0yOpEbkgN3QEQBj3NGQ/CF4J4/0IER6EYb9EYEDEAMzoAHpQxzpRzwZQCIZRBIZQjIZRpSMIIWMIo2MIZ2MI4NMIJNMohGZQmMyjSZkBk3JLJqROTQn82hBFpBFFtGSLKEVWUZrsoJssoocIkUeWUM7so72ZAMdyCY6ki10ItvoTHbQleyiG9lDPtlHD3KAAnKInuQIfcgx+pET9CenGEDOMJCcYxC5wFByiSJyhWJyjWHkBsPJLUaQO4wk9xhNHjCGPGIseUI5eUYFecF48ooJ5A0TyTuqyAcmkU9MJV+YQb4xk/xgFvnF7K1TK0D0MAd2xVyij3nEAPOJIRYQIywkxlhETLCYmGIJMcNSYo5lxAJXEktcRaxwNbHGcmKDa4gtVhA7XEvssQp2w2rigDXEEWuJE9YRZ1xPXHADccV64oYNxB0biQdqiCc2ES/cSLyxhfjgJuKLrcQP24g/tsN0uJ0EYAcJxC4ShL0kGPtICO4ioThIwnCIhONuEoF7YHccJpGoI1E4QqJxlIhxL4nBr0gsfk3icB+Jx/0kAQ+QRBwnSThBkvEgScFDJBUPkzScJOl4lGTgMZKJx0kWTpFsPEFy8CTJxVOwIJ4meXiG5ONZUoDTpBBnSBGeI8V4npTgLClFPSnDOVKOF2AhvAiBl0gFXiaVeIVU4VUYDF6DhfE6qcYbpAZvklq8BYvgbVKHd2BRvAuDw3lSj/dIA94njfgNacJviQS/I834PWnBB6QVH5I2/IG044+kA38infgz6cJHpBsfE3l8AkPABRgSLhJFfErU8BlRx+dwAr4gGvgShoKviCa+Jtr4hujgW6KL7+AG/AWOx1/hRnwPN+EH2AOX4Gb8CLfgJ7gVf4Pb8DPcjr/DHfgH3Il/wl34F9yNf8M9+A/ci//CffgfDA3/h2HgF7gfl+EBCuBBCsFDFIaHAUXgEUAxMCE1gD0pFramhvAooDh4DFA8PA4oAZ4AlAhPAkqCpwAlw9OAojARpcAzgFLhWUBp8BygdKJMGfA8oEx4AVAjeBFQY3gJUBN4GVBTeAVQM3gVUHN4DVALeB1QFrwBqCW8CagVvAWoNbwNKBveAZQD7wLKhfcA5cH7gNrAB4DawoeA2sFHgNrDx4A6wCeAOsKngDrBZ4A6w+eAusAXgLqCgLoRJeoOBZQPA4B6wLCo4EjzBGxDveBLQL3hK0B94GtAfeEbQP1gYuoPk9AA+BbQQNiLBsGkNBi+AzQEvgc0FH6gQviRiuAnKoafqQR+oVIiR2VwHg2D82k4XEAj4GIaCZfTKJiMRsOvNAauprFwDZXDjDQO9qYKuI7Gw280AX6nSviDJsL1VAUH0iTYhybDTDQFjqapsC9Ng8VoOvxJM2BbmgmL0yyYnmbDElQNS9IVsBTNgaVpLvxF82AZmg/L0gJYjhbCIFoEJ9Ji2I6WwPa0FCanZbA8XQkr0FWwIl0NK9FymJuugZVpBcxDK2EVuhZWpVUwL62Gv2kN/ENr4V9aB1PQdbAaXQ//0Q3wP60noA0wH22E+akGVqdNcAxthjXoRliAtsCadBOsRVvhWNoGa9N2WIdqYV26GdajW4iAbiVCuo2I6HaYknbAVLQTpqZdMDzaDSOgO2BEdCeMhPYQGdpLZGkfjIz2wyh0AEalu2AHOgij0SEYne6G9eke2IAOw4ZUB2PQEdiIjsLGdC+MSb+Ck+nXMBbdB6fQ/TA2HYNx6AE4lY7DaXQCxqUHYTx6CManh2ECegROp5NwBj0KZ9JjcBY9DmfTKTiHnoBz6Uk4iJ4iWvQ0HEfPwCH0LExDp+FgOgOH0nOwCT0Pm9JZuJDq4SI6B5vRC7A5vQhb0EswLb0Dl9B7cCn9Bi6j38PM9AeYhT6DWelzmI2+hNnpK9iSvoat6BJcQT/CtfR3uJL+CVcxAGA/BmCYgwF3OImBRDQOg2TE4ZCCOAIyEEdCFWJOqEbMBesRO0IX4ih4hWlh2IJfb3iyPoQX9CO8YQSbbf4rtnBYc3ffAOj29WOOxyyvMS+j/vNTRiRKCH7qEclaiuKaY589GRP6vBKllqrk5U5BKmmgCot2ZQq5Vqg6LFL2TMwMjcipeLsgF2wfzZxq1MLes3hGLvCoPo2oc8jYO0d/qsCpG3ElVaZHYxGRpJ+SKwmDct4Jor5yZ7JP9Zf2DN11RYrcmlrKSVusThXqTyWlJ1kLaqI/tCc0pEFZsnfx3iGjOKmiXhEjqtRKiNmIKEwETm3qqpWEop3pQTgJFCc1hT4lcCnVg7Er3wKlnHWKjbVRyIbq+DEyu3hELlow3pMzMeTOt2FTp2GMigheKFrSUekv4igCooGI1BQOxExykpTVP5GVMmsmuEFFjWQuuBPZaNTJhXpbaB/jNE5e06PH8Yi9NlAopXd98gtx4aKranJN77jnc0zaPfKsK18C0vzzUF28x+N6XbcA+XB5qNaHz2SbYZUMaVzRBjnbE5UnSH0roWrVnVeZU5q7X/s2RrkwR0N9hmTx3YsF6q6Tn9oi6208ugO85J6HsJX4rWM7UqtEsGpId+MaVSlt7L1Ct0DbsWptdtG5EPH941zmIZbIXQff8gTf09LVlVuUwXrX3nDDqncBBhoW6RVyJcorWEq58yIuEpKImUk3F6WGcwv0QKota0YQfqqEt9tGPyBg5pgZQb2bNRps+AnxFtiuNUE/Pm5x2V/geA+axXa/2sryOR6AxxLX16yjl1X7lM2sVsrm2c/efX5SbDvvbM7ne9qgwcPjWPKQSselWedLujTHg6yBpcjx9jVG/IAiAVzqPfeQAAJNM3C3YS01zcz3c77ZyK2zCLsWDX8vKGW5rHTMY/MSRWpYD4+yNW03zMqX8S7+Dt13aoKO+tMBpHUy/YGE0q2fHAXPMJ78LnZbcfdggC7dfpBRk9QI1Et8aq11BItXyCyn0nbdDX5kjK6wXa1ENVzh/idsvr40jPUOAa+u9Tca+lt3h78Er/XyeBGY9+DpwXR8cBuLyvi0tV7hfIbZ27ccOc+h7wGrZbnaPXn6lTdLVpmO8lriJCFoanpgTiH8+Rp3f4f+r3zGbccscwmqCSDccnt+q/vNzyKIaKrb0bnC6BLYKUIAmAjMDqBZOBQvtp2X+k4YQbKMcoy2ErMBgUmbwmQZMbNHgRaI8S5UMEV8O7OKiXfLdDXeG+es+em2tc4d2MJM7kwgHxvx1no/ElFSzWq62+t9iF00ZWMQr80ss+rEHOAzPc77MDFxhouiezYK1rYPKHc978ktO6utCV4XGDkgZDllNz8I0+ioivUaXrJ1UtOwRCMN59iLjecBuSUWbBVqnBRuhzrA0iyls+RpttukttAhRFWpaxzIudS2lgjo3d2yLAAxrwfkclaWsC57KyAQDGnreJy/rDZ9eNjbiNTX3hEC2UnYh9AzAgdvZxvrKKaPzGnaJO+31xSgRsmwxek6o3aTooQ1R5EdYAx+foxE+Jq+l9jUM5C2NltzzgXWtHzYhzlSFV9xOvjalhCaftyOkM/mdGryCF9h6JkoRhabZrAxRYHIQKBiRkHNccWCsbhJcALNZTUm/xx3DBbrp9i3ejpWVvPcltf2em4FeIG6qUuGAhBMW+EdRAsGzuw04CoeeesYb+592rj0yv9Bj3my38q3yPndTxqXX9Mf9tknekDIh266Sc9GcsDofRjbTSGm5u1qvZ0rpNfM6Yle7aNBODZgqkOz7nWWDXpj/aV1/eEwDoAivbUUoM4MgBVGOGmNwrOH0EnZSTKacpmYOenJ80h573LTov+1RQNoCDTDwhhMzB4DKZH5gLSl4xVbNbVxa90/aNUu3n36+/fGY1bjnFnii3+zEUWvmQYkGAv9gmutUQxn+F1jsoOTrcze30jVhLvVnB3NlovKRivjPU13/aZ/+zyGDniy7d/v95K236wjREEqjm5SSMwj2gS630+RGlg0EeK7zhCMBRnctIHp7UcMFoCN77CtQQX7NrXLfhDuXYuOHRc8Zj+8duSd2Jg8xuITvsiVyNgdOhI1/kqYNRRamgvMC9Eo72s3l7Ip8t1fIfwEUrEhJA6ABFY08l1Zc/ZEIte6pS8WC5gvbfGnwjHZWC3YywNADYSGKyyv/HL5wbJ7vm7Dyk3FtQ7FR2X7lhNLMHTA0HAP0DI7MxhGMBY1EMNJJ4HpKxmQKTQDQGvzkoVP0HrJoLYQ69HXmCBpACIdoECZmKqa4NjYkJvqxO0S3bg5PxHehoGAf2xd/utY9L9n4H8uvwauUr1ikxMb4EcyjevOxbsvrYnCYmA8WH29h5PoEUQQ703QCyGGNDgJ/sBOWBxg5HHrW7hChRe+XdmXBQriKrAXmXeZgRDOW/Zqby0AmpLeSBqehgiI3kjs5i3z46nBaL2ZgPjdrKcJIUwmRpt6s+PdUYB7PnNWa30TvZlWbht9kCqSs2ydK4194r506F3NX9BDxtqT9bMVjZkkgNYdY1+mFIx5WnskID2iO0vrHPp7THowoO4NZgzj+sC6QpSSKZ9MBny0h7XHfrU7co/546/eIdGxaFkaHkqjX8hXqFauGDOoP4ZPk7nX+UmzqTq/Fuk9dJOabAZB2BYxx/KzuYxJjDR2l3sk8vyZb8wp0p+OTSKhADgkOUPtOyydgsd3hQeH549du3LmaFoF1UqlVCpP1feiMIhalXjcHr389u2y5EOQrLcCsb3OsJgJnGnbC06IYd23K3LhFCQonxHpzKaw0X3TV4OGdXlYqPTIkqwNzBNgYhjB6vlHYEA3ZcFC2MlLfit0gxYR3OnOHO19Y8ZPlSUFH+85eErYQ1UT6nUmJiTUJXpnW1SVnBX+eUxp3/ChJfsWssVDTObd5jLPF77wwrE7j4tBwJyjSm6G5Pb5Me1wG6kXPk7IOJ/0M9hm6O0DGbQqeMTN1gOveApc8IYHK+DhOmB/4kBbUj9+7WuBfPK7QJ/8iacf/lD423+OJFnCKHHpnhOLKIKN03Lreepxh0LgcEzAEbYOQwLLSN1zPN5j+IxH3lQhac1NILQM1CZkQQZfdvgRRFGAxu9ih34pyKmXvM7oCBwWzwM7AhfcWcv6YqQZTUTdJMqb7hfs4bZ9qzru5TSsHgt3qc0xSvnHD2HIyOT3UfpgRlvtkUfHC73Gp5UA6gEACgLF/2owWyWn4el9NS/j8jU/4mxSHf7xr6s/TJ0BQu9x8X9QvwjPH6pa3MtdktHt3F0+yLscHao6jNBDRw4Tuolgpbq2qdLD1BevPTjH6Ocolnd23lORZNFvn7xgAITDndP3o1mLsxMXTYBxtHvqnqTjbwKocy/SYCsbPWGLXR5xW4EbjoI59tdO1WW5N1LE+HqV3NHGCaT78AfOQ+L9QeB5HL5D3CpHbwjROSUShDB698tgP9i3/+/0L/MjB4r/NP7wN7RvLab/gR1cGF+p/Ov0Y9/WvzkvIuuh9BC7D3/EZm1u4ApRrBKcbrNPrVpcdC4cRw6LMeiSD2IB9jdMkLqXrluL0pQMzMZ5Tt73fZb6vWMHO9cRPSrhxOvTK+My+ym1duXf34dvtb/SvvjTEy7J2Phcv+C3oT7BP75hr5df7V3+ZXOXK+f67GCi9+B54nR4ggYJzekZuv+Fh2+2e7YtjYd2pQ5cY2pPApNnPiXdy2PbQIiQaT7K8+tPd4auzey+3B1jcdHe7hAe9I23OuQwFi86Bq9OTrodo0Hq7XRwD/unu8a1OjvSf644f66w+FxBXBalX/vA/NaxuaWMnG9Z3LvyHD4n0Ptbhos71xOWObjfhVH73Haz2VTaf9RK9RdkV15DYo+FFiVkDKU+yijA4ClkyNEq+8BnCM5yOLE7RRYqXh5zppweix+dc1theF1kLDcExoIVASHqiuzXVzlxjo8TXMYLXqJnZLV8el8UH2JYGuNN4FYIyQm9Tz/IzFcMnntOmaorbK3EnJRgDba1+OOHyFMDic6ZW6WM4RzIQE2JvPGdEsmNp4K3qdtt72O9T4G/aOW7xsDXcY8EbH4xodSgg44iTWjh+JnAVJyQnyeLMYaxUB1xz90iH8TL68+UgnW+VpOTUHMR/ePTKjGD3XA+q8Lg6OVtdYvtGOrip7HpKcC7rUftkcNsWxtlWdOCWGrva1ZnojGbPm3zLYUtiArLHaO2Mm6NYm4PeTkL9uJpnBHrPqSIu++Mq7/poYe1j2zEeR0TEigmqA+2wXYLj0EiQWyMgbAl43LWbLuY0NkzE1qmpYqsKHpc/DQP+IoWCIsalbhdCuvFF1Oc8vS/BxtfD6nPr5DrmmA7DQ467R8pKPedgG+uI4YIKlCCXwEjkCnVRkLY/4ju4bhLK5vdJGF8hHxgj5sw6X1EPdxHV2+Ge7gBzd7HzKNHiYtnCRUkPAQjD62S/QBDT4xfcPqKfua1sW0vRxHIWArLoTVHPE9KL0wrvWm385t2Kem0u9UJF5XNxQadtcIMwnYhab5rSQ6aNIBVFk4Sizbw4X4ay/ZzhUG7CIu0JzJOMlN7ZYIAaQMv1ZfOvqQzanhsZdbLfGUmwYswFeKsSaez74juB6v6q9Pcvzv4cmP5zIvdfoKR6z9m9ja1V5rf0wVQv8omUCP1YzfyOkU0LCCMidsOUcPpDc5stNQ2XHLp9VKN1MyMMj3dFNZ7wuKg6xAM9s3B04zZ7P+UoNAPBrl+Gm1DbYbp4YGFZsDIugrBjqpIFusJw4rmEAjjbcSsShVl64qnTnZAG2QWdcHprwFNEA9AVqJJbooyhkxQfM1iNnsLuTHFxeSmO96irrOIx+pmo5bRrHgitigdhMGpDc5srNM7uD9oO3e8e+799fS21+YUpjUiSAqo1QEwCrOasjVhS8rjusjlUEhVlTtsnKHvYsK9aozD03sBmLrH+k1QbnuAoIxA6X5LeNTFfgMG+z/v7eqtTWoyN5JMa8Jjsu61ogB7SXwtNSbuwOZ4xI2Aqlrcjq7v1lEVdpzztAadz1Sn470q613BTa3rAEL0pnZ9XoXrj5J8CtU+W5feZlHYwJ4FyBbbVxAIbFzCVpCsQ8flxCNc7ltXw9g9CEimZeBW+D7Pq5X397kvLP309XCAE6hiWhTPJ8wi9izN+ERDgDemmmdSQ/06G48CjAh6f209bhY0C4n6oJTqHsVSlar+9lq+3BJTnLvwL6t/pnym0TbtUa5/ttnZs9L2c8gdSLCNIJzZb2IzSJVcRPB5J21D7gRCmCKKSsqU50VdPrTYMcuS/3L8ZDvlH0t7IuFAMlQO+gB+UEfeN+scwyUEPUFQ0q6gMIe2XqnoBftZMN+xSRm4wBULROUbipW6Xqya9EOGa3JrAxCb/Ms3I34l0n5V/GUUXmntx/p6v3kstv+Z2cLH+lWcXG+qv6xU6qrf/NqocbRm/AP9trlJTklt3u5Ntc9+cBadvnQv//l1J5VhwMGCnx3YkR1GSwAhw/n54ma+7wC3QLOzHgaShvfyftjtFOLg6Yp5kWYhMM0BcRI8E9pctIDtztsI3DOCRAdDL/+Z/gIpMClkU6PvXyaAsAIsrG7PrhA86dncoUpR96qo0+BrWk1u6Dis0ozv12ssn+ghyUoOJA9Sw5tCVjTMZelASEum/iYL6qWwXYkb5aj8lzYI3cMOvwMxjD3DQA3RCDOcbP5p2HGJBIzhy3qGrvHQHUc0tzAvkO/0JN3B7zHIX8PconTaryVR3j/VuWn5ZaCNY9qatiS3xq8hAc24dpxAihEjrkeQtpgmJ0KkgUR7sN5DH/KoU6pr4m26zc/aqkXtqJpqGDW3S6cJlcOT4bX+Gip3HfZK/Qfa7TjwvqrFLq/BqSSTPAMOTdCvXfTzYGy0OeCTgHc1IdJqL0ZYfBjOz/1j+Fio/2NgEf96Gc2DHXBT7IpYb1SOxrGgfzRQjpHG85+ttjaV3lwdtBNrw462Vv9m/MP14XJgxrJNeeUMSt2epGdd5U6oVPr8WrDkWdpaDo4E8Z9xzWe1JQPiQE5VY+cCCxqTqpZZX1st8YZZeoNMdhkdLXKH6Dbte8L6QFdjvwYjnI6c1u6iSoqF0mq61sr9wR8WL6vXcJg/NdX9t06+m8SZnxeokFGiqtxd9V2oRjY9Z9RmjVKXPTUn7NwFdolwd3MvykGfNeUrmAZaFc2S1SWznt63HozBhmhydkIdp+oUnA5W0V2r4xnWU31+CJSbAHviGvuBV+c/Yv9iz+QdpaGGrDdbGgYIpieRtKYwPkg/KYoAD0lYbwLdlvzSbaaqAdi3uVHZz8lo2Dl9/+mXS3emGbegPmjCgGGB1IIgjaceCc6eOyoRUqXEKyA+xord4xtGFUhdQ9Jipj6QUhKjSsdaoKI0R0TGGn6/s8Dwi4ZXCRKU57hcGxzMk8Pz270JP9OSpGrAgVzU2PATnE2XKU1s1htgbVSRWFNAY53iQV6ut5M73+HbZvY5Q+C2TfumtJEXI86NjOcG6aA2zKcLu1OKfPrZCa6gm+AuvtaRPFhHvUL4DpFQxT2A92SVqAo7VywbdTwVO6YCudnCc1KtOOCX8X4rESMS8S2mlvxHLtSlB2qM3XMIEgg8emOSqMUC+Mq2xSFTjTzRGkKXTIF5xEvxHuHpyyD2EuQxNaJqBdwISsqumARj6TF9bRTLmqPHW530fnZVi5lO7qBShnWhJnBj7A7Lp19T6VhrWvB6F4zEyverwiQ80oEGxNs9KDURO2gy7IlUbNLUBMxEadlVNWNIGkFEqT+k4LlwI4bEPrvnxMhWjspHLwA49+DTjLJNgCOpXZwjeujaIeSUO6/JEFwfbpAd5xkmWTExH15CF2oJkiwqZ4GpDRQ1bT3JT4QVqQc4N9T7kQBiwGOYvPW5HsPvEsCcRbA7OBaoLXokGx+UsY7uSMl/yay3dmKqbb8axCl4OPtykGiyQCmav/x6d2wnVh2Pctwd53sjt9y+MRQWoAuGixHPORxU6nSYeLDRVmAyvwsBNCS9MoA3pdP1RRW09oMpoBaL7vpZc1C7ff+4e+6cNXRv3FHqRXe+e9W/Hh93j0XXvCsdRX7/U09bmEDo1zk1mPRYveRG3abfjkM3iFpeo1NLuxHsAmbEVPViPinIJ8TmDl4xZJiSXMSUe+2M3sW9qse4eJ6oTIRV1rGrEPtbT6lySHNDVpR/LOsXVzgKN+wGm7tTjakDaftsHYE717lhWeIgOoehl4jWsEn1YDbzp5adH5zG548di25dudI5c7QJd1cEDW6hvtCh9QbJd5Mt8ecWebQvnV/fb8CSr5SoR/GuKD98khwD843QOAYBxNuAByUTv6CBZc9CSTyi5dbq6cuJE0GlvSECo1UycYu7H0+jQgEo7InNKvzt3jzCb/UCu8XmClL1VhkJXNJJuwmXpEUtLBW4ioGplfXNrkXvnihT4DsUtm5z8/5tG/ufmFNBW8sbY0pR83PJNgAFIIogdqh5Qvpn6MEIQCekmQOJLsIXhc0Ho8n7Zyfvmp6a80uirOOwDS7GFyHzKmy0+P/aIXOUWLWfB3RPdfmyVSBQjZuoPqN6w+S+xkYtTUmZMH7CXGAXTKwYY7WB2BrJY3lwY0F5zu5xMhclMuz6RgPENeXEyZPj06dMqMKt5KkNon62OE9hkn12TZ8MPi0NWszcHFuQDiwpmcVhqQbEAhHOzAkwXhcPDTC8GG8II0vS0hGBZ7jjU+QXkBXjdgJhaEC44pRxoNkSNxwOF6c3FL6mNCykWucRRJUFGFFMtVmqA2L5SdzFQRrLITMBAgNIibYSW+9ONl1dLkFv0EZd1SIlcDL9oTNgUBel+iTvUQR3pFgtYVXYFwoHadySfYaSLN9C6kE4Umd4DlmHBDgHvWDeDVl4ZnewJqxIAVgWI9hIQtihQgSsAxJFiUBmIpVRBJqoCTABxX4pzsaGxlySRXyq+hBCCYiiYRyb08HkGG3yaP6xuysuSgHxcQm082oCkLwgppmuimn1njcQDTpvtOq0NliyCRs7d58KpgZ0AJ2DUv5bBe8/XabK18aa6H61o3vv/p1mbFN68LcXPjZ4+eW24pY1D0Wlk/DfugOT8+NI16pelDDmQsJ6NwnB3KpfdkoFU5W/eJIwsAQzIlxYXDik0B/ye7v/A86d8MkEw/2SaoUBF/tPVs4C+MGET/MPtsz28GGER3Ana/s6kdlfspDhtoRsFKvt3r7m29HDXMqJtYzljrMwuPx90HkESQ+GGbjASvMnY/EbJE/C7B90vQkHCl5jh10qprVlxs4xWE40Q9E6lKl8lnc9YumYb7DunZQXA6Yhma7ncp37B4XWwhagXMtvRasmtSLya/rFqvErM780sLathjtiIuOOI13GE72htHQiBgS7JTsD8g97nF1HpYTmybUbCgAMkMMdiZm3BAfGuvM+GOQx39m7tcXj11zg9SnSs6hXv/z4d7rde/KruKd8EX+34pfjBYQJ6dkUWA2nxxJg17vWlW/miNYMDKNAmWKZdFSGYevUv6n2sprjJDW/tvUvr8mF/z5dR33N3grEESfaixg8wDXt+z3BOfKczxjr//gxgRRhO/tGeLmpQpLnuWG4O9lrkR8MlCpxqZGq64iFnbrfYwgqtDbtXHYVIVF90LkQudk+EWuQdFoAd41lOTD5ujjAUL2mxk0m4spAnS6A99l3CQkmvq6rfFWOUiv+Jf2r6l/IbOo9qoojjhtClXUuo2fKqB+x2Z6Rjb0Kn2Ao0lNpHBttrMNY3y8jk1fWRgmHI+Zchge/6RNN2484q6YOaK8D5w74tqMFTmaMKFM4hH0mPaYq7GNxLoOpp7p8nsm7zPVoRtMUxADHMXvm5fWz2dk4ZtCrFBRjG1cBIftc8DoLPGOASxnZCQuOeQdeRWJcUQmN7x+5XUGThwBgAI8ZK5cq0CMgLGrVLEi+UoYbDKQ8AsYEpKkJipFFt3xirpgwEWlxV2KvO9SvwkQJqi7d3MT1PrqaIijU9NW5VjueBuUZpcIhkoHYzCjtP7mJ+Xk0aN4kXDfNCfV8+59POW+2dL1Wh3NSZ05hUA0qTr24oMX+sKl6OGyLondPrkTt7znwAfJ1rq70LrfySn58gtJVSXIf6Z8l2ZQCfzxBG1yabExeyHG0GBNHY9JqcJg0cavB6tD6vaHhdxl2f8fzmtD7fRPgH/2uD7+9Li+b6FtdY0hGzXbJghDV5WeB8gzlMaQG9mEtkiDHsdZmsYxddFUf9uCIlv8yYBTUHLAuVLi25V6E8zGNMzqaaI9ITTC4E3DT6NaScDaxvPl1sIIqU2MHXKIaB8IpgIChy5BRQt6JUQuiCJQd003iiDprK9XoTxAV53bUMObt4QuywkvrD0Ce2MNh5wIPzlTwNqRdaSN6Jp5tfzF4hFxylBUHlwMxtXe5bBIhr5/EIBHAHz8YYgTZ9+QYmRFCVzw8UsinzPv6FAJKHsimkCGCIDYeEnKcpzEcW2OaXRdj9P4KLysTGvtVU7RsolyyXAZPx0HmL9BfBEg1ZLwknWVCqgsO2IkjW8k2ETmNKNeZIZgrwDaES6/gvJpEFYzOiueGORUdC2UTDsNKg5dibKCAaS5usdamVzACcUFhGbq2OgeAJkkKEYo/NyHpD94rwvpTo27ij35k3WQVAEeCu5IFXIkdx2CPBNNp2UN05bzURJN/7VvS5Wtf0RRKrcOtfl+lKlxGCvaTwS5mdQ9BGuQB24xSDB7PG1hmWjCBHcWZ9nO7DZj8Yd2NoxV0SZwzE0C0F8HYhCEUQNMKLF7+C/a8Fn02uQyHQhPlurzvTdUBCQuT37NlYmp8OhXjokUKlm32B5HGpR6oF91jNrWFW8hpw+wMBeUzm7LMeFtsyCshg3zDAY49ZgpRk4uzDvYCBRq2KN9AVQYKDIATGCk4AyoFbKjDDSGfCft0KpC0F5w2d3Vna8hkoifoCdflJ1vKScbl9ChaSPGcHq2JoPCWhpAbi4yE3LsqCt8z+gCogMam9lMABzD8nWZULuga3wFOwLO/7/l+6/vQXD4BR/t99DXWt4Ybp2+bN5xpGeEP8wXEIEBUkDqwgzfCMrrwB/eMUnCH/9NTjeqpgxQ8agiU9cNOWKAmDutwEpl22aE13nBGdgmO4rNZM5xXlZkFhmXYuWQml38Nq7nwr/iRQCZV8BU1PuWv1LpCbb7TFlOi/U+oeUYOQGEFOA31MfhFgRwSlwbXwpQKKltl04JzJEx3NSI1WGW94OIFNwZTGFDhxtT5ArjxGppwydSq5qjti+amuqDVCKj6so79UBUfLRj+cXYtq6BGXNAHjKxUzAI/rwltfwhi5ObMz4Sy2hf8ACle4Zzuk3CFKnxwmFazOclY2cggtQdZL2XYoP/EY/eWXRXAvrDsmir6BXQ4J9/D8ZTtuGWwpcCGJV415CM05uvq/jAPAdMGorLUBt9rAgwTF5bHtUxbCFl6kQr+fpFZWeGWSDbrKh56bLOUJO06cqwgaMn5jXktB9fJCezMCE0qcnpathuY6xAGkuv+LzH1F1OWhO//4tanICCNb3m5ahbdY2sStOOAHAuQGGVmUSCAO7t/y/9mJTXvHLLNq5jKKntxrRcEZ4D9+9aPjUJzl7XVwim6DYbEqmEXMSqi5Z+LA0tGIdyHceKXE37FEau5LDAjZ48OkBRI9q4ic/XQp49LL7BChie62+a6MlUGYODfTGG0m24ndQX3CtSuht126sGYSR3FCqq7ZgiXDDcmLoTceLvfOvef3jguRf+H/1fsUbXmMYIcgwfQuYf6mFH4wBQRsvxQWBEyoRf4ZQQq0leO97Ewjf0I4YorZGATp8U/oQ4vZRlyIOYTI9VduiQtdmyZW/aPFixKX3533TkzIP91HqXhHuNya6aqwMfDQfYySmJSLvX+ZDM0QGYLzvR14bls7N6m7gwtx4vnb1PfHMhHigiyNLayS1irJvd5npgPebccNbYVwJp70NtpKO8IbpKZ4UfZNcvA8Eeq0Q55c3vdbahnD56FrmLXzN63f7nTVhPWFzqi+WYijD7o88f74h3K/sT3W4t8chmCg/ssEScXERbh2AgQRpHWBEnjA6nGeDYztwjb/6awBrHQc50s9yKtfOwuXYXrZddxnTRqejkHKGCLagaWPEW9pIkXf3DjJbUjaX9iCD1nRoXGSlYuHrznI2mcHGrsV2AlsZrJLTDy4GE23JqIIHpiVp/CFTAJ3n2kQUP5N6YMo1nCErdOPlzYajdGO/D+D31THjwl4YOntG83x2ITGBESs6wMy7aMxEObsiuk+DJ046Jv2yhdQJJh6E3vPf/9a6K8L575QL9IfudZ+WUt3iZPvX+14sovX/4ojoVcQDQTmyd82fXKqsnq67AUHV/1RU5xPR6J8nRDuRMIZaiLLxcJzOnPt4jPVCZ8Y7SDTUFLtWrz5aDhVSi5g8f9J8n7xPhXiaTF3x6qu0Eay+xEh0QKBPBNFsRFCP4iBB/5uuSd8P1O7NDfmqwBgR/J0xDPgu7fMAV7tQYxn7js9j0V7dtmHxhwMzw3bJX7G6J3fyc4NG8emCtmUutgyEC0bd5gcLHHjps/0USItZ1BZ4G12YfJzz96UO85Nkv+88dBJr5vFg9kAtQmQTlM1sn1YfBd/yO+Dw0FdJMPFzW04L1f1KVWHTzP7H2Mf7XC+sZsVHmM2/ed8epC1bwx0mMGmrF+LwBfHwQa+vXvTom+9eBLPNPr/NM39qUMrs3Fm/Whnxx/4kHvMajTk8P85HhrZWgyDUf5qXueNS8iJeSO3cDa05VmL2oNWIgEZ6g7l6kRtUdyUXb2QzaYUngG3BjYOZ3hluphIVbzPCCtBUDX/ORQ8PjqEsEtiYcdAxMLJ8bgw0Ut7Drf/BUf3/P5hOC0fHYb077uJSHbSE0MeHivDvf0KM82aVW4YYycd39h2gN6G1F7B1ctGQI9FCUz4osYl7EqlanisBIAFa5NdMpmhxxelrbZ4vppif1KupXZW5tDsbpZ5Sqq1xhh/MgWqcVMBwLnCAlA7nWRYUSpXlkT658pAeGeSfLdo6+2twdVaEz/GTGZ1owFEUQDfZVuAt5c0LrdpGlyW+qFYeGfNBNxjonPSbajeNJcNGYfvo5Yp22GA9PVTKLyk+n/0iwsA70zFmZRSzUNcBE9CB8Pov/L2YcFq1TF6PT6VXM+0gZOei1X9MZbjKAaDyu2hmcd1uYR8HU112TI2pKXhe+9ABoPKgeMzeCAB49rNLJH0FFvfVcSLlDxCiVaw18P7PH4ddjfkycxdB2BIZqQ1NiRkNeAQ3bFWq98IS06WN/VRPTrD9PtN13ge40S2Ia1KhSyht8wxNIyEwfroSTmCDY3f8ZQP/MLatoLrKzphAi/ftxnavT/ovWbeRTU2F4u7f50eJ5DjkiZM62sXSDRWTIWYE1sGI06FyqMROCySZCABhzMILOSueZkIW1P5cwE/iKYqBqru15etlYvdmHTBdqFhKURZv4wt+9CGefldEZ61Nq6CHDkymSzWS6wFqyk4WgphwQpEEwyGAlwGtmpzIl0Cpi3nQfmpZFnH6TVVr2C996AN36AHHJLrYkg5n/hW4iwtzt8eIqN53tujkqsbxUFMIAxJRdhF5t7V4tBpIfDuiX96v+rsfdq6c+tnuEora6jvjolPJukU0Esohyi9ZHe0RkCergcVGvr6lqq+upaAIRjH+BPxzkUEgFEY8S34baCUVGnv+VLFuCBJNij1uKyJbseYDpzDY49qESRVhB+xZPplJOWJ2m1mtAccaTkpQPrjWOa2cv703MyHZanqZOH3K6OJOm7o1NLl8UGcRgC3CHHmEg6dPhGhlj5GSiwBRJ26vCiH4y7K+cz+9Ob2ojjDC1oA1tJ4vVdUZV3cHTUrwU1xpquQshsa5CSdtvmdJD3MT7dmSaccU4pocFMMsj1aueDDj/GadFUCHEWkXMBRE644917+3XZ9IdNtaJWH0QiV4j2P3J7pyQKgNfTvuQDqMUXwp0LZ7fOgGEvEEYvFBYPTZFDnCR5afFzi49OsaLSnirOo/8moiDS2QSl5Uynr9ySI66JoKiNO6jUf4yNTXoxfKY2e6qf2kP3oSN6vhTVQ938bPNO2qZFpDy4aQOz31mC0n1qitt9TD0szsBq0R7wlxyskEUjovHJTy20OnR5v6yUh4zwzQGmsX3TFyjJRzZz1XDh6ItEnNaWjYOPAmMEtnhIQkhrW/2MUtRVPerZxLepAr0IfvHLDdxRKtgqREDrb/5Kz5es9WemvD+1qYLt4v2JCjgfGjbkBQUhOdTF3dH5FZSwFQ5cPlk2hop0rTt3Xem3jyog95IkZWKLjHK9uTE5lacpHUjiSYvDnFRAELM7rcLyuUop3b0bMZK2eV+02GUcaiesV1e0vyACCCXy6Gd4Zu/eujOoIjdqLuk71mvUUmdXLvTlBFfYPJqUGELX5UKcUNTPyAfsNnM7LcYq4aPPmSD7Jz92kE0M2pihyxUSctpEJPJYua/KcNy01Hqf6oyYRbqkC16t+GKTQu3OAzEjrJ3irMkYJ9Ildlj+RaZPXe6zCv7KoQcXoFCz69mftP2dP9O934SJ9/DmlL6rqsSa551fZHOFRX0kb/Y81bHVoUUtOqce4VJOmZ/KTrAf3rJkagYrMcVlOz/NUeZThxUXNPLAfKgXRx90x12S1dOWVKQDuz4AnHDHr7QiJJ2lTsihDwQ0xb6cKRg2404ScaT0reRPdJIf9K3ZTufZJR2hCFQBXrW4TQvrMw08eTMrMnuwnbIlseGlHnwz9gbdXCb0IrrVa6L95AbTJLK/KAe4YwDZ4vWT76XCGsIptVfAmtfHuQjTWV0yGwJyJ7PAz4ZBBuYxDFs8zKrSmL9Tl8sB9VdOm05ag1Roa2qDTw1WvyyGD3vCSTnIOHel8OnPvOyNx4uLxmlkDs7N8djUAl3grIC9C1ZoUDD6M0fI0A7MrD7ybdt13wYeA4w1Omw7USo5A9x9gAIMGeJGM6B/1dgVkAjFFhRwi+UBJOxTisM70TQkBhSCx0/NLzYiAVs9s5K98a0aQmOH4+ZT4+JjN4rlt0tKlcHkfhONoKIyCoDzdxoV+65VHlZvm6XK6NhJ2xO4nF6adP67skjwU+h05UYkYgVA+W3Z3pvhNlXH9JY3u1VgF4KQPAjStR/Bn9QVKHwMJtJsTP3wt3aN0JFSAEHpdPf6QbLZ5cjPjOUdfJy4QINpmZS5AiQMNFKbD9EP+ao4MsosQqoMSqcY3xDXLE5OCO08xD8dLkmDhcKmQUuaStDHM7e1OwlxeSUw/aNf/Uqy/VP9Q4u0oCkyik2yE2pR7e6jkyHcggWb4xSqKSd2Vw7+M4g/eh5hB8IrtsJKAM3iuXh6Jc8dbbFgCku/RHkryYn9SQ7Mi6ZvT1ZzpaMmK5COtZTJ6NFj+17P6rAZ/oF217dn6ZVyShvolWwJNrv9dtEDan476/mqTcd+JyrHYForcO73KpeYChvWrIDOYwgOxdZGqYgC1cS29nDRuvqNCD8XKlE6hxVqTfndfTt+x4PD4enKULRVHC/NrBr1FbNgybFafy6lwuztLoE3tLwY+67iG6Ix0cNx2lpIxOMhlTv5AXKtEEyOlwYH+3YqXsrvGDb+z0meI7xs/IVjykQLQNXY3DlqvMDJClvIbsvIL/W5/2OSnoH5oi7AqietYlmsXq+zrLx4YeTpTwzfd2Uw1MF2jMaHe1rAqxkf9Ngbn6UPn2HZvFBkPcpSt8NAYMHke3uQ93lYh8HO0hZE4wuBMW9K47FD3FjAZEbq2jSm/MRFq2zaFVQr7fpVUayW1Mvjy54VhmcV9ehxcUJIHa+zG2bzuMhlufBzjrjafFbUJQPnG8tCWqHX0gl1ic1lw1vNiZF6KMOt6sxijOrEN2Kwb0reiBH39Jr+TSp9M5qUlQ2tlbPURQ5SZRM2cpLLi1jOIB/EAIXWgx1BhxkWOJtjyF/WfI306vOrnhVr7mhSJLFAL4jyBzoaJ2OKe/d3N48N6wjEUNh/CZApnphYy5ymZS6OdKguAnGuuFrvaj05aawE23XxjH41xEPhGkgFFgabSlxGWZGSe0JhiGG6m1Fu4i9QYFZJGwN99KW9G2dQx+s2kn0WVg4KrsmER38Td695c3r+uPbU4Oo8qAPQ3WjJHO477vqV+CN/ym9T92k/Ss12JasKngqyPwwr572xvKjNvBdag1u1far2CagtX3DAFOVSpY17eY81JbtWsQdsu6LWqjlrLGehLssL0gqxz7Ba2XUSgsPjp9iZ5N/Pqp8kUuFsICuz/D8fRQpWm5t29kmnVonzbCOeU9re4+758mO66+ScocGf/ec7gfrteMaVmLi/63RJMnk9PM14FjmxqcnXuJ8PdlWF14g/u67JM5AVM7fiL6y78ouiNDExAmzwK5JE+SfHZyTOsfEpE85lTk9RWQxC/liY2F2F/yyGXUzocPCuKJ0vp5RTmhLfuIwuj1AlZ88Z3hXj12++jtYTwrr5lTWUIIc7XzbHRdJZnFIekWXlNSp8K3zIGQC1Ok15d+YN48rGrhSVXypVJ89IamfXQgfIGjgsSsLQD8ikXZsUvYcmSoS/29NjtDVh07b97nMGuFhIEbIW28BFoKSUiuYJEjHeoJU2A8fJLRedc52b0LnhDSdI92+wcKQA4+N46d35rLtIOlNC4Usn8kVKJj4wMvQPnLHN/fh1HEyqvcXiXzmX+bAdwvEBTDqcEj6Go/H5P+c38KF0gj9cg/FtXcjrs9LaK/Ts5ithRcHo3CSsWaymVXgfrxK4KoC3P7bOpk/raJxBTO5hyNb/1at61xZX7itzVA01zrxTFxAxluXk7D+0TOznCWmVNZeLa/9ph706moCnVKW/n5yz1PFc4/OAe0oVxOoxb5iNNPBzqlBoBW9w8qfc6d92KyPz/iJUpzmRGPpvg5hF/7A0zddiGxOlIRT8AxNJiW4lstGr9MGGonTUfbPiVAtj2NNTYaQRAYJqPPiKnLB1xj4T3+EupUygxrxF2XfbSwTUHHgaRYjom/XUVwmSM70Yhym225FTAzEgY1zoVLE3yBjFFCiiIGC9TU/IlYPvhL2TJoTobTNFOMu+oyUQ0Ns4k+bB6aZbIhgVXnPK2XQi0dKj9qNaIiOFAoZS3+vqtQejUQrCCOlTEBWzQuU+LfEpRpj0ETpRFc+qX8pUiwDykJ82owgjZDzwIjTy33FYIwAW4zr8Fh8Y86/K7WrIVeT2rxFPREKAoaemE6gXSI+h3eKxLUmI9mAhZOaHUdDHdwqcTY+ceEKuHrwe9k6+txJEQz1uJd70CB1weHo5vrvYUyrb4EwGdZSCNB3zMjZh+m8oRlikG1YcF+hPoFXjD1SKH+IsK1bmcyRKx1mQ5+BAkzzADJ2bf9qFN/JfEXn2hySG9HsKDQMZI4EYdlFVJAvDGANGgGQZMMh2cRHFQyKXGyZg37jAh73ORenhM1FxNTWQKCUGplZcsZNad/ZEX1JaLsyEWSrUObPw/Nr0EpTkeaDw2CtWdLRtrHHuDe8bdyRiyZ0b3q2fpiKRwL8LjpUYkjtV3RXT+LBmUY8imjpLZC14KggjFQ3wliRyBw/qm3ypb5P+YGbxOOCsvuBr5WBc8bLc/xYHa/elhuaoc5/2eY3/y8eqwlkjrVwA3j1+Nw5QqaplWUzr2T3Df0a3J6JQaTcwZYFgmqQIwNn0YLAIwpQ3pXtZ16yndkywhAglCg8IKCIg6616+AgdQwgQL9JfIKuGYigWrL/Jvfloafqn5Zmby0tLKXSdlB/jKkcP+8tS0/bdD5OeMUoUdHUi0KbPtE2YrMQp17xf2h8UpFA9AkWJRTuJTUxlVcpwbfzWUkOVqMzAODALVJGqAx/DRYFgcbtZnjdmamlpCkNxaSlA+a3yzjOzzbgV56PtVZ2wXg8b3bkAQPlLUzYck/Nj8FYQJYEvi7x1a1/KqaFnj6qkJ2xhfe4azGWWV2QBiVLgXj7lfIBklDCJ5gZxmUbGJ7dwJVZrSdLcIhCHnLOyLJZ4Ajp3zbskSYoBydaBmLLx6KNexvd6N072terv6fGj51EserAFbXmQV8k+H8ayikBvhSHRepSOmXqdSRFfnZlrm4jU61rXS4jOTUdIb51rryRFuIVLBKFJbOg4+gcAEFRR3lm1YWVoUDEFztm4MSdpeBEwpQQVT1Q7RlkNWEUliB44xoT33w/SB9knDbGOkj860urAao7km8GJ7bLgafDEuiWCCrx5/oR0ACjliduQKODAkiCBURlhjJhY9IlMNgNNdyG9JBJEmGRBAZGyYAJKWAqAb0B8XpEeBlPIz0aCZ5B//0UmPbMAcOZRYH7caHzK/UgnMv3vS70TQeELxFtAItigVq8XkFIHElVlcGcHVEaiAmXweOF3SbDm67EjcrA3h92MZxrHRYu/Te7EkL6TfUeatyuDVc4iSCU3x1i9nLvWTODbKgI8puIjGhHsPCXMZQvzasCbw3z4yi6LDBo1F7YbkKiNgkayXdarh2ZJkByP+MTaOjimn8CEXBtz44VchGSySAnhuY1dC8Gc+Nt/MjjY+sQieCAH3otczKqlF48io9DTzZjq0PCNImFmyplQ9RefT7no3tPfIoERMzYzbqtnC7dEIIlf6RJDb2bI883GRWdcogSCPL98ZzjySE4z6ITPVcJS00T8se9tY0R6B5ZowkgZLFSanR5JWpDlo8dEpA12GWp2A3i3a0gWbARnPvv6gkEfeNtsUBUc0SoSZ6QelOyk+e4NraRGWJaDxqPodFC7c2I1eWcNJpYgH0uuxteQdtQgckLsWIr3D13FrkOd7mmq3jXuR5sdMlT+JlvzuuNW5lSWS3OeNwR996I+6PiSwq54OCv5oUGxDvnjuP725F8i8gaH1FyLRqYw+ODp6yE/09NCw1MsXi+uTn8FtpC/kqXJD8EwtobIyRDtIxvmHJyVRB6PzQNTyNI1TB+cELNF4pqf7UCPYBJrCB4Z3vtI2HgpPRxX5Sqm18VEmZ8c4CJ9Y5pQoGu+6UbdaVcXv3ZhyM3hrjimKrzoyfcE9PCeemukTdd6oce/R/D0PTV1PeaRii3SOpfNE7Oy7jt7t8yaXhP+7xjp8P1eOavF2/n+Pw9ef72ursluf/aFwizLLWBWXWxUusvdvbaFLlHpsXVLW5qefbHbm+rqoFwUkODn1xfRd+eOI9KRmzsU8e5ITWurj3dUBZvz/fsPHi5pb38/x8fbZhvzTF7K+LSh90lWltY5Zs95SwuYFTPG9mbAW/akcRTIViBS1xD81psBNvv3aMOe7xe9XnrkROtLqPGj4JtXSmsHprvFfhAScfODWLJ+oPbylpDgjwLRS617ki6/vmh9aLHj0iUHNH1wPcN3+4bZ4Wh7YOB2pJ+9YbvvErmkIsmqCbMmLTosz6dQ7EFJpBeRlJ3iwSLERZ12LNNFEeJhsW56M4gKnabITglVJUIJkCEitWRDBERVrdqHRQlZc9kVWSRneVCpiniqUqSoKlJkrMYCWVERgnIKl1sVSMCwjySY8OoVE61CqpauK6oTHijwGPRWPUa/b8jJ5TuKETTyDD8bQUAZfW77Xb1rLd0+vRmcv0St8F7ouGKfh4hXqR/x6+4MW/I3Ffc+rAzYO7z86mclIZ6wMdNG8qigYIITcdTixbelNuPsnGN7NNhSptN3Ksoj69S7lqGzy5BtTk4dp0IgqCbeOEis5vEqOH05OR9/aQ9rf+zqRvw4IT7Wm5PTV8Hh8YjVB29UEwUCTkVdTh9/OcLq4kUBqQUol1ltQ4ah4uLAxGbNzXVMmOCYcclNcnMvXwY9XrXKIcVo79sj8rEog01NxGphWrQo7360D02dsabQq4d04a6aSn2i7y9y41ObPaKzpz86Cno63ms9mvnqsV1/Kw/04t4DhX93CU3VxRITfK0cubQF4SxdQ6nKdnrw4PerU44FzOgI7Dh2jvsUx55f6xBsOuj2NPr9wXGuf0Vy/KQvfIykzgg4ZpNz2EcUStM4un5FiduoxVWLatxENPEQ94nWz7R0LVgKZy7rpdC1AERJQAIh+McU4cn3xgOfXVm1uLLSfY7zh/HhoAs+lUsXV+2B48ISoWjg2Bcx+jp6e+3U2M18Wof2ww+1SXcsAFBeJY3fvA0FXetUEgg3jO1vwB54//72hv1jFoElTv3AfAc3ieZVmZXYRRvIA8QWiQ84MrneqAcWiQGi2GgDid1sErY9NkD0yIdsqZy9WyyXMv65KnRcHYI4AWwfP//N0qz+sU7xzih4JgO/WTFiy2KZlp9l0LMkn6z76J+h39kyLE58+nTCQmIfS0x2ujVkERFvET50y6kwhiixX9EKkWCukUjtpd7Kc8UASPMnymjJ79hi1adt1y6e/gspvu0Qkb9OL9b1t/dbbengk+bUBHSuJ9OeljxrSPI98k/yo6L4pUmMJK+KSPNKdKVRfH7USfjRSshW9lGOpSwZVuZ+61OoZ53spneflFWUT7fcnbsiK3VMYj1p4WJzt28mtFBYECiPnm/QXLw4E/LMioHvnG02h5oFxmQi86IsyPFdPBUo8BKi2GPQbSrP31jB+OlV+kGRcGn8MB22L1ckioDE4CkCr7drfMNTQhUeyQhESlwZkfBEkqrKqiTV7MpNAuOv/KhcLrnkFoidxnJng2x35H17Z/Hkcv/o0P771t2hd7jTu32enn13eYTRclwtTKWWbcHLsRzPxlKuaX6omsCnbIyolPnakczKNsbVOtU4HR4dgDzVf1u930t1m+pe6liIq5Fle3oYlwgmIIERr1/gXUI8nBWfLki36Zqnn+BP0kwpLmBp7fjapQFH8QLwIZiar47QVHTcPNXSwxWRKWdcHUwtAJk+cZmXYrpOojKAEX6al38BKPP9W11fX0nxxIt8tq80ULn5lL1UAVD4xwosOa/PyfhTOi+fo1G5X+URYDA0w9OgXdKLLzRoC/HKeUtm1pgx0WapaHN21oEoFnO222WCRC0p5nBhQQjJGNtwPqJdmCu0R6x+9kzNJ5x1X8/6sRuC7pYm1U5bHv1ZUX6x+UvfKtOkjDRrpGn6fyU0cYnzykOLx731+Kxz2nTTDM+zU9MT086MzoxHP45KmJ4QLPYfeLb4fqM19ohu3vIJR8aPquAlJnmuOyJ4lO9K8srh96Xfv9/q3XqstXWWic5KTZ1NRTRNrzcL0E2GD0qZdK/EYBWRyi+5vhzzkNrNOUMgNWV7bbYpo6tiKgqnLwfRxNPEFFAY0tzQ7wZEsrjyci5rb4xzKGXx0muzdplDids8ZefySwjLvEwQCYNY4VkI12l0YQSJ06cgKo2kGST5y7WYc9DxWpyZpy7U692OWbyZYsKsu2trr6jzNI8bcmzu3mCuUGCwgsVpK2ZxBy16aw/ovMwVg9Z81wYzRZzZme6t92M8R3Senjoge/XYsN2Q73sOTyaPWEBpUKhn8nDN9ngYumDYHhAKigwJs7CNQjwq6w6BUa4D4/QBSueNmBWf12m5WYnAl58ozc971pe++FQqkyolp04VmpJ2dnh7r92cJ8Sq/dRYYR5KQ3G+WR57b2mi7XvvHF0xB3K839smfvJszOa8l/Wn9SBgqTFRTV7wXiAr1f/HHvbjjnL9Djs8blSYRUPZod76CXPccdzBXwl4UzmjXP9Djv8r2W2J1eMO+VcsU0nKFf9Npo5SPf5LPN26R6gYCMPk1XzMhohkELosJHj6eBmR5r1ALAbGgTM9yZXzikcGxgaPFL3x+S0RGginTrhQU3en4zqvh435PVukdR0Ny0lHULoFDVVfvd9iL7nWIyGesQ3nQ89DcrqciICNhMxg/v0XY/CJhQGTzxrqb5OYzXegdwvAcjCrRvzGd+QXFRpJemQBkJUHD/ARzlluz1qqgOUnxR1qEG7G9U4HW8imDq87dRKn0ug1KtzUujMd5w+H48/TMHp/BCE8a9v1lmw9PbLziR9ZYLy/ebN+uYhgnZSYfG55b3O2Q8mpP0/I1B8/+8c6x8btDqsTAeEdAa/joH+D6Xt0g7/+gPMoFQ0GVIdQSvJQGn7yTVh/yjf3OF0jfXtdGgo1gOXZqZoD/6MKlIoIfnqw8TTxvbE/6nOubhyds1tSvIXm2/SPoZmwbwwv4sjcxip58EIGVtpCdv32Ah8hWpobOqapYJrvJsJP+W9eO4Ys+ulpFjQQMAoksjrUYEraf9DyoGCahp71NBsQy9qkbbNH2gDt7hZJWC2LPkNDMbspZxqa+Y9GrZ4+3gYM0o6ReWYDR44NmLVNG5Je4mSs+glT0gFYCvC8MP1lRDyljsYGsW6KmDklbdBcTzadJYd3BiwHpbFA29Rgb2AM2Oy3ssxPu0tEE0/xLntWd4aaqv63thIfGT/SbdU9wrz3r5gA/XhjYviDxOix18gPAfQAkBcmYTrogl59NmOu9q3P5Xt3CDYa917F/Nli4jr59UCNVcQv/GMsI0ohdm4quXvRQuNRTe2SnqJT+6otMvgZRjsfGNHdTKv56+Y/X78P4vy9gdtG8bzOkwAInjpQEfb01S/pn2gdaAVczxp4V2Q/eNBOPoDSUKFv11gWkyMtZmbO/cpfcnt4/3nUD8kjrJ+cVmP5WHUoXtGkrKZMWEXghQhN1Vg/rHqp8xB1uYcobVsjWJFBbj90iOsBY+INlDNcXN13Fn0L+lf9c4BWQNt+dtL4or8aHWwnFzcFbl6GB8jtvf9NT88gPWaDBsGwpLGtsZPXwIsUNwt6enqB771Pgd8u1N4TfxtYuyC+l2/8IZP6MYESuBQP5VnDouXo5XiYzVw+TjF2Z+ezbZb3Lh8KJuWxgbaU/3ESCVgqO88avNMzCvLZ1nl5bODNsALjYNT3jcSMupXnXXmA/HUxmAZNgB+M30Lv7sjvyps0g02DIi/BSqsAeYDi1CB7u/vtu+2KO001wH/vvYrQ9R9dl/a7l3kRcJvPYePqyUNv5G80r0vkJQV7wDTHiwN5iAMSwGDskNeQWETu1YZtC/N+vYXlb+TFu+QlcljxslXZoWQaeYHUfvet5723tSSOQ78Ds3n//TMUm7+Mkzhr3hAuEP5eQSu4Rn6L0oAA0gFwZBk3igEfSH1uZ0NhNQA19fQECw8Ei4TBB0TBRrzahKJ0EPBpw59PV0mdjp52Nq+PT2m/WpRHq3wD6eHzx46SCgiE2VYazuZwaDZ0IwRRH+7RkZg67I8rHAeFDGT7PVLXrN0BtFHgc2H4B/Zj5DTynn3VfEuff6c/gfmPf+v6tphd5X9Bnd6XjPqFLxR0eWHpA0p5vwosvLe2+lCYKGc1lIA/i7+qi/LvnF4KWpqeVlH6q7gJ3GncIO4HpP7wWQV0S/qzp95K4GQI7Ad3uz8NCljzW95+EYdO4wfx+/M6mKeRJ2+a/TuiSddwZ2VVnDHEi8ylJqfhL+xrjdBHT/0S8s+F/mOqf+DJbLQlwA+yO/ozJ9oVSq6qSoZ0UdY3T92O4bgkQ1VVULILJ+bnqZ+TcyFc3SWGc3uq9/a1z87OoHOcOs4Zlen8eQXWBUqpWutcIfOrU4/Zod/mFAoWSxGv1weIj1SMYubiFSRSfMUb9D9RjI+H3laK5mDT5poNVd0MyNj5o5gBSVJTJZBJ2I1LrU43AkNGPZpr3G/O6MdL283PT7dDE/S4L7gJQVzV0ZKfeyQZm2AIMoHMEQSNlXYvv7wT8s43/YMaadVpjYcMMLbSHcuvoKMYqF2tcRznp/YHazDwSmvpCDABgAFss18uTjFY4TbcH2YigVJTIQlDdOpIjyRd/k0FLtEVBnf3JVHamMzk94czYCihsZrU/2T21EpGVYFX58+CoDZr2snN+QUztJk84+rrENoWJFANVvi40cUStuOrPx1Y6zeachvoWyFIlFfa3YBRCMYYAAgC5g5JAvHWYzqHHK6s3A+WrcUsdvgDKwQxh0zs2B3STmOHLcYAwqM0CxoJE6x53N8E9c17BYwJ68IMdDHn5AHP57xtZuV2Sf7/17mtwPyPxtTmFyw4EscnO38C7zST40QL6kRhUW2M6j1Qgds5uWy0KB1PywfjqnadNv8AYCP5QCSiPqWmCySzGhsftJhYcgO4lnBpZ2ep0fByw6U5gkHihQXegrPsjewi7PFkccykhgEPphQUeq8lj6jpHjbC8k0/RTF48QEuI1ijx8kFg1Sk6nNqjO/pd4c7aYDN978FMMRFWfkYE+tmOoa0CGDqZvvmUOA3KiFxSSXYbG19HsTMRTY3YLNLSGyUTuELg+cT50XBigN3mRFQfgpWqhHR6VszKYAipACr1QZI3I6VqbNiJmZh9+ru0K3RtZurg5JmjP/KYX+u0CPuSC+8eL81sJENWVZAMC9ULoiCsuhGGtejoQBLiKKmf7D9SaFU3OAZfci1sEa3zcji/79W6FGaJRXVs1ThrG6kQGgnFFmojoaYIloHRXaikFW9A87bsqngTSqCtJvgvE4S/JVkyZRH2r3O4W87p5q61pjU2T0LYLPssemS4QJ2yfRxOc1kwZRq0vvd/tjwo2hK80VqI9BRTRdMqOXQTtMFMw01GRoC7mBoN0DBS6TwAwC24oj4EV9BxoD/C0gLwZOZxH8AztotbqbEr/EKVEG+ap20BsfTYCeRroK1Gy+dvUWBLAFFyBbGWNKmdCpFIkSpljQUQVomjBTVgJmn6UBcDEFSw2wgO50MOiJn3BSWGEjHPh+DujLw/18IRBRb8P1YN2Le2+IejRo2cywjDBYkbCXWOsrPwJIfdTw/zi7kbQan6yBSD1XuzTkHzv2uejGgykhh24kBU25zvywkZjiFdJXdvDJVzRd35QyYCcz6t9zebyq4qZQkRtM6JZTGoMF5uqEjAwEiFJ77GlSTFkZyQ+Pj00NHFkhqnMrZ9vTT1GBqT3MoC6dHiA8vUKzfn52BIBmzwlOoI+LY1j89npGRWkOuaV9ERExEvxnXfCA6AgRBc4T+Hx72EZfyrGzmc72vZ2ftTvAhiy2TwHAzBcZxJys6WRKxZIpwSaLFFSsTDnGn4L0TPFWCFneg3aJdJt5uXaFno2TgNuGVRr/BUTYzPNMozX6FEk8AIyvur0GE3uGevnkJHDXgNXGUzBuCNNeo5rR4vKVuWTags4zHt6SBMpZLSAEKZdfXZycNLQIPHhpUECMxz1hFiwgdkD4wBAuHvFg4akTmKjfD4cDI349bCO2hsJQMKSRj850RRPu1Jse+CyI9mYyUBOy2YE1iF3573hX83aVXefbOfhqG7wpsshSo0qEIe3NhzXfBkcOsK0+xJLLzbklAJGke+CDs+aVfoLTLOTCAwkCEBKWhuRg7A5ZCMXdPoSAZYBm51IIFVUIBlFz7pMiGGGs+NhFXHBq0YzHvR5R+pJzyZWHpPYXyfmnhyzv3ckBuiGochHxsRkOQJLOEQIXi6w/GaeR0SAhE8L3zLep2uJFh1t9X00qcrFAQYxiNFcfZryl34ia/bkQ+shlKrNyyKizOhJ5EyAL/E+Vge0D5Kv8OXeC28tXb/eVgEpiCSUmdR3aWoEYroi1qBLJt8MwMvI2IHEnE7HvyiLSDcYWmUlOQv9aEZtLv71f/z71eIQJgu9nU6WNhBP8o9R/3ZNvWFu77m/n8ptxePv3C/tlMpn3wrZyOVDp9vpZo+99Pqj122TZzNSzb/183aqxYWkGdkN2wviGbsD4ovWl902vmZjS5v1ZgQda28/IN2Kf10OnraH2Zg6Y0dxqftkBpX4vthqp51TY1vJrELGygpJ+EPe6lJaU1Wilg2RaXo6i/9ByNhyh6IC+7VWS9stR49PklRX1O8o2UXrzAx1u8uKhoeP48vktdfGHxHPQ8M6IthtcfsopspHmZ/HGbKlwas/26jWkInm7CGQm8uGU4rCCZlsi06/FQCA8ihM832JNxB2HC7zfc93cJMI+EecJHGMHO9OvEC287nW+yqepJFreKJZPXsNJ4WRb2qmlvEvAZWTjXheYkx1JWXYug8IylrRcKt++Ptj16PMd666HnZZpkpTsSZa3Tekl9rGe2J/PYH4/wZ2miZ3O3lQZybjXXBPgcXvjVgEM2ECXirh4SYa3CWsClAW/Ybs4178cZYg37jyH0QIdxhgNmNQVH6IebaMGX0HOY//7DnKP433+BM78FxGeBvz2c84hGutZv5zrHuO46fJpzSboLfl13nOO6nir/byDmOEb4HOYpECFmnFS4oKBcBAFFmMwIZ2V7sRPjYPIkra6rt477lOUji0zA6MXeE9dJB1M1qWt6Qu0knyV3ZVFsOaFjOJlocnT0f1XZoYJUSg+GOzWNH+YitFwq8hAk2uvnbJgcHQBsg77L6Qncqb6x2uNhlvIGv3l9LQtul6asbFmP4dYKu1jgw6nmzVYtw5CALYgnxXM9OA1NWnOBpr+g+M27I99tigfLQzbgiek36/9Py4Lifo3AXNvQxPHgKgWqtWWkH9+AGQhVlcNKtWY884F2rbZ9tJ7qgLZNq61NsiHRqg3atoF5IWrb3QFzrpm2rZU2Le7cBqRzW+ZFYc2J2t8f3j1wIay0t7VtwMnpBXnPsKctcOAakWZQDoCt557huamZ97e1bxl0q1GtbncBFwTqSP2jDzxaozCTb98eQSaRAgF9BE1PYtLibU60jdVeklrH9CCXryA7kZ7Ll3vWP4ZeuYz0yAQbFrVmAxzG15MDZh79mmz1zyyZS14+s0lPhq0C2Qozvhder1u41xXQx4V9PrBefV7Fap8HjwRBHN9upYDKyqCkFQsAZ17yOPjR5wyG8XMpgn9J8Dg+lujSPJl06EcxhSDJ3hS356Me9vTjFwHEGdGPmrkFs7PapRBo1zJEjiQcEV3oN+8vKi6vvDEeS+4fHtaag+xQDYRUDwopcWkLUt+JDRMZt1AeGWloGPHl8xKvsw1nwc9XYkcv6VX+ni8TTNbmE/2l/rKW5bvUW1DGhRUee6/xxGSaBQ0V2+29VyTg0Lzu60VM+TP22DxKR7N11MrGJYEeHrpLKu6wrAAo45r0xw/aKBO0eP5NEge3WZUwwdurl9AcyOmwlEkGZKMFBvx4QkuaS7Qg1ejK4pz83hAI6bEcv4IwT4EH+OO1Z5jAt0jOyyIQ3vitOjzTXKJavo4I/LzQNFhFLE7e7hBmrGNKkuEwu5N9GfwcTZd7dnr/SZlNIsyUGOscwrYXJ6uIbl9QGjprOiaF2wQOBfHaJTKt+UBiyERw4pimXyIrkrWdPdYrbZOEaXFaVfCEPnFYIcyk/ezRtuyaj4iqOkRuWgb9Zs+yrfEgOgg/ikto+qiMovqoUU/aFIqJ9tyfyaOjHj3Wv6vSx1pMyC4Thzl6MAf2AS2wzsbdDEkNDr0FveDqLurjgxgny7AdBYYIHFrkh9Tn1CNOtAXta9XDNPOafYVXW09KyrCUwcXDhyf2vd3DwyX70OkmhYyIcxZ53qN+pdQ4uxO1p2pOZLgWIcZp+bNWjgBBjIm6ndJpFcOeqKq3k/quWWyzbldQIUgW5EboulUScf02gdhNBXIz6QMBkFq0hFvvykZzu0NjfgROhQM6jQpnPicv+n+1RgOKNU/cpx88mgOZxAIEwDqdEKcqFz2XCHUlHbatUQjIHHQBKg8uoLSVs+gDXkpns0+SQcD93K32ZIr6wJM7E+kOJu5xhv8SXnYu4r0rWEMiF6EdBTaDF+wIZAvWoKBSCdgv2bhsQQK9pSqxjbHkz37PQHNwLwHZjc6Eojsn83+0rqt+ZShKQ0Xk56Bm+MkP4M8vILr2BOVYvHy94FQge3jhkNapr9b7mLi5VtDn5FkxUO1SaVxZ5ylpujE7TwGUXujAfC3SS6GiN4S3IH6TCKzKPlRNjQ1QKwKo1ZPlVairOvE0+byzQFL75/VE+Fb7SuPVzb43EMBwJNpXrTv4Vfh297UcjHqWIeyKezZsuT/zorCaGm10vq3lDr7o/OCMlDzWJMUP3NOKT+or8YzqGouLnbh9qiISiNfbStI+mZBbZfWdCbApjx+rBN2S7lqfnZKKv0exVyK3hbebd/kdUJ3bAWjHxuZtJ+xXsgn/OShBQI6a5K7XMhOaC5MhRgrUVPic0+ZFCoXlkiALAZuBVMjeIGg1Jtsb4wtaH1jSmvwqWdDIr7ZC8sL8GIgRC+UXQjGd3/tWfrk51wxv+P+/jXqUaqUOnzcrAIKAxFGXGOgv5LkIcbJyTvkGiE+ms+hkvoETyiFDqNDijpiP2c22DrqJzw3bWF4/ebHgrPcmI5S7D3dlKRvDRj3IbBRCg/EPqOUdvHXlyBwIxsk07PIqHJsu+PPykotQajbKPb7VirlZvSOcPuuSp6inKK3wL1v4DvU2ptXWvUOUzaQnlrTrLpaJ4YaFpG1oHtnlpicRBNDV0fcKlY9e02kxviN+x/b7vWzZz/m6RsDfGrwi+OKRM1RhKsSAziij36YE9dECOfSHj5SF9xLIAlRH6lL7EyLVreoovL+6i6RD4UgAzuiPu+QEbfCod4+WiN42MEPV/xlXXFhuncSiAfoAigHwQtgajQqnwak0dwvuSuSo5vQCcT1jXxiUY3dLwfd/iFA3LJuUdnL5kxTgeX96uUM8pY6GBsnIFNE5Z8FBCz3BGW8FHJkzSUsDz8wM9gbJN/uXlflrd4lo4pk1uGW94K7MbHVBfAlfJx1oRDGU53ab8pgaBji3YqiXqMAcR4U48YixV+zO+6vDfJS+d2iH7tFcf+Or0VyU0b6xfO81Q3vz3QnKYhaNfhwGEGuEnWs6EDQahcPTQyPrJP6B/jJLzrF2CFtIlOAF6iyMU70OMSr4vaIjTJHhmIiICGlkaWSkp4ZBEL5S2ohJko+WCnSQ5FOYECcH/ZMvv0KcoF554eb0mFVVA3iuWX9paV7JgDkHP1C1nrIi8vUtFAxlzvqt9QpK9XotnmOuzS8pKWXdIMuPqGJmg1LJPVU4tyIyKxQgJ8jVOYTK7gi2RgyrxqJlBlbi6MPpyads7GUJ+ka1OZWcnurTvdv6/ncRLB3Cnphc65dDST3ReiXlpJeDTGkvtd2Xkp6MJ2ATdoWc6O2vuzRi6hbonwuGs1HmA1+Kjp1c6ZNB3s1LUFqFdyVBSewsc75lKG27dz3ciVIaG8o91AOBuoT24xLHTF+4rKOjzFj7kR1wmaUUNGqnJiiETWMOkOKvlpUqlqDh0n9oORoUr0ub7rn7S2OX29F770kPrMaiAS8Pz5i2utroyynG0mG2CYIQbOCuuDpM2nLxzHa4E754jrDdRVJv2IaGmKFrnaUNeHjdyMi6pOFFIEa42zxclijSirvTPW8yfbDzITmIzi+UQzFQQT4UC3taXPmqzM3ZiQgXaLcUw0XQZi1ULAoq5iSyKhppKRqnX6KWFszcXZWrwQJArdjPA3tHXpifchQrbzuTSdgLzy0pMfGFIPRJA/zPzwgE+6cB+K1+saP0yUUOldWbZ2IsWg5ln5V6WPua7WgdbmwlUgbXOfSfZ7u/GePQ1BFtUgv0+3yy2gy3qiQNDZEqT4hDYEGVJN9yhteHG/sd1g1SiK2rqphmEACrc9lcFpdkTQokB3i7KOxclIaCvKJaFSS0U6zOlRCaNMNko6imSUJYnWuv4KugolqQh9IEemEEQRzQ5y3aFhkw//FE5HoLczStJpVguiB4hox+IVZ/FzRxroTCiEnAZZ17vm8MVkQVeUqrjsZp2GB1o+wTSa2zf/Aaa2uOjeT6xmAqd9BP6aisULazdOqyqIJ1mriqo1LPSnHYZmP3JXRw/VqCINik8PfEvwkJjI6WT+FwoY40uAQWBnfjDu+zAdw6mfNp3Rxu6zdlNo3dOnTt0FgT07R/qO0aQysseaWFHxdP3D0hM54du/NtKGhIOtx7RpvX187Fe2PyMyCge/Zp6P0Gy3MJsoW8tAJ6ZMTok9BuPRFQcp7WmaTyBIp/nYnu+ynYRD09nXg4Eq57PCli0mQ14eSm71P2ZVaxo0B5golkwn0xhaDmI966KRX360zmrvldPFlceqGAWRWBeBLg9Coa1AbXT+7vYphqSW23FCFpTRldH47B2cQ3Tl1q9Ls2eGoKbkOUQfm5xdZK2M8gIjxeE58+Az/4fqOLc4PyESXcNjUVfgXiNhDIERkQiI5fJvrN+ye+BJX07QuyzlaY3IyIpO+mieL9tIL2gdCMHOZrg4vakGGuQRnU0QmXwSJ3ucdTh2LUj+Cp0+g8CX7opXvq4R4HC0ntremkF5b3xLgo+jG0yUUe5CMT+EALyM4rV3aadegreRi89fhcOwoLg6kE1FmPEG5H/xWf0V0Hj47CuadudNR5vGfg/5shBAM63YbGEQOQYMiShm7pa50rtgnKOqeYZJlH3fndm+u2x9VjZi/mRR4nmZcs8jd2+QsKPTIPeRYXDWj0XlCGdxcIwBNr/c/8Op04gJAM0UYeRWNwoUXotYwzAZXqBtv4mG3ZarU+J/f1qQEvWC/UZr0vj6I2TmRk5UjzGpNnzVRnvdYCLGAX7jHINJuNYXJfy4HmYX15gaEel18u5Kh6wyQ+Uk/Wk2h6/fweNm9CgZGZRr0maUNySqTn46D6yE4+oUBAC5qIebc6/s4DOifad9R37/6I33fuU5tsnqvH5rhcmj1AVaTQuTLhprcpgXe6B3fiV79LSAq7J96f4K/etCalwFGvI9NelLEb5KU0j38a2Aj1zKQEZRXbmKlBaRa0eY1+/csAqJ+Y05rmPjmF6oVYLS20rGZ9W/qFZvYzNkpDVx1pniUOxDDtmuva1jpPm6jXXfAdl6Y7ke3IxdPErec3zhI2oTRyByEO7lGaJAH23N6/kxpH8/JwWgNjB1CwpiIPZuoBWF1ZCIutxqWBhBVofSQT5aFr0Y0opjqyriDBN87rhKrumT8S7b8BN25Qc98eVWnTZrP5hPeXcQBjXMH3cY7k/OLDa/ri8M6ItFSdrr39RNDJykr7Xsg6Z87JBO0lJSeass7du0eve5wdsV78yMENzVkBh9ycfX59erpGy3JOWlJW1r8bB9VLGhNj+dZgAMNo/e3Z4yu/nS8XFUERdvyxqslvPUU1gSmPn/xmWo2vzw2JibN8Y5EXLIAFxdedV53w2yDLc4Njxn3002NtQE1N4La+16aP/z+vvDGJ8TWjRlVHHDGZvQYTwoMys054gdeJPHNz0J6MjCCN7l2vXOfHSz082lLyVMOkoCo1cSIvb0/QHkiqKFXUE8+dMOedbDyj+g2Ym4MrFEhFEc0Vz5+LIVZWrkFj9c1enFdznvnTZuakxSRnbh2YXn1d0/JPxMymqrpVzrS4mFtQ5KjyOfMxc0NodUD1b08ez64OXHrKb711tbMDYygqksuH1wlBPybVBNQ4/fTTR2HR6SFUHr0BZnPEgwh+TsZBKwDDjIu2L3zXxJKFPOmdmDHpGV0rxEIAmqmBZsHkzNu4VZhh3VSN6mB2tDwft9swrJNXnoffjQ3fDeoI+hbCwqHmY0+fUACJY8amZKJO5KoIoQhiAwdH+kt0e3nmH4N3VaS2dGL5nLxzhJWdQmymYUFONbqDOHyskMxBd5NhCu/+J7a7SfBCJhfC0BEugJG4ikzSnbL9pV04Dw5bofSNCe9YupJetL41/afdN4ZKa9bXRC9cUfTGJQaUR0E5uVAkFJWTEwX5JPplVf6cd8smRaTz68yBMhqZk1tqOavs474sfnw/ZgmwXv/+Ppt+/roDvwQMdvlH5Y9hoZt+wnQiOZEZa1smk4IWOQ6Pnjs+l2u1ZN1AXPYuOTSQDszabkJObKkEkZlwzjbM29aw0B+U17HLj545Pf+Zc0PDz+1BaV9G+sNCPRB4Gxw3kgC12P334QCWOGCtxS7329ApW3ccXVGXmwCUmERl0BUu8nsXnluNqKcoHkHSlBQpZISBndP8+1ffOdJe2HRdgTPEZ2KG/4XBWchMyt1q8FPRyPxD955i+DaFK43MaTJNaHZrtNqANQgPEyrCwoywW60EbbGVbLo8513KW8MbN8f+tNvonPU145NBV5EryMlgo4eAMbPnKQj+JETfj/Y/ZCjuTSpHEpXTbBrf7N5ovdUeEx4mig8LwzhssfZok1fS6HEr3qX+EwsqsT8dNpoB14xOBV+xaazxQwrj3J7FPdYvBqxhXYUF15tLMF1sRrBI86KHCfOUyS6HXd/67d5r1wWRqC3Zjbr+HCvRr8gjFjLywJrIsHngx3XG3cJp8Eh2Y0M2TM+CV+NwNl6Du4mn4vxP6pSdJ/2T7KDYwoIYiK60wkIoBq9hvl0j2wDxeEsG4SzjLCFj514ivaYPUEeQuHfncVvL8e42sNwasZ+nEQJwled9D0YxIIrkpNx1i8Z7+p0LKsT29xo14OHdsM273qO9VEji4LW7LMLiwI4PH1awsc0sssngacviO6ZqKNm9ZfhA7xeu9FopbAUB+j0j3yu1HPTItphM+8z7vFxyT3H8oH2YP5+V++7FByvVkeP5ZLisflAJw2NfDyJ37yKDTm3wfFxoabK7w0uZ/8aM072mhuUCNXdTsP2aUGTw7l3n/8trNGwFNZDLMBYLZ/D8HgGOrcE5M6Bao/tbjo5chklgAPT1tHcuOPwFztLayQjGjbB+Q2qMaPNxqEikD5BFbNCYZ1S4Fo//FbtaxXnq0QikyNDdO4NJI6sqPGRqzwoZ/c2SzoQ1ExMaNAmPTyAaCr/8HUyyHuFSjmyNzbDPutd1Pa2WuoRd9jJ/0WTCu29IvPRrZwoNH4f3l5nXwHkKOxY7MWIdlQsBJQwlaOffWP5ZTlGzaRzG0UMR6lIocSRYwS4FAhj0Z5QH8bHNEpt0m4adzHyLDPqusFgmayY6qhBsLawb+W9dQRIPZWyoz8TgtVpd/eTlky2vIk5VhRfeZrH6LN6yaFRSPdAaiGzjNoI4239sadzJyA8ZsDuB0y/sPhDCzG/aCax/a+F2ZcTOOyBqMcY61CLunZunwLbPX/hi2c3av39LAt+leghSwxgX+dyTuHvfkhkMg8OP7TkXIQPTr+ouSp347L/PnxwJwxuwWH8PS9+9t2d/c/qI48J4UPRVTeHBSZ5fbl6PH5b+/H8wvOdgrs4AmX/8hONb4OVyy0LND2GYbzCQfsjkvfqPisfYshyfnBOYGaMvRreMnFY/JH0weU8q/XuTDySfMoqmvZ+k6ICfeNvHcqF8dF9MvhBBH0pZMM6cqKqEmuDDnfDqEGFBn1V6qdclRxZlfjuAC7rbvBJpUq6UN8WduhxNBw3YeHG9Nv4GZ/ZuKIHKoe4NUCYJfI8uh0we5ie6Gkc/DUxJTSVxTLkkusDUo49EM6WT6GJTEQhco+nY/2Kj88efibV+D5GgVZnGkR4yvWT488myWHmFfNN9oSmmQ6KXeRhHxq4MRnLDpk7YRnzfZXx0hNRiXygQXCrPyMj3b7Obm4sn/rK40Xn/886aquvXq96LaDMg2MiPHomNNY80z3+36aI75bEEgx2vc7Jc/cO2yWOABisfCYyb/ddxy7BVgsV3dKGSdzjgPu9+ChSrUxXc490LmjDLdYtvcU+z/ECdJchjg+5TUdTdd1U+prNc+m8qe60tCOT8TxQS4hkJQPMdPCeAV5+GV6rPsBN3Y4br8cATxODUjOZOkhgDbxdZaNV1wiktxbZsjyz3p0BjOWhk9PL+oTSbPII1s16k8KDSnY/VFR8kpsibvwHVFxr3pd2YRITOF8s1DRzXbXCE4LGRowjM5ULVLHaM4QFa9QBg/P9XUvxZ+9wKvNKOI8Od4idLrSHFv9BoF9HuY1uJAP93tt99ODEkZFAF9VTVxFOyt5SWfJ4qdY48GjmR+2BPUdTqiiHt6SUHlkUgM4fIZrt2ui9gr8JEVvCzlk0h6bZu5YxkauJp0fzc5XCXCLMfY6y8m+0+MfRMsmDflUcEJu8DJ14k3D0fwHnMJY3pHJ3mj3R8/tz4qdTYXe3pa2JwP9LsmIUSU10cKgmj9rwauzgS/25zb+GbsEhVsRDc5qnM/22HbQZ/UM5XGqwJzcU2AW/+ScQi/MPY+9GmhsXF+lydWDIWqOL/4V04l+mv6Ypkd48m23mUZ7I3NcUpMPGG6jz5Dx9LTcPtaDLe+hSLMG+RhAseSu4aGXubr9hsJkFW0d2HCHnO9yha+IaOo+nJUhxsG/o6PyKzT2uocpQ7ZAMNdKHDsfJeUax7zrxARTwiVGAgSlWJgQikqTCi3YKkOO5SenTVmTRk7IeDpJU24auVBU2/qLHgkpn6V5NFk1/dHin39kiQj1vW2NcYPHZ7bFAToTVgr1l2y3xa+I2NxO6Et63093W/p8/7hN0dt0Gcj75EYc2KwU/QxmlnadPf4qZVoKsXs9XQ5F9dIZ8X4Haidj4g8oAyD6wF51b7ZqZoCDFQeUoi6xMrPAE5+u6XSeyEUyKQuXFjY9cDYVKSEJAosHOaTd7bXjs/aHblOTLib1G4+6BTX6FYCKyIL+4h7GY49jUbMXRT/nUXv6r0Ez59g3z9TI5vacn4D4tlm3n8ihXA6ZkNlLC2WgU6xBkcX+gdnMUqmWnd4hxurqwhKYhF63eGMwoiCX39345+/O3+z+aR+aVy8xRaNZw8A978RSZT5SlPaOQY8U3G9LnhlLnaSEUZFAOtjsOnGJaXVMXRDlxOJXb24iGEU73lfoJPT/GJljVGi1tDzNaUOkVZ7oAieDvdpVbmLiBpLAnHgBISawMUNUK/LqGBt8vjzJ8zoa+Co7y/e3CkatXFTxvLfNNqWny60F3U7YGVFceM/LEiyStGW/QgVaNdRCCDyw6xAsc1rV1iJsfRIupX1VUCxfdKr3Iz0xh4NEcJlDe5g08HZFr22Ti//Sp8jW57wJX+lMOsTF74Xzd93ho6SOce9Cd8w12UvjpTFbXTWJ3DU+6byGUKVKa343hHQZz108TQB66OGQcEENO6bVPB+kjmNiB4ujGEmSi4GO0G38rFENV5C36+d1zkGiWGCL0L0RLjnNaIObgHwAonlAVjol1gLtuVtSbForQQSukzVYvVDn0p0BHOV9Bca4RxDlriUwgIv9nvZX9BvkKW2VdkqyiNDfHEToV0TZfYJipZBeIzV2lWydL4yxchIxzG+fXlFKSBfgJT4OoaxMbIi8yzlHZsw9aOyW59G5EWntr2y92sUtIky481SSLd0utvPVrI+nhm3VBgg9iIcIUiIhxrEBHunS7fFO4s7Dgs7pSvw1l4Nd75AYw3jiDj2hHes++havGhUv9Qj4RpCR6hh0ADUDUsigIV7DwGsBSvnM+RqAWCxbX43V1eZPzIUgx4dSyPsmmfyxXRF8bXPkV0iKE28SV9k+TI2kkdvygLvX0M/6K1+XhHUu4HJ0x3mDDKRx9t0EUsWUgW+qbQ8HL/QK80I2p50MOHt5ZHvr9DdSWdCoAkrYLOYeGWwGWVl08rYGtASenMXvEDchcR3aX+gICJMpYRZoaf1GX9z8iyRsQlzFD4I1pOL55K+v9J1JNJF6knOOEX6H/fnrvY11X0O64/MgmP0T5fk94EmSyLabEbHOd2FY9UYNS4gS9x+T0prla+37Fpl/g3nwOi6YhB3Mu9fl3bpooRw6dq294BYAoWVYjwN8f+/GbEao127fz626rjdg69nRkSu8zyxrFjK509h06fdjQ1reEwcWt14tLE/AMHHCWhc/HOL90XRce8CiLFKg9p94bmJZe97FSNnArM/yn8DDlVf3TMSx5KM85vrkHYe7EoMua+du7f28v1sha8nvKJm6b+wMFVHImK19TnNtwh9SAwN7sYoptzH+3iU+YJOFVT0xuWgSFP55WtrUF9XSC5B4i/oX04bflzy4dTO6cEbDMyLdYy842lJ9I1MHZMb+0sMJnekO75hPVDq0iqz5zwO7sp0BaD9mF0ck5STdlEsw4QTBQLeJd6RTDxuCHvAu7NBlk+oDAEgCSWRn3ZF2UvcKP/1IIwomi3IGCYWIwJ12R6vO8Po0s+eDzzsRGnulNgdfepqV+Zfnn0lu2tTY9+Ff402H2qOvDIpN5Vxvfa9r6vL7hVcFvRte/7npSnXLdv9jIpDbB2clfg6kncz/aWkfNu8UUvFhba+kHuYY8znmQ8gvTHD+a2N+FmcZv4nW15gWtXBc2bs92QYPhI+Ln6jg5eLSMTpkYtCvzLruLiRqD97O0GiD/kE3mZh6SAn+KSmVlhiTb/MW35lVKDB8WzQyKbI5u0iJ6H9a73L2tHlrRT2ssjS5dVYAJAYF0OqRIH3235fpczCGtDb4SlgVkL3X7w1dK2wLyxaZpcXWjF9umlGzO0W2dDvzTg8PJ0DLCB7dLHOUmRg0k9SWtL3lwxXLG5z6YxThzKds9ZIVSExOR/dXkqMAkB2smaAKdE+hI+/GnmTz9yQWHA0xmwlhmxkWlBZBg/tNn4LgY1hwKRCSgSWXrfBRRqZKI4i7SDjsKBT+nS14cQSNLnYt5NBP5ca/Pxds3mNhpi72WVz8X7rH74XZQ4lOOeYxJMHikb0tpSJNOwSeqYV962u14l17l4et39xw8S2pXAtfL+DdxCOFoWm7fYs2E/VzX6FFzJCUw/4tDq+qSN1H1EUflSQLQ2LAwgX19A6XbAu04uRP2LKq/FGFUVvW+rvcdPrLy6vM5DamqzsXaen/hqzCX/v3uSbWLFtRjjtYW/th6wveYft3394Q0MOmdvZquZM84xwUOoocQyc9PWdN4gus8p9Pu1Jf474l1CnL+2lsV4X2DkhXo68d2yfdb352Uro0eWHmJG4bLlCm8SFKM5Sws7bEi65fIF89aKn6ar9mAtp/Ux4ZA6G0TA9fqx9UFCViNQlM9vf4fx2s00F0axPHuZg+ISsLw8IQVG8TJxT3FET4uYVDjmDkE6H85uW1+kdeU2rPZHPNdDdO8Sms+pCqMk4qO8xH1lrY+hQSk7KFBgIv5UBFHEMk6RTg2famXZHCkUqBFuj1Bk9NHqvcCowJ7WIqAn2T+5x/624EmRi51Bl4uoJYoHb3XT9RRhvyEjrVzMCt/9p11WQ8OFzgbngVXjsTh+padzRPmfb709GNEc0fftt4O+g+dnt1i05x5+dOGk6/t33U7B+Y8+c9424mJ8ii0OEIgScpFSwxSkd48cGYo4GTHU1dX7DN2+1RexZxAStQC5P2/UUsx23rdJL+tD5vVABaqc1gHT+hipvVjmhiAwagWoNfF88BLyRBUtS1meEnnlYGyVeNrrjU81L4Tm71j4ysixeO/Zmm3tXVtdbq4RisQJqz0RPskIJYAJ72T/9hM4M2DJd7giS9xjAWioKZyfb8lfGwCP4OTLmbRkCoK+KdKqF7Cgt0Y26QUhNLtwPfC1cjKWOSvEdxKRdyEsm37WhoSRfa7xUpz0Yxwk9hhEJGoqWmZ+YlukP4m/OXXI0Ldls6NoNWzW7VvEPRGnCbwZ+iKAKhRsumbksEb2pyEVEMghUESSw3r0hG2PVEFoqUl6UmPp1JSw12r9+D5VZDZSWaB46C65hLNn/KS1U7sgU732lMB4AbHnnUpAqdBAUS+1vMENuebk1NVFkWtaGKh9z1FS7PRgaiUlg8X8tYMlJXftGUMsIPGXF3+eqYZn4zLFCw0LoK9+JL2KHzuoSG+MS4WvXpszZ86dWFBA1i9Qb755MmhjDkZMKPSGvYyGx4DEYBxYXHQ4QgYICYAwM1GTL2VzIes8FilZNflipXPR5JdK2cLAlxxWa7gJLMPVUcabhuzsQdtYOR3TdjBGTIyjWjjTgB3zskdSdQfwixJgDAPInzPQfksYqIKvteC5V/ERkl0p5gH+b5RhLENKOUhubPeav2lxPmxhhbE6bDXNm11lFrLWXjdNW2PU7Sf3e1m69IesddosN9ywAsGme07TnCpOS7VUFxff9/N2gmqYV1GRnb3/ZvFQzEE0hCW6Q25BxuUchoZkEPJJbS60kyCXPQMUWm7c0VbZ8ZxFsSR+D6ant3nu5jVRFMrBSb+uwjBKzciA5G6CjzxoPYiJCvexMyqLag6BB3ipFZ/Btki9HWjxU3r8X51nnJdxQUJBcGgXk4MLBKASJVRM47uvOVDRG0BRmnldBmQjqXASZg5JLfcmZribFs43cdtFNPEQd2rqrMzwgWfZ5TB7nlX4h/8Z8ZYHwgJGvMLICIGinEYMaEN6creK9VY90SNaZzy8FvaV0938ts63dpfdMt8VelJp7Tw5oUaXapI/ChqpiW6NZssWJYb1iIUkbNmqobeHFhj6ppmm/JWUWrwOR7r/lZKT3w1lkyjiZT51n4zDvPBZ6dR6DtpghJ3RSiefF2D5nukI6j4ZYhXicpgyZ9ZsR022KDXY5Qg4JOtXpmZzwP2oC8qUyYTCoJn7zoSBRCeP7v6loC0O/7FpxvnHvs6WNRZDvY0umTQVssQn219gEeg3TU3bbCaQZd6X06fdnlWrGp0044njYBzYILkMiwYoAkhiU//Fr87E1ExChTHhc2V1DBohrG/8zACHdtrcGBuJiTLFBEsrjIt8LEwT0qCkigrgBzvbbuQ7LPIOuMFOuKZ6K5w/HbHr+TRvZnBw5hdRoOhc5djRYy/lU5fJWJ9Cm5H+KvtMt227xW1eg0GFQpsokAqtbz2/0snud0wcl9ux5mBBXFwAC/lkHf91YoqLMeBX+RmMA/HMnGTU8QWjPbQr3smWGCz3+fvLmtaQa5NKS+Lxk6CaAprSPsxhML4xOQmElpLFKDRS1dWF6VVQGT0huMniXnOaOa/jXMNIlyoI8FgnVWJiI6bPqdIZwspNgeT74Kjbrro6sGud21Eqgy6a6bl9rkfIyMx6XzxXf/8h2bkyudIiuWP7codLnO+MttlldJmz4SnK44hr4hQ84N101/WoNYMhqsw0km01XbkqExwNYmxhNm+or2idGnsw5Bz+4TGcpOXwhcC+vvxk8zm5Qus9fFsu5Zjbb5GWWVnh9P/iGTwI7XZJVVnMUyi3EqIO0NbVnSEABPDH2TQ4BVv/FtT4cnrm1gujSpY6HIOJaFsR32ZkHPytMB1RYdkGZGt8sa9VD4pyqrJiei9Nd3J+Mcqhqi8Rctyls3MQeElv01OQ6dvslYg/Dq06717mfn7V2ZqQ8ZBg+mOFR3juwzxz6cQDByaWms0Pb4/2XG783jfbonHy97da7bkyhTlncy8ULYOGQgqUXrqj3SsyZqaBwjDSgnE/ardTTCXwBWnjFlHymcJSgNWXCKU1zGJ8si3V0RLjOCBKuNxsCOg9wjAhcYxKCNJe/fNQKB+aR6xqfa7sudaGnsA3EGmDHz7OzTl37vy5nJySEvCLbOG8RTEfeizsycqa1gNMccDnil0zziGKwHZbu+PWbe/gbsMMFDZ04ngTRfCgU4cYAw/fvlu3KTrYpkdhCOB9MueAIVvvjOpn2VUGPfgVhfguYLY8/AEg2lQBRoRtTZjboulnH2/vr2vjuvaPrSsOzmssLYCVmoMLrdGi6+2aWhob0dzM8zBZ19dzNEmE45ovLk5oqgqPXP7qtjpu9mr+zslThBTBfoHaq30PpXoEeJ7wAjySJNmo8dqL8M1y8+qQsx+PAondkiBggUiy0kntVIEpmpsSx0eA6fVHJ4JKJ2fy6fKPWc2dIeBFCv/ZUQKA7cy8aaDMRY1Rqgg8XQJJryi8kgemuALBY/tzE75/KKDK7ac/f+L45JMvAzD293coDeMfPmlx7NylPSA/YAx+vAhHk3pOniDk5Kk7q/iU9dzLxFCzJHxi0xcXgVcEGXgA7msCgBDcqPtM8+68urjXW3Rpb6fIRyFe8+2XzSnEe6fMR3zdAO8fQ+oR9sDIpBu+CUxyd3mrfOInAgAIIMh7Vuy2dDARLv8V6Cz00LaL5SuEfz0NcvYQ9rfLxcaoC0KT5ns/GKc+B7PLibnufnKVPKh5I5wHV114uq/7wYNB7A3BVXBe80b2Ti+vXa3Hb0CpQJQQL4TYCT4sBSt9bCF09wARlPr7YrCM3jxvHgRvgkO5eXto4tYXCHfuFEasMijaeDJWTAQkECG+C4PE+O73fgLs1fMLGL3V5rgiTVlHR1lcHihVQRW8jO3sPANSk0x0eHs5bmffvtXV5Xj8hLHZnO7JE2M4UEYRhV+4dJiMKQZR0jbj3IVnEIhJGnBT0tNK9vFvA4hof2veGY9047vVub87F2fW5Ji/i9wUs+n1FpBEJCMQRcp0yAeASt7ZKUiM562P8uHX/+CWxWvqnz9dH63K6dMatfP087mKsTTCLIeryhNFtXAr10LAeZvkL/YhWlqxAhqyhwANShNAGurudjwJEnacBXEG41DkeZ1MTRE1TlZlKU6FRA4JZEBGdLXPA49CKJYA8KfeQHxnDSu0cWVg5ecD/MoaoRZIN1gL2WvjfNNWL0yeKAlNzfYoELwBBZ67SmhKGPstHO4Xl+yS6fadGkxy9VekLMP4pAMKabJRphekbm/Kh0iUOaQmTNOnCZC8vFgJgYAGyd0Za17Oh3NNEu2Wgzw2f2nqCn/8NGMa7+YUV3deiFtxQfMDZ1sT92haMkK1jHKk3XSvEDIjw8rL43xgEMsYSwRZd+irjXA66E23k2+U4AkxPPvVBn84WClSYm85p44XFYEe5PI0sg0TGbZmzdgAk+cWbQX7OuTk3xbZpIdje0PKRZB4mcpEdgwgUZGAAgET7Eb297s73DEAZg0cj6GkdnH6du1bW1KyO33xdml3yWnRTRzig62bhFFPMJlAfnZeHVowdnhZo0bQ0gE2w+xARXZjeA6m9PJfhh076ihe8OCBAxjfFBWAx9C1lEc1DK9EgLNF2hTYwaA1hMAEa9b/p321bgfekcS5MTTrnVpSlSsMPGeM9c+1LcyHql/MEqwaY6LmOxn2KNc2KkISkakMSssO9kK6mZESspm/ugp6Tzofe4t/QPqtTbzXCp9VXHot/dKldHMhM/GGujUGHkwc2OIWXZ26DoL0GNbhlQ9Gi2li0PyAeYF9s2ILpqR5Oerr9d44we8q5Ni1OihmOaII3pKv+BkczJpTIU4kKhZ+9kW8/DMsPee0TkbosgfFb5RPcic2cgbS819QJcfPqK3vm55SftE7O/o19OaqFx2MjRtGeH19bmVkfGUs4XbUayqzNWtanl+h24/3nwjp6XZAohYizIopadz+aqf6jBUv/JYmWqznNMOpfn91WmFkd61S2qeiOTZpCiGtgsnJQqHEoNPIGp1B0wwCCApDekIYDRdhWgEJjU3ZIpzLuQsLDU5wgdP2NCx3nDA8qNHZ5J5z1wsmsXqvZbzfwsxZp2z3FrlGFZUFlyVxBu5tOpk567cbf/z8Mc4F1kRPbkVAkTDK/SaxxHK35BOXiLXoLK+tWTPTtRy7pq7Jcs2eFCloCri34dCbR+Ef5wVKcAsTvsj+r4Efpx82DEbgwcyYnGvsIPVeRoSVQIUUkzV0goUrKbSi2rMJXxDYKQ3LpTIwV3PPOBF4FNFyX7SzMFz27h05mzFyn0ljZBodmW6YrRHzh8LRuJXYij3i9mEdLSf3WPKs2zKJKFfIOYbCWiHKal7wnB6ZB6jCNEbiUlqrJbCtkId1cseSukawJw0+RpawxdvN7zU8uVxrzf1aTcHg83lIl8mlwUuQRFQvbk/bk+99dGPsb9hLyqVCt6YLRIOolgwnU2+rQcx9NJd1QcyzaRfF0rDPlt2ezUYJp9kAnjX0S4EV0lfjGWEnkySV5rqbZs7a4AA46/tsBm3sxK0DFSkN6/dVs8IAbMVLvQLlfvlmZcKOnjJTAytxa9twwxWlpASed7O2d6aQAZwVYBXyWUrQxj7vs+j4Mzx/Xb3qmeaKUktoM5f+3zRNt58nvTlr8fShUW1NSKRy29I2S8ntlw1Y8J3on7kyYoPGabasp9VZW8XZI306yukBkTa1G1oVtJumXwMROSMt8HhP/JI/t6WW9oDSsIXtfTEV8d2EveZMNjdGawfM94IatMLbVorCyFIFnAZ5oyW7I3l2OYzsTfEkbXkBQxMzKQY5WkzIlCx7e0TPp9ntkaiRktQQDUh84MIony97UzjmD9CWv2hXgVUo9GKFz3K5T7WyVGn1VyShNw5Zoewt8/hy7jCzgI7OB1jd7ZHZvI4Vq5XJD5vFHlvD4Ke57jNj8+kTBLnZY3jTe6aTpNLoZbA/L9jJmcdv2gXr7qt/KO+K6RRxmZE8O56Bm1/s6hRUOAN5nSxuS8jWmbYFcjQPkmmnrdmr/22VX1tW/zTfcqMkfB7LJQhba4iPnUW5u8Ub2KJjw1KClEGELVyoRnftaSkMnCvI7paAlHYDbfHMYhcEcZoKjxEm3sKyNWCUZvBibSUPGv3ecJo1trxAYLcWa8yzNZFzLQELb9i7q5ERpVxwTF9UjkYnD2tqrVJMFjGNHAl6WHqIfzQNRXoGvT+k3bTIsMUYk5HmS8fqtMRPjsVN0rNOvgZZ4kGw1Pu1BK0FrK9brGddRcB5JJM1hbOOEe/BsNfTDEYxlsgXcpvpp3OHkxmu43dwd7syU2e5O5pJfmB6qwbwwbsTSQJI9Igc6+aviqZqb4gW0QipYUTQGOqfvuE7fcNBy+N2CTPb+aEF0+icLTI6B++1SrCa/bXD75On3Y6ek7mS2IpcSAuQjjwhrLxpXF3KG62zRD1rBM4p9eIJaSy18uEeRBLD0hBvPcsppMkztALhnNddhRjd8pQkw6/LIgVAOD6I6dQFzQKXAMD3Ym6Zzlc+M7oNMgJi8pdsP7sS9B92TaUAb/7+T2i8/03MjO0PX3yN/ENTIPDGMwEAAiheS4BfM79/8H5s5GYx+sRFRsrL2SuS1V5VWNut9brXlW57Q+G+t3Awc++l0Y5hqQ7YO3zZS5PLvaLx2asmT3Zr/drrFuHeMGW5t/D5yhEa1BUCChACpximHfIxOuti+GaO69Al34p8UloqaCUrfWN+SS2PHg6FEuTgM3VSVTXsSUdfHDijhSepZ0a1jiAZZ0LfzsvltCtuojaxRbebjS9RBDgSBZO/8HEzNHTMOkutoRrUIrslntUnkiwqsMcljltXftHGbm/poQsOtvZM9me2M+ZtWi1zlRw5x4J/uBqa4KmxflIdfyDoSmcEua1ZICJOdt5UzMpuO823SzYMjO+uA/J3kGJKKaeSamqp/2eT1Fba/lT9kHSm7NzA+hfyJ+SM40yaM65D/m188i/jL7z8s/j/8L+/P+N/wb5/fv/+dWGYNrvD6XJ7vD5/IBgKR6KxeOL/uvItM53J5vKFYqlcqdbqjaa0Wu1Ot9cfDEfjyXQ2XyxX6812t1dkwP9PJ8mKqumGadmO6/kAIkwo40Iq07Id1/ODMIqTNMuLsqqbttP9ME7zsm77cV73g6AAwwmSohmW4wVRkhVV0w3Tsh3X84MwipM0y4uyqpu264dxmpfX+/P9/ddtP87rfgAQgpEoNAaLwxOIJDKFSqMzmCw2h8vjC4QisUQqkyuUKrVGq9MbjCazxWqzO5wut8fr8we3vrBM4VzqnpJHB2H2QbDe5/dZVqmQchxnLeMNF37AtnGuRka71/qQcXCphC7dSgiZkzhXBKSi/iIjJUHgv9nP2Kmfj7AgSOmywjSvEZcyiGWHbYl2gfcp60iqJH89ToyQ9VYeIlRaZzbqo6wEZ2GOW5WoNoWyEgwWDhf4wTVCOpd3MJUMyTHMqwpgjurr2XubnRukpc6H9tv4WzKFB+g9sTDNSvMlkBbJ7AAInIH6rBl2eXlxkwdpjF8DMDXV0lR2xePj8vUryyIgvUBBkCGjLl7Hd6TviVz+J02GjSBvtN5nsAJwFOykIXIDzMNPxn5DBYmxDAmabBv2svowDfh8tXNQflxKydAOeUHpV9bGrCUm28sUZh/WBMGO0rtov5ia9d1AufqnN4HKkqdqzKRdWour3uUcwTiglj4m46iivsMXCGOhgG8Mxyh17ylBdcQkC72WSb0bK3m6IBM4d1tQF0zGejfoUh0AjLpoZlQimVT4uMXH95qTxoIFUYlU6AlORX9FTokfhPEEUxgLFW8ZINIe5dz7zhSiQeBh7Stj1ZihYUuWNYgerJ1xkA0vxnr/ysPcVyWqcLzKSOVyJvIQs0KrC2Dvd2gFRt3EgQCYpnVYsnRKU6w1qheq9Vjo5Tyca73TSM0PgllomLME4PscHQqH5mXWy46jHVP/S6+RayntjSNZGANckeyKDjt3R4QxSw9VmvOJuwJDKiTbkUzqQ1JbxiC9wDsbs1KtazA5JQKaQ9QBIkJcJHBN6WLw9XXFbQMOpStTsIFAgDYheZ+i2nVOfIhOwA+cvmj31XhcPQtvRXX/VUKy5F7pmZKzALao5h6aK70X3NNLBojK3HCg+aAi8c8PPcjnNL8OKXI2H8nlQeqpubROsxXqIdbBcaZ/LWmwcrH/I7/KV6/zWGA2BtaOs+LpRIPSECmpNO35aDyN19wPJkYHMssCgIyfbdSd6WoFgNu1EozrIBeA6lDEQYoh2hcks44DmkljewDE0c0ACDMO1GNRfRWchbED6xTJ9A67ASRCCcZr1XEakhi0EDgZA2F9/x8BPunfWAYsFiXUD/ps6LS2yOviC6ngB7ZjsQjvDOkl0xIwS3JNU7cUXPv8FEG53lB3SgkgUj1xT48MHOQn6CqZUs8d5NJHPDdhb0ecdWR51ik9GfDL3QfuFOORwE7Bmn0oAvNflJSVKvU+Z48GPLaMGx9t2OkxIRzlQSkpAxzzQCYT8N+mtldVnqcmqtlyZB3OwjADd+t+MHnf9BWCsmFR4JLYhTbZPckVz/TG6boj/YIzLo7d+n7gZ/0IkBS5yGgIIUu2GHlWH/qBHV3JWjMP93ZL7aIxrgRM2+Cjbbvok22bXtYYhsC2LZV7zG5leZV6TRq3c4H938xBl4ZvO4+owzlk+Qa2cDemj9eXhyurlOywVA76fLbsTP8xvll2cdHnu1T/hwNfZ3X+K4PUyV5LYKy0iNyv1SuOIhVAJQcPDtTQPcadC2UAJTf4Ai5CEmqXCpGzFZyd5o/DgJnJ7bsV7KV2wfC5jdHbBpI0vieTv+qRYp30qX8KLQHza4XQrAQv7hM/SY58tZJG795hh9SM4WESNMwxhKRK2VlH2BgduJC38OHmO1narzKDICJiIMAx86VuxBgnfSm46hQS/r7AjC1nhtlYMO9m/kr10i2rdLIoYBqDgE+ZNB3DD9Q7CEcV6mKv8n4uC5N1HaSxFqulD3uQYOK6/FP223BszqRGhhDU7ONnYu5DJnqojjOtEDGl/Sr77kGcsN57w5WmLQwBpqquE3aW9W4Cfm4aksUFnUEw6RmEVtakK1qkkmMOgkTTHzmn5ZW0baHwfQakqKE+JjgQw0WhZY3qzKwHrqFwRBrAmNJKxqzDJByUDn3WRZ7VXc3nQdZeuygcEg0z9pQgrIWj32QkJwASD9QjJAtsoOQMYFZtJQSQxNpjAR+vXFbftqt9SoOu9Chy9nR6Gw2JzJPNcpIG9rUYabEyzNiSFvjlGlfRm17DTMRIz9YnarZnN9buMeq0XP2ogyZKQcaZQKVtJJb2AR13ihWpg+kRlXqPaIlsyis3pX4zyizBdl0heERl47dVjq/5bKIDjlekM9XSHCZMOCwZFtbH+PZW57YxmeXKEmOkDSfr08zZLDTq4VpQ+WyR/oNqL1LTJQtbTrOOTIinsTThKnpCkUxV2cmp1CSfTCG6knEIMvoizFwqfcoPwEN3Wr0R/baYEA28xPeMeM3tHoc0JidXqgaQDIOhim+VoxJVzk7MlBE71YyWHsWZTKy6kzYtg40bdOXv7FYApP0eqtSFphXuhPP1Lp/odT4rC+YgqlBUWuxEhXZCIpnKbJvjxh2YiLWIkV4aVwI2dvt24uC9mJAkKeACH2Y8RJ/72osdjdaC/PU4+0YCN5MbmI7/0hc=') + format('woff2'); + /* #ifdef MP-ALIPAY */ + src: url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.woff2') format('woff2'), + url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.woff') format('woff'), + url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.ttf') format('truetype'); + /* #endif */ + font-weight: normal; + font-style: normal; +} +[class*='cicon-'] { + font-family: 'coloricon'; + display: inline-block; +} + +.cicon-Aa:before { + content: '\e7a1'; +} +.cicon-accounts:before { + content: '\e681'; +} +.cicon-accounts-o:before { + content: '\e686'; +} +.cicon-add:before { + content: '\e6e4'; +} +.cicon-add-round:before { + content: '\e717'; +} +.cicon-add-round-o:before { + content: '\e718'; +} +.cicon-alarm:before { + content: '\e61e'; +} +.cicon-album:before { + content: '\e759'; +} +.cicon-alipay:before { + content: '\e6e1'; +} +.cicon-android:before { + content: '\e6e2'; +} +.cicon-angle:before { + content: '\e605'; +} +.cicon-apple:before { + content: '\e8e7'; +} +.cicon-apps:before { + content: '\e737'; +} +.cicon-archive:before { + content: '\e7ae'; +} +.cicon-archive-o:before { + content: '\e7ad'; +} +.cicon-arrow:before { + content: '\e608'; +} +.cicon-at-line:before { + content: '\e75c'; +} +.cicon-avatar:before { + content: '\e663'; +} +.cicon-avatar-o:before { + content: '\e665'; +} +.cicon-avatars:before { + content: '\e67e'; +} +.cicon-avatars-o:before { + content: '\e680'; +} +.cicon-back:before { + content: '\e600'; +} +.cicon-backspace:before { + content: '\e6a9'; +} +.cicon-backup:before { + content: '\e61f'; +} +.cicon-backup-restore:before { + content: '\e62d'; +} +.cicon-barcode:before { + content: '\e71f'; +} +.cicon-book:before { + content: '\e6a2'; +} +.cicon-bookmark:before { + content: '\e6a3'; +} +.cicon-bookmark-o:before { + content: '\e697'; +} +.cicon-bookmarks:before { + content: '\e6a6'; +} +.cicon-box:before { + content: '\e714'; +} +.cicon-box-block:before { + content: '\e6ac'; +} +.cicon-box-right:before { + content: '\e6a0'; +} +.cicon-brand:before { + content: '\e726'; +} +.cicon-brand-o:before { + content: '\e727'; +} +.cicon-building:before { + content: '\e6c3'; +} +.cicon-building-o:before { + content: '\e6c7'; +} +.cicon-camera:before { + content: '\e6fa'; +} +.cicon-camera-add:before { + content: '\e736'; +} +.cicon-camera-add-o:before { + content: '\e735'; +} +.cicon-camera-lens:before { + content: '\e68f'; +} +.cicon-camera-lens-o:before { + content: '\e68e'; +} +.cicon-camera-o:before { + content: '\e6fb'; +} +.cicon-camera-rotate:before { + content: '\e71e'; +} +.cicon-card:before { + content: '\e744'; +} +.cicon-cardboard:before { + content: '\e7a9'; +} +.cicon-cardboard-o:before { + content: '\e7aa'; +} +.cicon-cardboard-off-o:before { + content: '\e7af'; +} +.cicon-cart:before { + content: '\e70b'; +} +.cicon-cart-o:before { + content: '\e708'; +} +.cicon-chat:before { + content: '\e739'; +} +.cicon-chat-bubble:before { + content: '\e69b'; +} +.cicon-chat-bubble-o:before { + content: '\e6a7'; +} +.cicon-chat-list:before { + content: '\e69d'; +} +.cicon-chat-list-o:before { + content: '\e6aa'; +} +.cicon-chat-o:before { + content: '\e73c'; +} +.cicon-chat-smile:before { + content: '\e779'; +} +.cicon-chat-smile-o:before { + content: '\e78e'; +} +.cicon-chat-smiles:before { + content: '\e76b'; +} +.cicon-chat-smiles-o:before { + content: '\e74a'; +} +.cicon-check:before { + content: '\e69f'; +} +.cicon-checkbox:before { + content: '\e713'; +} +.cicon-checkbox-o:before { + content: '\e715'; +} +.cicon-check-round:before { + content: '\e6f1'; +} +.cicon-check-round-o:before { + content: '\e6f2'; +} +.cicon-choiceness:before { + content: '\e728'; +} +.cicon-choiceness-o:before { + content: '\e729'; +} +.cicon-chrome:before { + content: '\e6e3'; +} +.cicon-circle:before { + content: '\e7b0'; +} +.cicon-circle-o:before { + content: '\e7b1'; +} +.cicon-close:before { + content: '\e6ed'; +} +.cicon-close-round:before { + content: '\e6f3'; +} +.cicon-close-round-o:before { + content: '\e6f4'; +} +.cicon-clothes:before { + content: '\e72a'; +} +.cicon-clothes-o:before { + content: '\e72b'; +} +.cicon-cloud:before { + content: '\e64e'; +} +.cicon-cloud-done:before { + content: '\e641'; +} +.cicon-cloud-download:before { + content: '\e647'; +} +.cicon-cloud-o:before { + content: '\e646'; +} +.cicon-cloud-off:before { + content: '\e64b'; +} +.cicon-cloud-upload:before { + content: '\e687'; +} +.cicon-code-box:before { + content: '\e7c3'; +} +.cicon-coin:before { + content: '\e78a'; +} +.cicon-coin-o:before { + content: '\e79d'; +} +.cicon-comment:before { + content: '\e738'; +} +.cicon-comment-o:before { + content: '\e70e'; +} +.cicon-community:before { + content: '\e742'; +} +.cicon-community-o:before { + content: '\e743'; +} +.cicon-countdown:before { + content: '\e722'; +} +.cicon-countdown-o:before { + content: '\e723'; +} +.cicon-creative:before { + content: '\e72c'; +} +.cicon-creative-o:before { + content: '\e72d'; +} +.cicon-crop:before { + content: '\e6d9'; +} +.cicon-crown:before { + content: '\e776'; +} +.cicon-crown-o:before { + content: '\e777'; +} +.cicon-cut:before { + content: '\e74b'; +} +.cicon-DarkMode:before { + content: '\e7c4'; +} +.cicon-dashboard:before { + content: '\e62e'; +} +.cicon-delete:before { + content: '\e6bd'; +} +.cicon-delete-close:before { + content: '\e6ae'; +} +.cicon-delete-line:before { + content: '\e707'; +} +.cicon-delete-line-o:before { + content: '\e709'; +} +.cicon-delete-o:before { + content: '\e69a'; +} +.cicon-deliver:before { + content: '\e7f7'; +} +.cicon-deliver-o:before { + content: '\e6ff'; +} +.cicon-demo:before { + content: '\e916'; +} +.cicon-discover:before { + content: '\e70c'; +} +.cicon-discover-o:before { + content: '\e702'; +} +.cicon-discuss-fill:before { + content: '\e790'; +} +.cicon-discuss-line:before { + content: '\e78f'; +} +.cicon-dollar:before { + content: '\e79f'; +} +.cicon-dollar-o:before { + content: '\e79e'; +} +.cicon-done:before { + content: '\e633'; +} +.cicon-done-all:before { + content: '\e62a'; +} +.cicon-douyin:before { + content: '\e6e7'; +} +.cicon-drop-down:before { + content: '\e61c'; +} +.cicon-drop-up:before { + content: '\e61d'; +} +.cicon-eject:before { + content: '\e63a'; +} +.cicon-ellipse:before { + content: '\e74c'; +} +.cicon-emoji:before { + content: '\e78d'; +} +.cicon-emoji-o:before { + content: '\e6ee'; +} +.cicon-equalizer:before { + content: '\e802'; +} +.cicon-eraser:before { + content: '\e770'; +} +.cicon-eraser-o:before { + content: '\e772'; +} +.cicon-evaluate:before { + content: '\e7f0'; +} +.cicon-evaluate-o:before { + content: '\e700'; +} +.cicon-event-close:before { + content: '\e6a5'; +} +.cicon-event-done:before { + content: '\e6b2'; +} +.cicon-event-list:before { + content: '\e6b8'; +} +.cicon-explore:before { + content: '\e628'; +} +.cicon-explore-line:before { + content: '\e719'; +} +.cicon-explore-line-o:before { + content: '\e710'; +} +.cicon-explore-o:before { + content: '\e626'; +} +.cicon-extension:before { + content: '\e620'; +} +.cicon-extension-o:before { + content: '\e63f'; +} +.cicon-eye:before { + content: '\e740'; +} +.cicon-eye-favor:before { + content: '\e7b4'; +} +.cicon-eye-favor-o:before { + content: '\e7b5'; +} +.cicon-eye-o:before { + content: '\e741'; +} +.cicon-eye-off:before { + content: '\e7b3'; +} +.cicon-eye-off-o:before { + content: '\e7b2'; +} +.cicon-facebook:before { + content: '\e6ea'; +} +.cicon-favorite:before { + content: '\e623'; +} +.cicon-favorite-o:before { + content: '\e621'; +} +.cicon-female:before { + content: '\e72f'; +} +.cicon-file:before { + content: '\e857'; +} +.cicon-file-copy:before { + content: '\e85c'; +} +.cicon-file-copy-o:before { + content: '\e7bc'; +} +.cicon-file-o:before { + content: '\e7bb'; +} +.cicon-file-text:before { + content: '\e858'; +} +.cicon-file-text-o:before { + content: '\e7b9'; +} +.cicon-filter:before { + content: '\e6ec'; +} +.cicon-fingerprint:before { + content: '\e63b'; +} +.cicon-first-page:before { + content: '\e60c'; +} +.cicon-flag:before { + content: '\e64d'; +} +.cicon-flag-o:before { + content: '\e64c'; +} +.cicon-flash-close:before { + content: '\e73b'; +} +.cicon-flash-off:before { + content: '\e6d5'; +} +.cicon-flash-on:before { + content: '\e6dc'; +} +.cicon-flash-open:before { + content: '\e74f'; +} +.cicon-folder:before { + content: '\e6a1'; +} +.cicon-folder-add:before { + content: '\e6b4'; +} +.cicon-folder-o:before { + content: '\e6b0'; +} +.cicon-folder-special:before { + content: '\e65c'; +} +.cicon-forward:before { + content: '\e601'; +} +.cicon-fullscreen:before { + content: '\e915'; +} +.cicon-fullscreen-exit:before { + content: '\e914'; +} +.cicon-game:before { + content: '\e6c0'; +} +.cicon-game-o:before { + content: '\e6d1'; +} +.cicon-git-commit:before { + content: '\e7be'; +} +.cicon-git-commit-o:before { + content: '\e7bd'; +} +.cicon-github:before { + content: '\e6e9'; +} +.cicon-github-circle:before { + content: '\ead8'; +} +.cicon-goods:before { + content: '\e778'; +} +.cicon-goodsnew:before { + content: '\e7bf'; +} +.cicon-goodsnew-o:before { + content: '\e7c0'; +} +.cicon-goods-o:before { + content: '\e70f'; +} +.cicon-GooglePlaylogo:before { + content: '\e6e5'; +} +.cicon-grid:before { + content: '\e6ce'; +} +.cicon-grid-o:before { + content: '\e6cc'; +} +.cicon-group:before { + content: '\e7f5'; +} +.cicon-group-o:before { + content: '\e753'; +} +.cicon-guanli:before { + content: '\e750'; +} +.cicon-headset:before { + content: '\e6a4'; +} +.cicon-headset-mic:before { + content: '\e6b1'; +} +.cicon-help:before { + content: '\e66b'; +} +.cicon-help-o:before { + content: '\e65e'; +} +.cicon-home:before { + content: '\e70d'; +} +.cicon-home-2:before { + content: '\e6fd'; +} +.cicon-home-2-o:before { + content: '\e6cf'; +} +.cicon-home-3:before { + content: '\e6fc'; +} +.cicon-home-3-o:before { + content: '\e6e0'; +} +.cicon-home-4:before { + content: '\e732'; +} +.cicon-home-4-o:before { + content: '\e6e6'; +} +.cicon-home-community:before { + content: '\e799'; +} +.cicon-home-dot:before { + content: '\e794'; +} +.cicon-home-dot-o:before { + content: '\e797'; +} +.cicon-home-line:before { + content: '\e793'; +} +.cicon-home-line-o:before { + content: '\e792'; +} +.cicon-home-o:before { + content: '\e70a'; +} +.cicon-home-sm:before { + content: '\e798'; +} +.cicon-home-smile:before { + content: '\e79c'; +} +.cicon-home-smile-o:before { + content: '\e7a0'; +} +.cicon-home-smline:before { + content: '\e791'; +} +.cicon-home-smline-o:before { + content: '\e731'; +} +.cicon-home-sm-o:before { + content: '\e79b'; +} +.cicon-hotel:before { + content: '\e7a8'; +} +.cicon-hotel-o:before { + content: '\e7a3'; +} +.cicon-huohu:before { + content: '\e72e'; +} +.cicon-IE:before { + content: '\e922'; +} +.cicon-image-text:before { + content: '\e781'; +} +.cicon-image-text-o:before { + content: '\e758'; +} +.cicon-import-export:before { + content: '\e615'; +} +.cicon-info:before { + content: '\e6ef'; +} +.cicon-info-o:before { + content: '\e705'; +} +.cicon-input:before { + content: '\e75f'; +} +.cicon-input-o:before { + content: '\e6c8'; +} +.cicon-keyboard:before { + content: '\e6b6'; +} +.cicon-kinds:before { + content: '\e748'; +} +.cicon-last-page:before { + content: '\e60d'; +} +.cicon-layout:before { + content: '\e7e8'; +} +.cicon-layout-o:before { + content: '\e7e7'; +} +.cicon-LightMode:before { + content: '\e7ba'; +} +.cicon-link:before { + content: '\e6ab'; +} +.cicon-link-off:before { + content: '\e6b9'; +} +.cicon-loader-fill:before { + content: '\e76d'; +} +.cicon-loading:before { + content: '\e746'; +} +.cicon-loading1:before { + content: '\e749'; +} +.cicon-loading2:before { + content: '\e7f1'; +} +.cicon-location-off:before { + content: '\e671'; +} +.cicon-location-off-o:before { + content: '\e66d'; +} +.cicon-location-on:before { + content: '\e65f'; +} +.cicon-location-on-o:before { + content: '\e661'; +} +.cicon-lock:before { + content: '\e6ad'; +} +.cicon-lock-o:before { + content: '\e6b3'; +} +.cicon-lock-open:before { + content: '\e6ba'; +} +.cicon-logout:before { + content: '\e76e'; +} +.cicon-loop:before { + content: '\e616'; +} +.cicon-magic:before { + content: '\e6b7'; +} +.cicon-magic-o:before { + content: '\e6c2'; +} +.cicon-mail:before { + content: '\e6be'; +} +.cicon-mail-o:before { + content: '\e6bc'; +} +.cicon-male:before { + content: '\e730'; +} +.cicon-mic:before { + content: '\e656'; +} +.cicon-mic-none:before { + content: '\e642'; +} +.cicon-mic-off:before { + content: '\e652'; +} +.cicon-miniprogram:before { + content: '\e7d6'; +} +.cicon-mobile:before { + content: '\e854'; +} +.cicon-mobile-o:before { + content: '\e7b6'; +} +.cicon-moneybag:before { + content: '\e7ce'; +} +.cicon-moneybag-o:before { + content: '\e7d1'; +} +.cicon-more:before { + content: '\e688'; +} +.cicon-more-tag:before { + content: '\e672'; +} +.cicon-move:before { + content: '\e768'; +} +.cicon-move-round:before { + content: '\e602'; +} +.cicon-move-round-o:before { + content: '\e603'; +} +.cicon-music:before { + content: '\e795'; +} +.cicon-music-off:before { + content: '\e796'; +} +.cicon-my:before { + content: '\e78c'; +} +.cicon-my-o:before { + content: '\e78b'; +} +.cicon-near-me:before { + content: '\e654'; +} +.cicon-near-me-o:before { + content: '\e649'; +} +.cicon-not:before { + content: '\e667'; +} +.cicon-notice:before { + content: '\e666'; +} +.cicon-notice-active:before { + content: '\e66f'; +} +.cicon-notice-active-o:before { + content: '\e65d'; +} +.cicon-notice-o:before { + content: '\e664'; +} +.cicon-notice-off:before { + content: '\e6b5'; +} +.cicon-notice-off-o:before { + content: '\e6bb'; +} +.cicon-numcode:before { + content: '\e755'; +} +.cicon-order:before { + content: '\e786'; +} +.cicon-order-o:before { + content: '\e7b8'; +} +.cicon-paint:before { + content: '\e75d'; +} +.cicon-paint-o:before { + content: '\e75a'; +} +.cicon-palette:before { + content: '\e696'; +} +.cicon-palette-o:before { + content: '\e691'; +} +.cicon-pause:before { + content: '\e669'; +} +.cicon-pause-circle:before { + content: '\e678'; +} +.cicon-person:before { + content: '\e679'; +} +.cicon-person-add:before { + content: '\e668'; +} +.cicon-person-add-o:before { + content: '\e66a'; +} +.cicon-person-o:before { + content: '\e67d'; +} +.cicon-person-pin-circle:before { + content: '\e66c'; +} +.cicon-person-pin-circle-o:before { + content: '\e670'; +} +.cicon-phone:before { + content: '\e6f0'; +} +.cicon-phone-call:before { + content: '\e6d7'; +} +.cicon-pic:before { + content: '\e756'; +} +.cicon-pic-o:before { + content: '\e69e'; +} +.cicon-pin-drop:before { + content: '\e648'; +} +.cicon-pin-drop-o:before { + content: '\e655'; +} +.cicon-place:before { + content: '\e651'; +} +.cicon-place-o:before { + content: '\e650'; +} +.cicon-play-arrow:before { + content: '\e66e'; +} +.cicon-play-circle:before { + content: '\e674'; +} +.cicon-play-circle-o:before { + content: '\e67f'; +} +.cicon-popover:before { + content: '\e74e'; +} +.cicon-popover-o:before { + content: '\e757'; +} +.cicon-present:before { + content: '\e73a'; +} +.cicon-present-o:before { + content: '\e711'; +} +.cicon-progress:before { + content: '\e784'; +} +.cicon-qq:before { + content: '\e7d9'; +} +.cicon-qr-code-fill:before { + content: '\e767'; +} +.cicon-qr-code-line:before { + content: '\e75e'; +} +.cicon-quill:before { + content: '\e760'; +} +.cicon-quill-o:before { + content: '\e761'; +} +.cicon-radio:before { + content: '\e6d4'; +} +.cicon-radiobox:before { + content: '\e763'; +} +.cicon-radiobox-o:before { + content: '\e75b'; +} +.cicon-recharge:before { + content: '\e71c'; +} +.cicon-recharge-o:before { + content: '\e71d'; +} +.cicon-record:before { + content: '\e7a4'; +} +.cicon-record-o:before { + content: '\e7a6'; +} +.cicon-redo:before { + content: '\e612'; +} +.cicon-redpacket:before { + content: '\e7d3'; +} +.cicon-redpacket-o:before { + content: '\e71a'; +} +.cicon-refresh:before { + content: '\e611'; +} +.cicon-repair:before { + content: '\e73f'; +} +.cicon-repair-o:before { + content: '\e73e'; +} +.cicon-repeat:before { + content: '\e617'; +} +.cicon-replay:before { + content: '\e619'; +} +.cicon-reply:before { + content: '\e618'; +} +.cicon-reply-all:before { + content: '\e614'; +} +.cicon-road-map:before { + content: '\e769'; +} +.cicon-road-map-o:before { + content: '\e76a'; +} +.cicon-round:before { + content: '\e716'; +} +.cicon-round-angle:before { + content: '\e6f5'; +} +.cicon-round-angle-o:before { + content: '\e6f6'; +} +.cicon-round-arrow-line:before { + content: '\e734'; +} +.cicon-round-box:before { + content: '\e604'; +} +.cicon-safe:before { + content: '\e77f'; +} +.cicon-safe-check:before { + content: '\e875'; +} +.cicon-safe-check-o:before { + content: '\e876'; +} +.cicon-safe-flash:before { + content: '\e783'; +} +.cicon-safe-flash-o:before { + content: '\e775'; +} +.cicon-safe-key:before { + content: '\e76c'; +} +.cicon-safe-key-o:before { + content: '\e766'; +} +.cicon-safe-o:before { + content: '\e77e'; +} +.cicon-save:before { + content: '\e677'; +} +.cicon-save-o:before { + content: '\e684'; +} +.cicon-scan:before { + content: '\e703'; +} +.cicon-scissors:before { + content: '\e762'; +} +.cicon-search:before { + content: '\e6f7'; +} +.cicon-search-line:before { + content: '\e771'; +} +.cicon-searchlist:before { + content: '\e720'; +} +.cicon-search-o:before { + content: '\e782'; +} +.cicon-search-sm:before { + content: '\e631'; +} +.cicon-service:before { + content: '\e73d'; +} +.cicon-service-fill:before { + content: '\e704'; +} +.cicon-service-o:before { + content: '\e721'; +} +.cicon-set:before { + content: '\e773'; +} +.cicon-set-list:before { + content: '\e76f'; +} +.cicon-set-o:before { + content: '\e774'; +} +.cicon-settings:before { + content: '\e77a'; +} +.cicon-settings-o:before { + content: '\e780'; +} +.cicon-share:before { + content: '\e6c5'; +} +.cicon-share-line-o:before { + content: '\e74d'; +} +.cicon-shengji:before { + content: '\e747'; +} +.cicon-shopping-cart:before { + content: '\e685'; +} +.cicon-shopping-cart-o:before { + content: '\e676'; +} +.cicon-show:before { + content: '\e785'; +} +.cicon-show-o:before { + content: '\e787'; +} +.cicon-shuffle:before { + content: '\e61a'; +} +.cicon-sip:before { + content: '\e764'; +} +.cicon-sip-o:before { + content: '\e765'; +} +.cicon-skip-next:before { + content: '\e6dd'; +} +.cicon-skip-previous:before { + content: '\e6d6'; +} +.cicon-slack:before { + content: '\e87b'; +} +.cicon-slack-square:before { + content: '\e891'; +} +.cicon-sort:before { + content: '\e6bf'; +} +.cicon-sort-order:before { + content: '\e6fe'; +} +.cicon-sound:before { + content: '\e77b'; +} +.cicon-sponsor:before { + content: '\e77c'; +} +.cicon-sponsor-o:before { + content: '\e77d'; +} +.cicon-star:before { + content: '\e683'; +} +.cicon-star-half:before { + content: '\e67c'; +} +.cicon-star-o:before { + content: '\e67b'; +} +.cicon-stock:before { + content: '\e789'; +} +.cicon-stop:before { + content: '\e6db'; +} +.cicon-store:before { + content: '\e7ac'; +} +.cicon-store-0:before { + content: '\e7ab'; +} +.cicon-store-2:before { + content: '\e7a7'; +} +.cicon-store-2-o:before { + content: '\e7a5'; +} +.cicon-sub-left:before { + content: '\e60b'; +} +.cicon-sub-right:before { + content: '\e60f'; +} +.cicon-subtitles:before { + content: '\e6da'; +} +.cicon-subtitles-o:before { + content: '\e6d8'; +} +.cicon-sync-alt:before { + content: '\e613'; +} +.cicon-tag:before { + content: '\e751'; +} +.cicon-tag-o:before { + content: '\e752'; +} +.cicon-taobao:before { + content: '\e712'; +} +.cicon-terminal:before { + content: '\e7c1'; +} +.cicon-terminal-o:before { + content: '\e7c2'; +} +.cicon-thumb-down:before { + content: '\e6c1'; +} +.cicon-thumb-down-o:before { + content: '\e6c9'; +} +.cicon-thumb-up:before { + content: '\e6c6'; +} +.cicon-thumb-up-line:before { + content: '\e71b'; +} +.cicon-thumb-up-line-o:before { + content: '\e6eb'; +} +.cicon-thumb-up-o:before { + content: '\e6cb'; +} +.cicon-ticket:before { + content: '\e800'; +} +.cicon-ticket-o:before { + content: '\e701'; +} +.cicon-time:before { + content: '\e6f8'; +} +.cicon-time-o:before { + content: '\e6f9'; +} +.cicon-timer:before { + content: '\e69c'; +} +.cicon-title:before { + content: '\e82f'; +} +.cicon-titles:before { + content: '\e745'; +} +.cicon-toggle:before { + content: '\e706'; +} +.cicon-toggle-o:before { + content: '\e733'; +} +.cicon-topbar:before { + content: '\e788'; +} +.cicon-translate:before { + content: '\e79a'; +} +.cicon-tree:before { + content: '\e659'; +} +.cicon-Tt:before { + content: '\e7a2'; +} +.cicon-twiter:before { + content: '\e6e8'; +} +.cicon-cicon-community-o:before { + content: '\e6df'; +} +.cicon-undo:before { + content: '\e61b'; +} +.cicon-unfold-less:before { + content: '\e60e'; +} +.cicon-unfold-more:before { + content: '\e609'; +} +.cicon-upstage:before { + content: '\e724'; +} +.cicon-upstage-o:before { + content: '\e725'; +} +.cicon-view-agenda:before { + content: '\e639'; +} +.cicon-view-array:before { + content: '\e636'; +} +.cicon-view-carousel:before { + content: '\e638'; +} +.cicon-view-column:before { + content: '\e632'; +} +.cicon-view-day:before { + content: '\e627'; +} +.cicon-view-headline:before { + content: '\e62b'; +} +.cicon-view-list:before { + content: '\e63c'; +} +.cicon-view-module:before { + content: '\e629'; +} +.cicon-view-quilt:before { + content: '\e630'; +} +.cicon-volume:before { + content: '\e6c4'; +} +.cicon-volume-off:before { + content: '\e6cd'; +} +.cicon-warn:before { + content: '\e662'; +} +.cicon-warn-o:before { + content: '\e675'; +} +.cicon-wechat-pay:before { + content: '\e7e6'; +} +.cicon-weibo-fill:before { + content: '\e7e4'; +} +.cicon-weibo-o:before { + content: '\e7e3'; +} +.cicon-weixin:before { + content: '\e6de'; +} +.cicon-whatshot:before { + content: '\e6ca'; +} +.cicon-whatshot-o:before { + content: '\e6d0'; +} +.cicon-wifi:before { + content: '\e6d2'; +} +.cicon-wifi-off:before { + content: '\e6d3'; +} +.cicon-yamaxun:before { + content: '\e7b7'; +} +.cicon-zuoji:before { + content: '\e754'; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/icon/_icon.scss b/yudao-mall-uniapp-master/sheep/scss/icon/_icon.scss new file mode 100644 index 0000000..f277fc8 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/icon/_icon.scss @@ -0,0 +1,181 @@ +@font-face { + font-family: 'colorui'; /* Project id 2620914 */ + src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAA08AAsAAAAAIIAAAAzuAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACIUgqqHKM2ATYCJAOBJAtUAAQgBYR5B4MwGwIcs6JmclIAsv9LAT3W/EiCkXnK3Xny3Onomo8T7OwIi5b6OurgI7NQyMA0DecgDbMUXzZtybquth6v1ed4jzlbhWe8oZQGrbWZlVt/3xesuXQIRTwSkka/imlMNEIkda7mMvhA4790wiQPssgK0F3uNkCb2eyTq63TFabC13bqKnT/f9r2XRijHkYPBoxYQdioY200RxgzwE6Gn4NsYyX+qsD9VRvVQwAcs1sVVQBPpMFHVTiQ0SY0khn2Z8ycgyURv1jvJyjWdAPEHyCPBYW6EyErvLhvBgDU54DA7uCctjbtpwoHYQbOEsApsYk9Q2BggezBcZ+bo/+fmistkypBinEV7nXZqewmBwsHezD9/D5TnvCgwKyQciUAWeHIo6/ynRppC6ZrdCN/KHpRo/+MrZoHW6HrYDSjXzAweu/6SUCAN2ef1Ty/fTAGK8mlMeSwViRETblKImm0Hp1UQTJZa0G9Yhj8okHsxS/As/ft+UiSgYCgQ7AutDE508bX574s8v4P3VE/lPo82JkFQAMkYMowlxgUF7Bv2AGa8oiXfRpOYI4LXCTyWoFlG+zFKuqMab5PL8+X18tXf7FkeEnXczQarXBs0Sv6CQppD6S+92ewm2hT9tS1yjKWvNppv6d++Ar+Gf/X8z/lsbZxdLK1s1dSVdNxMFTWUeEFUVLR1dVTUCBBUloGZuYmVhILU0syUWhcBzJvvPJEcETWREBkQwRFjkRIptI4RLZETWRH1EX2RE+kBDEQaUFsRNrEjumAHsAcQE9ghqDPwNqjr2BGoO9gKqAfYKqgn2BqoF9g6qB/YBqg/xBpQhoRGZPGRLqkCZEeaRKj0QyYImgWTAY0ByYLmgeTAy2AyYMWgYGWgIG2wMxA22DmoDMwE9A1mBXoFkwCeoTIgv8GM/VoH+0swVlc5ok/igfKvyxXpsudskcG8ixSB8jocEkfJ6IThI+wkJDGpULiYQNCXq7Uqn0FpjTnzsr4aIpxIHfzRQpAVD23bETXqCa6tPK6zRhFqR+qD9RLM5Cjyzm3ZWSqD+e2dKdUpVStVqCcVVE4Kev1eHn5F5a7yUBScDhVqvfzsazL0czrlY407QMbxpfhPkHiWXd5Tgk771nuZqNCNp7T2HSoUDaYtDH1EEshIf2TcnB+gjWn++SFQt11rOufxDS/zcDpRUgt9wi7/3YS8vwnEddvEnT+OPpYYJjERIpR8cUD2Di5NDOC2FLH5/TJSLf4rpNHRzVwx2WWMzyRACnwdytZloIwScBjJbB0iE/ybmMSFHLKbupqsZvm2Jo8OtOPn5UgbpdKMEXLck6mEgz7zHC/lmW4fzUvh66me6Z9xvgBdcE+afyYIzMzWgiag8AdQ0IDoDpdaiSrlTUyp4h3GBgNxql/KnkE2VFmUsdEIGO3v7Pjm5GpNGKz45sX/021DR1Dig2386gn2PMeRtYS1JyPTq9ngOAToofLeXQ2uh6XsnhwHAmmyz9hlt3G1QBgO5xKYrkuJhDfzV+s8MKaPbsbvs9P0ef4Ib0SEG0A7y4DfAALepMfo8edgliTpS13fj94y+MnLUuH95qxPX/y4iVapVK+E9wyzSqmgZUAHsBKBg+ztxFDu11io9k6AXssDwBTw0Lq3GlhR8GuC0kFsuTJTinNTH8YzXDc+AzgdXYKmml5jZVLUHPqdjWWRkxiEwnQsdyvP/yzouBvFPmvQH9egEYtXLNe85Aew3+NUBlEyiJYZSZ9NfS3cMr4G7rhCJgml8yFcKlybogqj/VKxI3FkN8Znr5o8FZqpqbSuvOYpRnyJwt818FeEcfjp1LHbhsO7gAPfLt/+NIusKB3XzZc3XuQl9tzpbAJFehj3yOgf2S4t/XsDcfpY3bdAHW1GgGgR+2RxRV+p2DLZZVPBbjHONiPTjeQ5Gso+/LR2Wp2dhiqks+h7PtnQJmVFXRbi2N56tEZtx16JBumdNOeueP7W97VxpF9J0XS3NaDfHS2jQOpY6OBT9c/eh4jOl0xPPDU5ao3qG6qqjq3plKlrlFW17+h4oGjUqFWq3LVuarKgw1OE+VE87OhPE+9Kd1Ahs0BF+78MkxA44encRqfPowHj7ZCxQqOszhD4aDIkMCQTo8TC0xN7VffMHwX29/i/dF3OckiAtFOLbj7+64wnK6mllkgcP2QDiTajrvYmcUmbEsd1HXZtJVGXpWcXCXX/OyeJ1dVJWvkP2f0rY2kJl9GicWULN+MlJ1T4nyZmb1EKJ13fpMJH++JNWW19UjGwyUr9F0RlV6VvVKp7vJJM8+ZN+Z8NVLvOhZoroi+I2J4P+g/Di/GesJ2e5d/oufW1KvBif5du2yrUSTP2ZfDi3G9Csnih52StufbeuKMWS962doJGkXfi65X1hqdpyOuORnZ9cyiY0GNAjsHr2yQAEkOufEpROAEOjVMRIJABsGN6DtspT4lZQJ3be+VrMCJPSfpmCw0EDFka80QdCZsrK2sGb6QPxHpM088MOO0sat8ARBgqb1qeVVSUpVc/bNSdl6VpJb/zBevuH3Wl56z3Uz0Ukkkql4SlUriiy1uk83GAKbOMdnOqVJeZPgEPsno9cwQ1Un92sBX5i/qcnkSrV87OdFMz1hmHJVZy3zl2RF8fcNWA5tyw+sHsicRgdhlPECezfNccBelqdHRwnjtwoebyYLWjS4k/ahVlv334/VDlJPThW5PIExEwvbQp0/LEIGo8H/mdjTEvgjEOglNROL20P9yytCH9BDlTSW2sc5/MKcciQNMAWKkLB/0t1Y1PACR49Aco9z+mT9+eFo2fViG2bOKBYIk7sICiU9vxtPzOE4uaMIkb/emlgQk5H24X+ANMBxnw8lPUibmP1kaK4ZSLboDbIbrbHF+9tfPGtLKdEhHLoik55+9qjwh3p4yZS70bHlA6y1A+sFR1pSxz/5DQ5mmPVK8ElnT/FO71B/bHGBT3lQg17Nckr9qSGyoTxyeUmpuSJxicYbJxX6/WG+A2I82xsc7VQuqndiGlIByYlPl6C+QN7sFIkuXmE1RrGNtlGvypNsvXZpnFkL6z9z8PEm9fW0sEP3JlqmAOE7Z8ZgsWgBHNzrK8Bu2qlA0uFJ5RGcHAVYteO1XwceCX18jPX3QajWyPAlFSfJkZqVcUELJ8jS+RBLhm53V2Zk1jAQeDkh2jlVT3BpkGOmFZWEJjvvHXT67j1bdFQERyBUx27cTYq6FwjJnLXxPm8ZVKiqx8++3VY3z20d2Vb3AaydhdHQMBFi4C+NCHyISCzhrE7/Fis1v675sShv1TDZ5Lo02pf3pJXw9o/3SS9Kr9frTz9f5en/p5kti3vEqHLjkaUr2bKAD35zw2gEWSvOWpdNily6rwLo8URdQb1Fkh2QGBWWGZJtCsjJsZnB2sCkrGHCWZYrpZGYGZYUc4fb0HOWC8PXDl19av37D+pdeKigAN1FbN7AW7O2/+86asr7qHFUqIey25YQwTxe0143GawGM6Oru3XOYY2fPHBUxdpBCvz8CUYMZQRkzDCbAQfL4ibc5wMrfKJBnWi4lHxy7YUITzAntTjDAUw/TslY0hL1iP7SACb2KU05jZJKfwkSwXJAFOoulAQBg6dwTl4zTTjITdYo4+lAV+SPs2V4BYDTnQ6AzbZLUuhW+/T9WY5ZtGSCr4kXkcZ9yS1A5xe3EamQMA/CTWHldRm/AHf1YeOpFhwc+6FssOIY1QCrFveu+y4GTC1i+mUubpDDlv8+nhlXRTEWpo3wsQ6Jgrff322zCCv4v8jDHZenBNAxOvUKcqfrfciEwnpf9uxzZ4EHj3jTKBMDb8wH/d85p+B2WJZOhQC6hPAiCMSRIznCwCp8RtGBVKDhrgjfp5upB05yNYQdgwsdFoIZPQaj4EaSG72AV/idobf9CoZFhgrcX2LrBYCTzd04IJIMWwUokCsvQutxRmCOx5ncQzXJJjya/9AmoTigRE3+crb6AEqiei9TzaMocipCwEOca7w7yHEVFmIJiP2autkejUPYQvsLC6FhHgMSAJgRWYtSEgkohZ50kyh9sJP92d0BkJidRkZ+M+gSA6keIvRMmfGNK8AUpaT5Nal2bi0yxrYaE05mggnBuJAf5AxcqOUrf6ivMFyuUVbaN7JmFVOK3ayn2GMFK9Gt94uMZQElFzYKGlo6egZGJFVZZo2iG5XhBlGRF1XTDtGx2h9Pl9nh9tYYxqCzApe1YOzF9D13CWakbMRYwsOOe1gGdsKtyrKFLId7t6fsR97D7YZR6MInOzYVMOCmjtgdqlN4MKhtX8H7GAgkaGnJgaLkNPGxLravauoHqoc3rOEkZYuMqV2s/B5cTzqEhNHUzR6n1lzUUVqub0MWN7E0ANWqQpGInkCprhkgt34Z2JREu2pqw8jQuymbAZ5U7KNzRrbQ7XS/M99AwAA==') + format('woff2'); + /* #ifdef MP-ALIPAY */ + src: url('//at.alicdn.com/t/font_2620914_57y9q5zpbel.woff?t=1624238023908') format('woff'), + url('//at.alicdn.com/t/font_2620914_57y9q5zpbel.ttf?t=1624238023908') format('truetype'); + /* #endif */ +} + +[class*='_icon-'] { + font-family: 'colorui' !important; + display: inline-block; +} +@font-face { + font-family: 'ui-num'; + src: url('data:application/x-font-ttf;base64,AAEAAAAKAIAAAwAgT1MvMla+dCkAAACsAAAAYGNtYXAQUxhKAAABDAAAAVJnbHlmS86JUQAAAmAAAAUUaGVhZA7I1xIAAAd0AAAANmhoZWEFqgF3AAAHrAAAACRobXR4BycBzgAAB9AAAAAibG9jYQZmB5wAAAf0AAAAHG1heHAAEQBDAAAIEAAAACBuYW1lGVKlzAAACDAAAAGtcG9zdADDAJYAAAngAAAAPAAEAewBkAAFAAACmQLMAAAAjwKZAswAAAHrADMBCQAAAgAGAwAAAAAAAAAAAAEQAAAAAAAAAAAAAABQZkVkAMAALAA5Ayz/LABcAywA1AAAAAEAAAAAAxgAAAAAACAAAQAAAAMAAAADAAAAHAABAAAAAABMAAMAAQAAABwABAAwAAAACAAIAAIAAAAsAC4AOf//AAAALAAuADD////V/9T/0wABAAAAAAAAAAAAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAgADBAUGBwgJCgsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAiAAABMgKqAAMABwAANxEhESczESMiARDuzMwAAqr9ViICZgAAAAEAUP9hAMcAdwADAAAXNSMRx3c9tP7qAAEAUAAAAM0AfQADAAA3NSMVzX0AfX0AAAIAPv/6AeMC3wASACQAACUDJicmJwYHBgcRFhcWFzY3NjcHFAcGByYnJjURNDc2NxYXFhUB7wwCPDxZWTs7AwM7O1lZPDwOdB0bMzIbHBwbMjMbHdABPmM3NgEBNjdj/r1jNzYBATY3aAI2ICABASAgNgE9Nx8gAQEgHzcAAAAAAQB1AAABbALZAAYAACURIwcVNxEBbGmOjgAC2Xt0ff2ZAAAAAQBBAAAB6ALfAB4AACU1IRM2NzY1JicmJwYHBgczNjc2FxYXFhUUBwYHARUB6P7X5SIREQE5OV9fOjkCaAIfHywzGxwJCRX+6ABdARgoJCIvYDY2AQE3N189GhsBAR4dMxoYFhn+q10AAAAAAQAr//gB6QLgADUAACUmJyYnNjc2NSYnJicGBwYHMzY3NjMyFxYXFAcGByMVMxYXFhUGBwYjIicmJyMWFxY3Mjc2NwH1DRocLysYGAI5O15ZOzwGaQQcHTAuHh8BGxw4ERE+Hh4BISE0LyIhBWgGQD9aXkA/DtI+KioVFCcmOl03NwEBNDNeMRscHRw4Mh0eAVsBHyA4Oh8gGxk7azEyATU1bwABACQAAAH+AtkADgAAJTUjNSMVIwEjARUhFTM1Af5OZbUBAHH+/wEnZW5hqqoCCv32YW5uAAAAAAEAQf/5AewC2QA3AAAlJicmJyYnJiMiBwYHNSE1IREzNjc2NxYXFgcWBwYHBgcGIyInJicjFhcWFxYXFhc2NzY3Njc2NwH2Cg0MKBcgISsoHx8TASv+d18IGhosPRgWAQEHBhcOExMYMRkaBmgCDAwdFygoNDYmJRknDAwK+i4yMioXDAwLCxTBXf5yGxMSAQErKkIlIiIXDwcHGxkxJiQjHhgQDwEBDxEYKDAvQQAAAgA5//oB6ALZABcAKAAAJSYnJiciBwYHEyMDBgcGFRYXFhc2NzY3BwYHBgcmJyYnNjc2MxYXFhcB9A42NlERERAPnW+mGQ4QAjs7YGE6Og5rCh4eMzIdHgEBHh0yNR0eCd1cOTgBAgMGATn+ri8sLCxmOjkBATs8awJAISIBASIhOzshIgEjIzIAAAABAEEAAAHzAtkACAAAATUhFTM1MwMzAfP+TmTe9XECfF3Qc/2EAAAAAwAw//oB8gLfACAAMQBCAAAlJicmJzY3NjcmJyYnBgcGBxYXFhcGBwYHFhcWFzY3NjcnBgcGByYnJic2NzY3FhcWFwMGBwYHJicmJzY3NjcWFxYXAf4NHh4oJRkZAQI7PFxbOzwCARoZJCceHgECQD5gYT9ADmwLIiA1NCEhAQEhITQ1ICILDAoeHTEwHR0BAR0dMDEdHgrTOyoqFxUnJzpcNjYBATY2XDonJxUXKipAZTc3AQE3N2oCOSIiAQEiIjQ0IiMBASMiLwFKPh4eAQEeHjEyHh8BAR8eJQAAAAACADkAAAHoAt8AFwAoAAABJicmJwYHBgcWFxYXMjc2NwMzEzY3NjcHBgcGIyYnJjU2NzY3FhcWFwH0Djo7YWA6OwICNjZRERERDpxvphkODwxrCh4eMzQdHQEeHTIzHh4KAhJaOTkBATs8ZmE5OAEDAgb+xwFSLywsOQNHISIBIyM3OyIhAQEhIi8AAAEAAAABAADHiynwXw889QALBAAAAAAA1sTJ5wAAAADWxMntACL/YQH+AuAAAAAIAAIAAAAAAAAAAQAAAyz/LABcAiIAIgAkAf4AAQAAAAAAAAAAAAAAAAAAAAQBdgAiARcAUAEdAFACIgA+AHUAQQArACQAQQA5AEEAMAA5AAAAAAAUACAALABsAH4AtAEGASIBegHAAdQCRAKKAAEAAAANAEMAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAJYAAQAAAAAAAQAKAAAAAQAAAAAAAgAGAAoAAQAAAAAAAwAbABAAAQAAAAAABAAKACsAAQAAAAAABQAeADUAAQAAAAAABgAKAFMAAwABBAkAAQAUAF0AAwABBAkAAgAMAHEAAwABBAkAAwA2AH0AAwABBAkABAAUALMAAwABBAkABQA8AMcAAwABBAkABgAUAQNmb250ZWRpdG9yTWVkaXVtRm9udEVkaXRvciAxLjAgOiBmb250ZWRpdG9yZm9udGVkaXRvclZlcnNpb24gMS4wOyBGb250RWRpdG9yICh2MS4wKWZvbnRlZGl0b3IAZgBvAG4AdABlAGQAaQB0AG8AcgBNAGUAZABpAHUAbQBGAG8AbgB0AEUAZABpAHQAbwByACAAMQAuADAAIAA6ACAAZgBvAG4AdABlAGQAaQB0AG8AcgBmAG8AbgB0AGUAZABpAHQAbwByAFYAZQByAHMAaQBvAG4AIAAxAC4AMAA7ACAARgBvAG4AdABFAGQAaQB0AG8AcgAgACgAdgAxAC4AMAApAGYAbwBuAHQAZQBkAGkAdABvAHIAAAAAAgAAAAAAAAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAADQANAAAADwARABMAFAAVABYAFwAYABkAGgAbABw=') + format('woff2'); + font-weight: normal; + font-style: normal; +} + +._icon-checkbox:before { + content: '\e713'; +} + +._icon-box:before { + content: '\e714'; +} + +._icon-checkbox-o:before { + content: '\e715'; +} + +._icon-round:before { + content: '\e716'; +} + +._icon-home-o:before { + content: '\e70a'; +} + +._icon-home:before { + content: '\e70d'; +} + +._icon-edit:before { + content: '\e649'; +} + +._icon-close:before { + content: '\e6ed'; +} + +._icon-check-round:before { + content: '\e6f1'; +} + +._icon-check-round-o:before { + content: '\e6f2'; +} + +._icon-close-round:before { + content: '\e6f3'; +} + +._icon-close-round-o:before { + content: '\e6f4'; +} + +._icon-waiting:before { + content: '\e6f8'; +} + +._icon-waiting-o:before { + content: '\e6f9'; +} + +._icon-warn:before { + content: '\e662'; +} + +._icon-warn-o:before { + content: '\e675'; +} + +._icon-more:before { + content: '\e688'; +} + +._icon-delete:before { + content: '\e707'; +} + +._icon-delete-o:before { + content: '\e709'; +} + +._icon-add-round:before { + content: '\e717'; +} + +._icon-add-round-o:before { + content: '\e718'; +} + +._icon-add:before { + content: '\e6e4'; +} + +._icon-info:before { + content: '\e6ef'; +} + +._icon-info-o:before { + content: '\e705'; +} + +._icon-move:before { + content: '\e768'; +} + +._icon-title:before { + content: '\e82f'; +} + +._icon-titles:before { + content: '\e745'; +} + +._icon-loading:before { + content: '\e746'; +} + +._icon-copy-o:before { + content: '\e7bc'; +} + +._icon-copy:before { + content: '\e85c'; +} + +._icon-loader:before { + content: '\e76d'; +} + +._icon-search:before { + content: '\e782'; +} + +._icon-back:before { + content: '\e600'; +} + +._icon-forward:before { + content: '\e601'; +} + +._icon-arrow:before { + content: '\e608'; +} + +._icon-drop-down:before { + content: '\e61c'; +} + +._icon-drop-up:before { + content: '\e61d'; +} + +._icon-check:before { + content: '\e69f'; +} + +._icon-move-round:before { + content: '\e602'; +} + +._icon-move-round-o:before { + content: '\e603'; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/icon/_sheepicon.scss b/yudao-mall-uniapp-master/sheep/scss/icon/_sheepicon.scss new file mode 100644 index 0000000..cf7ea08 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/icon/_sheepicon.scss @@ -0,0 +1,94 @@ +@font-face { + font-family: 'sheepicon'; + src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAA7QAAsAAAAAH7gAAA6AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACFGAquMKcBATYCJANYCy4ABCAFhGcHghMbGBszo8LGASAo3ovsvzzgDulfoYNbbIQFfeT6cUXKcnp8h6BAxr+OT0PaNfv10KZBODSIpU3sSo3EFhur478eSgk9tB9t3u5+1bOm2u/adRPIVAjdKiUTIiF5p0G7H4liOw9t80+OPDw84PjYX/CsAiMBxaj6kzAy38TIGQsWkbpo6xcu2kX11lw1dxwop50cColKPds3ntdm7TMQ5O5+/WLKMIHXtiAAiNIW12xIQlaYu4Gc3QMp9L00hYPmlmYUAIc59ZTtJbdsO9j2NSK25QLAc0DyxvKXihAq8ZKMoATv/f9zrzYZAHkEYdZa9V6Swn15H145H9pmnAJChmzHijgpJuV0xK6bIiH5+Bk9o+tkhfLTTSUJvfZo7JSOMoWx6YxH4gujkBDUd70OAql9x8x4+frt0KaW2NHmkBOFuKBmcLpD7kZznJkSu0PZHhMdAphlPpPwmn5/fbYxAiNokCc6ffJsOicffk0Me+0L7OXaXBW0bUAALNhes1htvv+VDWGbyikru3MPQOwrBkZTwKn1Plz08HMihm2VwHXeg0GnV6k1WqWCEwAi/AfPSqQyOTFQh+TKAVpqwGCvSnMxpv/A6ED/g9GDeqxChQlGDSowGlADRgtqwShBQzAK0AgMBxqDEYAmIMjRFATQDATQHASztAChCi1BAK1AAK1BAG3AEGgL8Zz0w7gU0MZTgOiRpBsy5RLFCuaCL5xPM0NODq8d2THAOMI4ubYfquKsiEWTK4eh6dLW43a8zOpckM+TjbnHdU1JVlrnxSTBlFHdSMq3EylMQYzHhjubO3aq7d5GobB13euVUhgAmWHC58lnTFrRDCqvztCU9YlrJOoRWxI1TTQmWeFHZ+NL4AbKEAGCSnvFWkQNs09QG4oOPwoNpWp3Igca3Ijt0enb5js0+TSgbcvz9Tps1wO/MfvfIdQN/VsKcnWwUYOTaKVfTMxPs3q66vjgClvbbTYEuoS6SS5OV0RrAdWvsMVLfXlLmcs1lWJhTSVP8rDHqbV5o6jTHIuLhmAA1flCHbspEhMFy864PMEQhCNNHWbhxhk258Iu6jgCf6sh0ILiPgCqts3YJqh/EKNO8AGsmKhmQdqr9at9GVEMbJSj53lt1snRPWqDSpyZxmMEVc9HzZ0oopAvsoXrKhGBfk3BDIABwH1B02U+xWzmM0Djl1mO4vw3BOHrXBr9hNHDMUQKzjQEqXwuDxZcWHRh2VGXJKqPeJO3/AZkVx9v27Q7tlvHnW6av6EgDxCdwsmuOGqBQEBJBve5cgEh+yxKeSj/iGUn9BMLq5EdXKYuW/OBjXp3vKOnKnHtPV8vhm+bYvfmscPd+A5r7efmxFbv1k97dX6Fwuo5nKA8Wg1unahNCDpxH5f4F1e1Avm+J3bkirM/B1AhHkJb4kpDSglrbCUS6Cqxa1VFyupCJ0dNYejan0vb1A8Ka/myLMlEUoiihO6nZuJk5AaJtJSPvodqG/gaybU0QfZtKrRS3O/bidlgV8Z3pKbI4cCo4yVvkkw7RTJ2UNK77Q9PQhPqxex+dB+QEx7whgM5Y3QV/RGOSYliqX7GSzpdq7OoBVTx2PrTMd1+Wd0fdauWJKmBIx995D0bDjNEGwnjvgBQpdML/A1fy1wmurOjsCdwpCei9v3dXPCw/mp6J3bRRPB9J/BPW50dhLadQYN6abeMHYYgl9xP6njrAKPFNiKR9DGX6VaI2bLFUmKKtfsOj5cmUYXWlagKhkFbOArjBptIBaP1RcxULU6yoVsDKN8lLIfQaRX9PIOvgxNsqg9RSccoe+H7LT3aJsOJLTGSgm4BWABvm1gL3igAG/BBHSyADIgUsk69ltYJBhd7rAa1Xrwt0eiCWKPL3U1zN6i0FvTdrbJ3m2qtoG5oQPdWD0c3QfV5WptcB/F2Srp2aHFbOoYcoXuPuXi3f1HUvfenYkQnUUiOVRNj8+RnXgePrgPANUIc4A4Hg0uvD2/GvuCAuhBH/xE3OqRefM8W68GISmsunTYDetfdZgWGjiCjXjBE6u5JiRBELt7MmrRUTYfm/KSFVmKVIk6ozxbI3d3lguxvgpzOJvfIEXzNGfMeXrXvhea5ZO7ZAtKZsKwE+3geP84hcdE+gR8fx090UCXaS3AUtUX7yDCWl2Avygo7dSpsetpwKhhWgO7PndKvF+9a5hyra1mZohfrXOYk1dWpaGZGnujv/usNLOx3nLOW3wpbC+hGcUd8RsgPEFesSP9ftz/f67st6ZdqBeh7ryItSaFS6Cb0HieoRRQZ6X7g4ZrLDbm5kYGmUXz1yOrUwo91/49qMisALeESc954nrnE2ma67UPDEjplso2V3Z9xJ2EJKLAxM80k0Vih2JxokvYv7944UaFIN04z+ZdhTGyZeixzl7i4SNxl74D64hIXmfu7nF1O4RidtL90C50cGO/ruzVOLjt0yMdfaVD8GJ0QyZFETU42avH0mk6RmTg5FEaePkXaPs5Lc2XdYvXOX6wGfcly7aZvvea2Zfl8ALePB1OVvjRmCPsN7421NaQzdRVUqBeiuhZke1mEdqkhOK4a2Av6KuvYS7wlmyXbd7E9AvQ2y4PbKRHXQ1QuBNHyn9wjcXRSdWBQ2su62Z+SBkECP+MgnuVUW7G4CkBV/HGsTxsbw7T7sLAdtqY2R2tci6M9RrO5Scexfq3SJK1+zFbZWlrcSZX5Ootarw3phjEYpl4sBq3Rt5C2El8Tt5JiiDAlui2OYWsgjI9RlLUwJSXMBq1h79WmD1G5+LRBd2cW0hn/oOO27jPw+NbNTciKF1vT7EpMw4zCLIvfjcTJQhFlclguEcGTGhmXzyCTr5Gx88Wh5zzKNeWacUwR6YAjie5N96eLueLlUHkDwv/qo3RCy3Yc+P/q96nzy6qNdz3K0CpE/MWoJ9qW8FtOppYZh+qGRkEEsFaUJZRnuuV4fBdqr0B+DwCsdeIIvTy3+x4Fdlxpab2yfYqI74MYyszySDnEFIc0x+pDcB6cw5EaZg4RxR3Og51H5XKnjiFk4/v5pmmm+MXTNRUKZzo7hR1Zh4w0VomyPQTZwrxGCL9To3HQ4zzLI0+Ue/ZXlV0rUM1LSeVVtfFqUpKreO3dyGQhGFWBU17W1XEpRbxao0Zq3urstlfJe9IaP3lyunrifTS+J9nU3ywwTmhRCFEEDd1oUjw62X6hVsDulmbA0G5Y0KBApcvYinqv9GoqzgC6UcCx+amf39Hg2akQRc+to3PO4usH+Psd+c07FtKDwmjF8CnlyKmiYo+hdXzfXRAconJWOY2PH1G5qIKD7dAEdoJAQn1qbqGHQkY1wUkVUmWprrMwudrU3KL4PJdSKg9JqjEil1N1Bwss9azyLdfpQsCJhxFIjEGhNJXAwhj1vREaEhiJSY4gUsQ9+u7vaydqL68WPnayDAkgsQauI2EscPrq8qXbxvPGLz9+mrec//r1VryXb52+RvxoXzMfExMfM9/NRu31Mbn1N/eLRvFei4T5+cJGIWVpEublCZuB0KANZSh+F4N77vuD5uhXxFHlmOkI4g1RtX+lLC3kNctDQ53ms8ZkjVSDSAC2F4aFHQnhz2jqm/3w1POwQwlk2sIWGs1Hd+Szv4htPWdQfmNzbeqq1uuBN3jYd59PrYsnu8bf/7NNTu6xHmf0zuoYHQoyVlQyOebh645NtqY2EyzyWEOzNs6cxffvfbvUllafm7131z1FrOQR3BJwD0lG9yf4012g8whSrhMIYRGMFtwNUizHmeDkY9mCjkQ3sxhOCUgixQBcZ5x0ZOtGa2AMP4L/UUfMcr8hu7PCpqPT3sau7BhfJduTHQkKixuENuQH2AQ8/rSSNMHW5dNA2Etm+jtogjx7niSDaTEl4F1ChpcMQpU4sZo0Zp0xVEohtKnErSuyKX9MFCF/ZSwwyF7xdIlYYrfMhkLsb46YYSP20Q2XnLyf2bZXBANC3sIUtA3afiuP5U6eIRoQchemIVsSXc4wezTH27ZxKyMTIdlC0wu5jqwZl+e2Pt4+9jAOmYFR9fUwQ2NGlzBdsoe7p7CEGzbIA5wY52ku+oydLzL3dEyD8UDWCRiILoYB19KhGT//u3DlvUeGtja3054Y3FMdtrhmfeHK5/9TziIy6igWMVcaTL67hukZXi94bHBt70iZWSFcnMOUAFzEfqijsXKWwLanNivfnRXVzu4dLjcth33mYMoM7ANjFYuOPlD6gAUHHoOBqFspk1um/AZdWE3dXt1Cr2qh1nxQarSzqNPCzj/agiljFi/nKw5WzkwfyNjpbUW69vVJjKn4E8YoUOWOBwB/AjwFJtCVwFaBLsp23BqW+T5wP2j/+7PvBn91U9LQbLsbbACIaoK4LUh/BSpA+Hd0W3B/5LsqTcP9I5n613r7t723oWOKzeQthy34HSxJi7+a0x47/I9/yTqIf8yEVd/5UfI/5KRmczL6To5oBqR+Eng7qfV1XVydtPSz2tXFi43IAljW2EVwGLu5OJA5hBBjjxantpz0nuk8A6RMgFXPsVhqbxYbpbdgMfYdOIz9sjgwmiDE2H+LU9cqBpZZjWsLToxa0KjioQJQtHYLvdJvdJdac9HOf+QUsF3t81024xUjsg6bdHUHEassU6NevCfDuibVMpUIknuR9rjdWpZNDtR0ToxalssbpXhsHICi1Zf0z/eN7lJrluT/FU6OYF+5spfbSfCvcpSqcU2Kp6s7EFuxag5spzfKS1fBepRKSsvWSoSRP+craO3R1tezsnLevKu5CGROu1pJ92PYZOUUKFSkWMkvum87V6FSlWrFK0GJ4iVIlJ0BmiDDQqcAA08NDhpinIFHqLI6RJwK65haYpk5IpMy0GzGQHWNIIub5hiik1JGCdTofuU6SLZahySDQkM1vUSNiWjWCj66SL/i5nzBJIFiRptDYNAtiIbHL1dTwonBOlyRHyNig5xGZwYy2OkAAAAA') + format('woff2'); +} + +[class*='sicon-'] { + font-family: 'sheepicon'; + display: inline-block; +} + +.sicon-edit:before { + content: '\e711'; +} + +.sicon-basic:before { + content: '\e712'; +} + +.sicon-home:before { + content: '\e70c'; +} + +.sicon-more:before { + content: '\e707'; +} + +.sicon-check-line:before { + content: '\e708'; +} + +.sicon-transport:before { + content: '\e709'; +} + +.sicon-goods-card:before { + content: '\e70a'; +} + +.sicon-collect:before { + content: '\e70b'; +} + +.sicon-warning-line:before { + content: '\e70d'; +} + +.sicon-score1:before { + content: '\e70e'; +} + +.sicon-score2:before { + content: '\e70f'; +} + +.sicon-goods-list:before { + content: '\e710'; +} + +.sicon-back:before { + content: '\e706'; +} + +.sicon-unchecked:before { + content: '\e703'; +} + +.sicon-warning-outline:before { + content: '\e6ff'; +} + +.sicon-question-outline:before { + content: '\e700'; +} + +.sicon-circlecheck:before { + content: '\e701'; +} + +.sicon-circleclose:before { + content: '\e702'; +} + +.sicon-delivery:before { + content: '\e6fd'; +} + +.sicon-orders:before { + content: '\e6fe'; +} + +.sicon-qrcode:before { + content: '\e6f9'; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/icon/_style.scss b/yudao-mall-uniapp-master/sheep/scss/icon/_style.scss new file mode 100644 index 0000000..a2c4dc8 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/icon/_style.scss @@ -0,0 +1,43 @@ +@import './icon'; //核心图标库 +@import './coloricon'; //扩展图标库 +@import './sheepicon'; +.icon-spin { + animation: icon-spin 2s infinite linear; +} + +.icon-pulse { + animation: icon-spin 1s infinite steps(8); +} + +@keyframes icon-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +.icon-90 { + transform: rotate(90deg); +} +.icon-180 { + transform: rotate(180deg); +} +.icon-270 { + transform: rotate(270deg); +} +.icon-x { + transform: scale(-1, 1); +} +.icon-y { + transform: scale(1, -1); +} +.icon-fw { + width: calc(18em / 14); + text-align: center; +} +@each $class, $value in $iconsize { + .icon-#{$class} { + transform: scale(#{$value}); + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/index.scss b/yudao-mall-uniapp-master/sheep/scss/index.scss new file mode 100644 index 0000000..c841956 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/index.scss @@ -0,0 +1,27 @@ +@import './tools'; +@import './ui'; + +/* 字体文件 */ +@font-face { + font-family: OPPOSANS; + src: url('~@/sheep/scss/font/OPPOSANS-M-subfont.ttf'); +} +.font-OPPOSANS { + font-family: OPPOSANS; +} +page { + -webkit-overflow-scrolling: touch; // 解决ios滑动不流畅 + height: 100%; + width: 100%; + // font-family: OPPOSANS; + word-break: break-all; //英文文本不换行 + white-space: normal; + background-color: $bg-page; + color: $dark-3; +} +::-webkit-scrollbar { + width: 0; + height: 0; + color: transparent; + display: none; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_avatar.scss b/yudao-mall-uniapp-master/sheep/scss/style/_avatar.scss new file mode 100644 index 0000000..e69de29 diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_background.scss b/yudao-mall-uniapp-master/sheep/scss/style/_background.scss new file mode 100644 index 0000000..775f37f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_background.scss @@ -0,0 +1,204 @@ +/* ================== + 背景 + ==================== */ +/* -- 基础色 -- */ +@each $color, $value in map-merge($colors, $darks) { + .bg-#{$color} { + background-color: $value !important; + @if $color == 'yellow' { + color: #333333 !important; + } @else { + color: #ffffff !important; + } + } +} + +/* -- 浅色 -- */ +@each $color, $value in $colors { + .bg-#{$color}-light { + background-image: linear-gradient(45deg, white, mix(white, $value, 85%)) !important; + color: $value !important; + } + + .bg-#{$color}-thin { + background-color: rgba($value, var(--ui-BG-opacity)) !important; + color: $value !important; + } +} + +/* -- 渐变色 -- */ + +@each $color, $value in $colors { + @each $colorsub, $valuesub in $colors { + @if $color != $colorsub { + .bg-#{$color}-#{$colorsub} { + // background-color: $value !important; + background-image: linear-gradient(130deg, $value, $valuesub) !important; + color: #ffffff !important; + } + } + } +} +.bg-yellow-gradient { + background-image: linear-gradient(45deg, #f5fe00, #ff6600) !important; + color: $dark-3 !important; +} +.bg-orange-gradient { + background-image: linear-gradient(90deg, #ff6000, #fe832a) !important; + color: $white !important; +} +.bg-red-gradient { + background-image: linear-gradient(45deg, #f33a41, #ed0586) !important; + color: $white !important; +} +.bg-pink-gradient { + background-image: linear-gradient(45deg, #fea894, #ff1047) !important; + color: $white !important; +} +.bg-mauve-gradient { + background-image: linear-gradient(45deg, #c01f95, #7115cc) !important; + color: $white !important; +} +.bg-purple-gradient { + background-image: linear-gradient(45deg, #9829ea, #5908fb) !important; + color: $white !important; +} +.bg-blue-gradient { + background-image: linear-gradient(45deg, #00b8f9, #0166eb) !important; + color: $white !important; +} +.bg-cyan-gradient { + background-image: linear-gradient(45deg, #06edfe, #48b2fe) !important; + color: $white !important; +} +.bg-green-gradient { + background-image: linear-gradient(45deg, #3ab54a, #8cc63f) !important; + color: $white !important; +} +.bg-olive-gradient { + background-image: linear-gradient(45deg, #90e630, #39d266) !important; + color: $white !important; +} +.bg-grey-gradient { + background-image: linear-gradient(45deg, #9aadb9, #354855) !important; + color: $white !important; +} +.bg-brown-gradient { + background-image: linear-gradient(45deg, #ca6f2e, #cb1413) !important; + color: $white !important; +} + +@each $color, $value in $grays { + .bg-#{$color} { + background-color: $value !important; + color: #333333 !important; + } +} + +.bg-square { + @include bg-square; +} +.bg-none { + background: transparent !important; + color: inherit !important; +} + +[class*='bg-mask'] { + position: relative; + //background: transparent !important; + color: #ffffff !important; + > view, + > text { + position: relative; + z-index: 1; + color: #ffffff; + } + &::before { + content: ''; + border-radius: inherit; + width: 100%; + height: 100%; + @include position-center; + background-color: rgba(0, 0, 0, 0.4); + z-index: 0; + } + @at-root .bg-mask-80::before { + background: rgba(0, 0, 0, 0.8) !important; + } + @at-root .bg-mask-50::before { + background: rgba(0, 0, 0, 0.5) !important; + } + @at-root .bg-mask-20::before { + background: rgba(0, 0, 0, 0.2) !important; + } + @at-root .bg-mask-top::before { + background-color: rgba(0, 0, 0, 0); + background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.618), rgba(0, 0, 0, 0.01)); + } + @at-root .bg-white-top { + background-color: rgba(0, 0, 0, 0); + background-image: linear-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.3)); + } + @at-root .bg-mask-bottom::before { + background-color: rgba(0, 0, 0, 0); + background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.618), rgba(0, 0, 0, 1)); + } +} +.bg-img { + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +[class*='bg-blur'] { + position: relative; + > view, + > text { + position: relative; + z-index: 1; + } + &::before { + content: ''; + width: 100%; + height: 100%; + @include position-center; + border-radius: inherit; + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + } +} +@supports (-webkit-backdrop-filter: blur(20px)) or (backdrop-filter: blur(20px)) { + .bg-blur::before { + @include blur; + background-color: var(--ui-Blur-1); + } + .bg-blur-1::before { + @include blur; + background-color: var(--ui-Blur-2); + } + .bg-blur-2::before { + @include blur; + background-color: var(--ui-Blur-3); + } +} +@supports not (backdrop-filter: blur(5px)) { + .bg-blur { + color: var(--ui-TC); + &::before { + background-color: var(--ui-BG); + } + } + .bg-blur-1 { + color: var(--ui-TC); + &::before { + background-color: var(--ui-BG-1); + } + } + .bg-blur-2 { + color: var(--ui-TC); + &::before { + background-color: var(--ui-BG-2); + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_border.scss b/yudao-mall-uniapp-master/sheep/scss/style/_border.scss new file mode 100644 index 0000000..4ef1d54 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_border.scss @@ -0,0 +1,140 @@ +/* ================== + 边框 + ==================== */ +/* -- 实线 -- */ +.border { + overflow: initial !important; + @at-root [class*='border'], + [class*='dashed'] { + position: relative; + &.dline { + --ui-Border: var(--ui-BG-3); + } + &::after { + content: ' '; + width: 200%; + height: 200%; + position: absolute; + z-index: 0; + top: 0; + left: 0; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + border-radius: inherit; + } + &.radius::after { + border-radius: calc(#{$radius} * 2); + } + &.round::after { + border-radius: #{$round-pill}; + } + } + &::after { + border: 1px solid var(--ui-Border); + } + &s::after { + border: 4rpx solid var(--ui-Border); + } + &ss::after { + border: 8rpx solid var(--ui-Border); + } + @each $value in (top, right, bottom, left) { + &-#{$value}::after { + border-#{$value}: 1px solid var(--ui-Border); + } + &s-#{$value}::after { + border-#{$value}: 4rpx solid var(--ui-Border); + } + &ss-#{$value}::after { + border-#{$value}: 8rpx solid var(--ui-Border); + } + } +} +/* -- 虚线 -- */ +.dashed { + &::after { + border: 4rpx dashed var(--ui-Border); + } + &s::after { + border: 6rpx dashed var(--ui-Border); + } + @each $value in (top, right, bottom, left) { + &-#{$value}::after { + border-#{$value}: 4rpx dashed var(--ui-Border); + } + &s-#{$value}::after { + border-#{$value}: 6rpx dashed var(--ui-Border); + } + } +} +@each $color, $value in map-merge($colors, map-merge($darks, $grays)) { + .border-#{$color}::after, + .border-#{$color}[class*='-shine']::before { + border-color: $value !important; + } +} +@each $value in (a, b, c, d, e) { + .main-#{$value}-border::after, + .main-#{$value}-border[class*='-shine']::before { + border-color: var(--main-#{$value}) !important; + } +} +.dashed-shine, +.dasheds-shine { + position: relative; + overflow: hidden; + &::after, + &::before { + border-style: dashed; + border-color: var(--ui-Border); + animation: shineafter 1s infinite linear; + width: calc(200% + 40px); + height: 200%; + border-width: 2px 0; + } + &::before { + content: ' '; + position: absolute; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + animation: shinebefore 1s infinite linear; + width: 200%; + height: calc(200% + 40px); + border-width: 0 2px; + } +} +.dasheds-shine { + &::after, + &::before { + border-width: 4px 0; + } + &::before { + border-width: 0 4px; + } +} + +@keyframes shineafter { + 0% { + top: 0; + left: -22px; + } + 100% { + top: 0px; + left: 0px; + } +} + +@keyframes shinebefore { + 0% { + top: -22px; + left: 0; + } + 100% { + top: 0px; + left: 0px; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_button.scss b/yudao-mall-uniapp-master/sheep/scss/style/_button.scss new file mode 100644 index 0000000..7069345 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_button.scss @@ -0,0 +1,87 @@ +.ui-btn-box { + display: inline-block; +} +.ui-btn { + position: relative; + border: 0rpx; + display: inline-block; + align-items: center; + justify-content: center; + box-sizing: border-box; + padding: 0.7857em 1.5em 0.7857em; + font-size: 28rpx; + line-height: 1em; + text-align: center; + text-decoration: none; + overflow: visible; + margin: 0 0.25em 0 0; + transform: translate(0rpx, 0rpx); + border-radius: $radius; + white-space: nowrap; + color: var(--text-a); + background-color: var(--ui-BG); + vertical-align: baseline; + &:first-child:last-child { + margin: 0; + } + &:not([class*='round'])::after { + border-radius: calc(#{$radius} * 2); + } + &:not([class*='border'])::after { + // content: ' '; + // width: 200%; + // height: 200%; + // display: block; + // position: absolute; + // z-index: 0; + // top: 0; + // left: 0; + // transform: scale(0.5); + // transform-origin: 0 0; + // pointer-events: none; + // box-sizing: border-box; + display: none; + } + &.round::after { + border-radius: #{$round-pill}; + } + &.icon { + padding: 0.8em 0.8em; + } + + &.sm { + font-size: 24rpx; + } + + &.lg { + font-size: 32rpx; + } + + &.xl { + font-size: 36rpx; + } + + &.block { + width: 100%; + display: block; + font-size: 32rpx; + } + + &[disabled] { + opacity: 0.6; + } + + &.none-style { + background-color: transparent !important; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + display: flex; + } +} + +.ui-btn:not(.icon) [class*='icon-'] { + margin: 0 0.25em; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_card.scss b/yudao-mall-uniapp-master/sheep/scss/style/_card.scss new file mode 100644 index 0000000..17aa6b3 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_card.scss @@ -0,0 +1,353 @@ +/* ================== + 卡片 + ==================== */ + +.ui-cards { + display: block; + overflow: hidden; + & .ui-btn.badge { + top: 0; + right: 0; + font-size: 24rpx; + padding: 0rpx 15rpx; + height: 40rpx; + } + &.no-card > .ui-item { + margin: 0rpx; + border-radius: 0rpx; + } + & > .ui-item { + display: block; + overflow: hidden; + border-radius: 10rpx; + margin: 30rpx; + } + & > .ui-item.shadow-blur { + overflow: initial; + } + .grid.grid-square { + margin-bottom: -20rpx; + } + &.article { + display: block; + & > .ui-item { + padding: 30rpx; + background-color: var(--box-bg); + display: flex; + align-items: flex-start; + } + & > .time { + padding: 30rpx 0 0 30rpx; + } + & > .ui-item .title { + font-size: 30rpx; + font-weight: 900; + color: #333333; + } + & > .ui-item .content { + flex: 1; + } + & > .ui-item > image { + width: 240rpx; + height: 6.4em; + margin-left: 20rpx; + border-radius: 6rpx; + } + & > .ui-item .content .desc { + font-size: 12px; + color: var(--text-c); + } + & > .ui-item .content .text-content { + font-size: 28rpx; + color: #888; + } + } + &.case { + .image { + position: relative; + image { + width: 100%; + display: block; + } + .ui-tag { + position: absolute; + right: 0; + top: 0; + } + .ui-bar { + position: absolute; + bottom: 0; + width: 100%; + background-color: transparent; + padding: 0rpx 30rpx; + } + .bg-black { + position: absolute; + bottom: 0; + width: 100%; + background-color: rgba(0, 0, 0, 0.6); + } + } + &.no-card .image { + margin: 30rpx 30rpx 0; + overflow: hidden; + border-radius: 10rpx; + } + } + &.dynamic { + display: block; + & > .ui-item { + display: block; + overflow: hidden; + & > .text-content { + padding: 0 30rpx 0; + font-size: 30rpx; + margin-bottom: 20rpx; + } + & .square-img { + width: 100%; + height: 200rpx; + border-radius: 6rpx; + } + & .only-img { + width: 100%; + height: 320rpx; + border-radius: 6rpx; + } + } + } + &.goods { + display: block; + & > .ui-item { + padding: 30rpx; + display: flex; + position: relative; + background-color: var(--ui-BG); + & + .ui-item { + border-top: 1rpx solid #eeeeee; + } + .content { + width: 410rpx; + padding: 0rpx; + } + .title { + font-size: 30rpx; + font-weight: 900; + color: #333333; + line-height: 1.4; + height: 1.4em; + overflow: hidden; + } + } + &.col-goods.col-twice { + display: flex; + flex-wrap: wrap; + padding-bottom: 30rpx; + & > .ui-item { + width: calc(50% - 30rpx); + margin: 20rpx 20rpx 0rpx 20rpx; + .content { + padding: 20rpx; + } + } + & > .ui-item:nth-child(2n) { + margin-left: 0rpx; + } + } + &.col-goods > .ui-item { + padding: 0rpx; + display: block; + border: 0px; + .content { + width: 100%; + padding: 30rpx; + } + } + &.no-card > .ui-item .content { + width: 470rpx; + padding: 0rpx; + } + &.no-card > .ui-item .title, + &.col-goods > .ui-item .title { + height: 3em; + overflow: hidden; + } + & > .ui-item .text-linecut-2 { + -webkit-line-clamp: 1; + } + &.no-card > .ui-item .text-linecut-2, + &.col-goods > .ui-item .text-linecut-2 { + -webkit-line-clamp: 2; + line-height: 1.6em; + height: 3.2em; + } + & > .ui-item > image { + width: 200rpx; + height: 200rpx; + margin-right: 20rpx; + border-radius: 6rpx; + } + &.no-card > .ui-item > image { + width: 220rpx; + height: 170rpx; + } + &.col-goods > .ui-item > image { + width: 100%; + height: 340rpx; + border-bottom-left-radius: 0rpx; + border-bottom-right-radius: 0rpx; + display: block; + } + &.col-goods.col-twice > .ui-item > image { + height: 236rpx; + } + } + &.loan { + display: block; + & > .ui-item { + padding: 30rpx 0 30rpx 30rpx; + display: flex; + position: relative; + background-color: var(--box-bg); + + .content { + width: 450rpx; + padding: 0rpx; + .tag-list { + width: 450rpx; + display: flex; + flex-wrap: wrap; + font-size: 12px; + margin-top: 18rpx; + } + } + .action { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + } + } + } + &.houses { + display: block; + & > .ui-item { + padding: 20rpx; + display: flex; + position: relative; + background-color: var(--box-bg); + .image { + width: 230rpx; + height: 180rpx; + margin-right: 20rpx; + border-radius: 6rpx; + } + .content { + width: 400rpx; + padding: 0rpx; + .tag-list { + width: 400rpx; + display: flex; + flex-wrap: wrap; + font-size: 12px; + margin-top: 10rpx; + .ui-item { + height: 20px; + line-height: 20px; + } + } + } + .action { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + } + } + } + + &.product { + display: flex; + flex-wrap: wrap; + padding-bottom: 30rpx; + & > .ui-item { + width: calc(100% - 15rpx); + margin: 20rpx 20rpx 0rpx 20rpx; + background-color: var(--box-bg); + position: relative; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + // display: flex; + // flex-wrap: wrap; + .content { + padding: 20rpx; + // width: calc(100% - 345rpx); + .text-cut { + font-size: 16px; + } + } + .image { + width: 100%; + height: 240rpx; + border-radius: 6rpx 0 0 6rpx; + display: block; + } + .ui-progress-tag { + width: 4em; + text-align: right; + font-size: 12px; + } + .border-top { + width: 100%; + } + .ui-tag { + position: absolute; + top: 0; + left: 0; + border-radius: 6rpx 0 6rpx 0; + } + } + // & > .ui-item:nth-child(2n) { + // margin-left: 0rpx; + // } + } + &.shop { + display: flex; + flex-wrap: wrap; + padding-bottom: 30rpx; + & > .ui-item { + width: calc(50% - 30rpx); + margin: 20rpx 20rpx 0rpx 20rpx; + background-color: var(--box-bg); + padding: 20rpx; + .content { + margin-top: 15rpx; + } + .image { + width: 100%; + height: 285rpx; + border-radius: 6rpx; + display: block; + } + } + & > .ui-item:nth-child(2n) { + margin-left: 0rpx; + } + } + + &.orders .ui-item { + margin-top: 30rpx; + .address-box { + padding: 15rpx; + margin: 0 30rpx 30rpx; + border: 1px solid; + border-color: var(--main-a); + border-radius: 10px; + position: relative; + .ui-form-group { + min-height: 10px; + } + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_code.scss b/yudao-mall-uniapp-master/sheep/scss/style/_code.scss new file mode 100644 index 0000000..5221c88 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_code.scss @@ -0,0 +1,55 @@ +.ui-code { + font-family: Monaco, Menlo, Consolas, 'Courier New'; + font-size: 90%; + position: relative; + z-index: 1; + color: var(--ui-TC); + .ui-rich-text { + display: inline-block; + } + + &.code { + display: inline-block; + padding: 0 10rpx; + margin: 0 10rpx; + border-radius: $radius-sm; + line-height: 1.6; + vertical-align: baseline; + } + + &.pre { + display: block; + margin: 1em 0; + line-height: 1.6; + &.hasTitle { + margin: 3.2em 0 1em; + } + // border-radius: $radius-sm; + .ui-code-title { + position: absolute; + top: -2.2em; + color: var(--ui-TC-2); + left: 0; + } + .ui-rich-text { + padding: 40rpx; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + } + .ui-scroll-view { + &.ui-scroll { + max-height: 500px; + white-space: pre; + } + } + .ui-copy-btn { + position: absolute; + z-index: 2; + top: 0; + right: 0; + padding: 0.8em; + border-radius: 0 $radius-sm 0 $radius-sm; + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_flex.scss b/yudao-mall-uniapp-master/sheep/scss/style/_flex.scss new file mode 100644 index 0000000..1daa45b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_flex.scss @@ -0,0 +1,79 @@ +/* ================== + 弹性布局 + ==================== */ +.flex { + display: flex !important; + &-sub { + flex: 1 !important; + } + &-twice { + flex: 2 !important; + } + &-treble { + flex: 3 !important; + } + &-column { + flex-direction: column !important; + } + &-row { + flex-direction: row !important; + } + &-column-reverse { + flex-direction: column-reverse !important; + } + &-row-reverse { + flex-direction: row-reverse !important; + } + &-wrap { + flex-wrap: wrap !important; + } + &-center { + @include flex-center; + } + &-bar { + @include flex-bar; + } +} +.basis { + @each $class, $value in (xs: 20%, sm: 40%, df: 50%, lg: 60%, xl: 80%) { + &-#{$class} { + flex-basis: $value !important; + } + } +} +.align { + @each $class, + $value + in (start: flex-start, end: flex-end, center: center, stretch: stretch, baseline: baseline) + { + &-#{$class} { + align-items: $value !important; + } + } +} +.self { + @each $class, + $value + in (start: flex-start, end: flex-end, center: center, stretch: stretch, baseline: baseline) + { + &-#{$class} { + align-self: $value !important; + } + } +} +.justify { + @each $class, + $value + in ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around + ) + { + &-#{$class} { + justify-content: $value !important; + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_form.scss b/yudao-mall-uniapp-master/sheep/scss/style/_form.scss new file mode 100644 index 0000000..91d3eb3 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_form.scss @@ -0,0 +1,121 @@ +/* ================== + 表单 + ==================== */ +.ui-form-item { + padding: 1rpx 24rpx; + display: flex; + align-items: center; + min-height: 100rpx; + justify-content: space-between; + .title { + text-align: justify; + padding-right: 30rpx; + font-size: 30rpx; + position: relative; + height: 60rpx; + line-height: 60rpx; + } + .content { + flex: 1; + } + input, + ui-input { + flex: 1; + font-size: 30rpx; + color: #555; + padding-right: 20rpx; + } + text[class*='icon-'] { + font-size: 36rpx; + padding: 0; + box-sizing: border-box; + } + textarea { + margin: 32rpx 0 30rpx; + height: 4.6em; + width: 100%; + line-height: 1.2em; + flex: 1; + font-size: 28rpx; + padding: 0; + } + picker, + .arrow { + flex: 1; + padding-right: 40rpx; + overflow: hidden; + position: relative; + } + picker .picker, + .arrow > view { + line-height: 100rpx; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + width: 100%; + } + picker::after, + .arrow::after { + font-family: 'ui'; + display: block; + content: '\e605'; + position: absolute; + font-size: 34rpx; + color: #8799a3; + line-height: 100rpx; + width: 60rpx; + text-align: center; + top: 0; + bottom: 0; + right: -20rpx; + margin: auto; + } + textarea[disabled], + textarea[disabled] .placeholder { + color: transparent; + } + &.align-start .title { + height: 1em; + margin-top: 32rpx; + line-height: 1em; + } + .grid-square { + > view { + background-color: #f8f8f8; + border-radius: 12rpx; + .mask { + background-color: rgba(0, 0, 0, 0.6); + position: absolute; + font-size: 20rpx; + color: #ffffff; + width: 100%; + bottom: 0; + text-align: center; + padding: 6rpx 0; + &.red-mask { + background-color: rgba(255, 80, 80, 0.6); + } + } + [class*='icon'] { + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + transform: scale(1.5); + justify-content: center; + } + .text-gray { + position: absolute; + width: 100%; + font-size: 24rpx; + text-align: center; + bottom: 20rpx; + } + } + } +} +.disabled { + opacity: 0.6; + cursor: not-allowed !important; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_grid.scss b/yudao-mall-uniapp-master/sheep/scss/style/_grid.scss new file mode 100644 index 0000000..b1b5230 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_grid.scss @@ -0,0 +1,103 @@ +/* ================== + 栅栏 + ==================== */ +@use 'sass:math'; + +@mixin make_col($screen) { + @for $i from 1 through 12 { + .ui-col-#{$screen}-#{$i} { + width: calc(100% / 12 * #{$i}); + } + .ui-cols-#{$screen}-#{$i} .ui-item { + width: calc(100% / #{$i}); + } + } +} +.ui-container { + box-sizing: border-box; + margin-left: auto; + margin-right: auto; + padding-left: 30rpx; + padding-right: 30rpx; + width: 100%; + max-width: 1440px; + &-fluid { + max-width: 100%; + padding-left: 0; + padding-right: 0; + } +} +.ui-grid { + display: flex; + flex-wrap: wrap; + &.multi-column { + display: block; + column-count: 2; + column-width: 0px; + column-gap: 0px; + > .ui-item { + break-inside: avoid; + padding: 0.001em; + } + } + &.grid-square { + overflow: hidden; + > .ui-item { + margin-right: 20rpx; + margin-bottom: 20rpx; + position: relative; + overflow: hidden; + } + @for $i from 1 through 12 { + &.ui-cols-#{$i} > .ui-item { + padding-bottom: calc((100% - #{20rpx * ($i - 1)}) / #{$i}); + height: 0; + width: calc((100% - #{20rpx * ($i - 1)}) / #{$i}); + } + } + @for $i from 1 through 12 { + &.ui-cols-#{$i} > .ui-item:nth-child(#{$i}n) { + margin-right: 0; + } + } + } +} +@for $i from 1 through 12 { + .ui-cols-#{$i} .ui-item { + width: calc(100% / #{$i}); + } +} +@for $i from 1 through 12 { + .ui-col-#{$i} { + width: calc(100% / 12 * #{$i}); + } +} +// 小屏 +@media screen and (min-width: 0px) { + @include make_col('xs'); +} + +// 小屏 +@media screen and (min-width: 320px) { + @include make_col('sm'); +} + +// 中屏 +@media screen and (min-width: 768px) { + @include make_col('md'); +} + +// 普通屏 +@media screen and (min-width: 1025px) { + @include make_col('lg'); +} + +// 大屏 +@media screen and (min-width: 1440px) { + @include make_col('xl'); +} + +// 超大屏 +@media screen and (min-width: 1920px) { + @include make_col('xxl'); +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_markdown.scss b/yudao-mall-uniapp-master/sheep/scss/style/_markdown.scss new file mode 100644 index 0000000..37b023d --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_markdown.scss @@ -0,0 +1,62 @@ +.cu-markdown { + position: relative; + z-index: 1; + &.selectable { + cursor: auto; + user-select: text; + } + inline { + display: inline-block; + } + + .list { + .list-item { + line-height: 1.8; + .list { + margin-left: 1.28571em; + .ui-title { + transform: scale(0.6); + &:before { + content: '\e716'; + } + } + } + } + .list-item-p { + position: relative; + padding-left: 1.5em; + .list-item-t { + display: block; + width: 1.3em; + text-align: center; + position: absolute; + left: 0; + } + } + } + .md-table + .md-table { + margin-top: 30rpx; + } +} + +.paragraph { + margin: 0 0 40rpx; + line-height: 1.8; +} + +.blockquote { + @extend .paragraph; + padding: 20rpx 30rpx; + border-left-style: solid; + border-left-width: 10rpx; + border-color: var(--ui-Border); + background: none repeat scroll 0 0 rgba(102, 128, 153, 0.05); + + .paragraph { + margin-bottom: 30rpx; + } + + .paragraph:last-child { + margin-bottom: 0; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_menu.scss b/yudao-mall-uniapp-master/sheep/scss/style/_menu.scss new file mode 100644 index 0000000..a4a8282 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_menu.scss @@ -0,0 +1,54 @@ +.ui-menu { + background-color: var(--ui-BG); +} + +.ui-menu-item { + position: relative; + @include flex-bar; + min-height: 4em; + padding: 0 30rpx; + .ui-menu-item-icon { + width: 1.7em; + margin-right: 0.3em; + position: relative; + display: flex; + align-items: center; + justify-content: center; + transform: scale(1.3); + } + .ui-menu-item-icon .ui-menu-item-image { + width: 1.2em; + height: 1.2em; + display: inline-block; + } + .ui-menu-item-content { + flex: 1; + position: relative; + @include flex-bar; + } + .ui-menu-item-arrow { + width: 1.6em; + text-align: center; + color: var(--ui-TC-3); + } + &::after { + content: ' '; + width: calc(200% - 120rpx); + left: 30rpx; + position: absolute; + top: 0; + box-sizing: border-box; + height: 200%; + border-top: 1px solid var(--ui-Border); + border-radius: inherit; + transform: scale(1); + transform-origin: 0 0; + pointer-events: none; + } + &.first-item::after { + display: none; + } + &:first-child::after { + display: none; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_shadow.scss b/yudao-mall-uniapp-master/sheep/scss/style/_shadow.scss new file mode 100644 index 0000000..27cb3f6 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_shadow.scss @@ -0,0 +1,90 @@ +/* ================== + 阴影 + ==================== */ + +.shadow { + box-shadow: var(--ui-Shadow); + &-sm { + box-shadow: var(--ui-Shadow-sm); + } + &-lg { + box-shadow: var(--ui-Shadow-lg); + } + &-inset { + box-shadow: var(--ui-Shadow-inset); + } + @each $color, $value in $colors { + @at-root .shadow-#{$color} { + box-shadow: 0 0.5em 1em rgba($value, var(--ui-Shadow-opacity)); + } + &-sm.shadow-#{$color} { + box-shadow: 0 0.125em 0.25em rgba($value, var(--ui-Shadow-opacity)); + } + &-lg.shadow-#{$color} { + box-shadow: 0 1em 3em rgba($value, var(--ui-Shadow-opacity-lg)); + } + } + + &-warp { + position: relative; + } + &-warp:before, + &-warp:after { + position: absolute; + content: ''; + bottom: -10rpx; + left: 20rpx; + width: calc(50% - #{40rpx}); + height: 30rpx; + transform: skew(0deg, -6deg); + transform-origin: 50% 50%; + background-color: rgba(0, 0, 0, var(--ui-Shadow-opacity)); + filter: blur(20rpx); + z-index: -1; + opacity: 0.5; + } + &-warp:after { + right: 20rpx; + left: auto; + transform: skew(0deg, 6deg); + } + &-blur { + position: relative; + } + &-blur::before { + content: ''; + display: block; + background: inherit; + filter: blur(20rpx); + position: absolute; + width: 100%; + height: 100%; + top: 0.5em; + left: 0.5em; + z-index: -1; + opacity: var(--ui-Shadow-opacity-lg); + transform-origin: 0 0; + border-radius: inherit; + transform: scale(1, 1); + } +} +.drop-shadow { + filter: drop-shadow(0 0 30rpx rgba(0, 0, 0, 0.1)); + &-sm { + filter: drop-shadow(0 4rpx 4rpx rgba(0, 0, 0, 0.06)); + } + &-lg { + filter: drop-shadow(0 30rpx 60rpx rgba(0, 0, 0, 0.2)); + } + @each $color, $value in $colors { + @at-root .drop-shadow-#{$color} { + filter: drop-shadow(0 15rpx 15rpx rgba(darken($value, 10%), 0.3)); + } + &-sm.drop-shadow-#{$color} { + filter: drop-shadow(0 4rpx 4rpx rgba(darken($value, 10%), 0.3)); + } + &-lg.drop-shadow-#{$color} { + filter: drop-shadow(0 50rpx 100rpx rgba(darken($value, 10%), 0.2)); + } + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_table.scss b/yudao-mall-uniapp-master/sheep/scss/style/_table.scss new file mode 100644 index 0000000..ad5effa --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_table.scss @@ -0,0 +1,133 @@ +.ui-table { + background-color: var(--ui-BG); + max-width: 100%; + display: table; + &.table-full { + width: 100%; + } + &.table-radius { + border-radius: $radius; + .ui-table-header { + .ui-table-tr { + border-top-left-radius: $radius; + border-top-right-radius: $radius; + } + .ui-table-th { + &:first-child { + border-top-left-radius: $radius; + } + &:last-child { + border-top-right-radius: $radius; + } + } + } + } + .ui-table-header { + display: table-header-group; + .ui-table-th { + font-weight: bold; + border-bottom: 1px solid var(--ui-Border); + white-space: nowrap; + + padding: 1em 0.8em; + } + } + + .ui-table-tr { + display: table-row; + z-index: 1; + } + + .ui-table-body { + display: table-row-group; + position: relative; + .ui-table-tr:hover { + background-color: var(--ui-BG-1) !important; + } + .ui-table-loading { + min-height: 300px; + position: absolute !important; + width: 100%; + height: 100%; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--ui-Border); + } + } + + .ui-table-td, + .ui-table-th { + display: table-cell; + text-align: unset; + padding: 0.5em 0.8em; + // font-size: 90%; + vertical-align: middle; + } +} + +.ui-table.table-border { + &, + & .ui-table-td, + & .ui-table-th { + position: relative; + &::after { + content: ' '; + width: 200%; + height: 200%; + position: absolute; + top: 0; + left: 0; + border-radius: inherit; + transform: scale(0.5); + transform-origin: 0 0; + pointer-events: none; + box-sizing: border-box; + border: 1px solid var(--ui-Border); + z-index: 1; + } + } + .ui-table-td, + .ui-table-th { + &::after { + border-width: 1px 1px 0 0; + } + &:last-child::after { + border-right: none; + } + } +} +.ui-table.table-radius { + &::after { + border-radius: calc(#{$radius} * 2); + } + & .ui-table-tr .ui-table-th:first-child { + border-top-left-radius: calc(#{$radius} * 2); + } + & .ui-table-tr .ui-table-th:last-child { + border-top-right-radius: calc(#{$radius} * 2); + } + & .ui-table-tr:last-child .ui-table-td:first-child { + border-bottom-left-radius: #{$radius}; + } + & .ui-table-tr:last-child .ui-table-td:last-child { + border-bottom-right-radius: #{$radius}; + } +} +.ui-table.table-striped > .ui-table-body > .ui-table-tr:nth-child(2n + 1), +.ui-table.table-striped > .ui-table-body > .ui-table-tr:nth-child(2n + 1) { + background-color: var(--ui-BG-1); +} + +.table-responsive { + width: inherit; + height: 100%; + max-width: 100%; + overflow: hidden; + box-sizing: border-box; + .table-responsive-box { + position: relative; + overflow: hidden; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_tag.scss b/yudao-mall-uniapp-master/sheep/scss/style/_tag.scss new file mode 100644 index 0000000..e69de29 diff --git a/yudao-mall-uniapp-master/sheep/scss/style/_text.scss b/yudao-mall-uniapp-master/sheep/scss/style/_text.scss new file mode 100644 index 0000000..8249022 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/style/_text.scss @@ -0,0 +1,104 @@ +/* ================== + 文本 + ==================== */ +@use 'sass:math'; +.font-0 { + font-size: 24rpx; + --textSize: -4rpx; +} +.font-1 { + font-size: 28rpx; + --textSize: 0rpx; +} +.font-2 { + font-size: 32rpx; + --textSize: 4rpx; +} +.font-3 { + font-size: 36rpx; + --textSize: 8rpx; +} +.font-4 { + font-size: 40rpx; + --textSize: 12rpx; +} +.text { + @each $class, $value in $fontsize { + &-#{$class}, + &-#{math.div($value ,2)} { + font-size: calc(#{$value}rpx + var(--textSize)) !important; + } + } + &-cut { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + @at-root [class*='text-linecut'] { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + word-break: break-all; + } + @for $i from 2 through 10 { + &-linecut-#{$i} { + -webkit-line-clamp: #{$i}; + } + } + &-justify { + text-align: justify; + } + &-justify-line { + text-align: justify; + line-height: 0.5em; + margin-top: 0.5em; + &::after { + content: '.'; + display: inline-block; + width: 100%; + } + } + + &-Abc { + text-transform: Capitalize !important; + } + &-ABC { + text-transform: Uppercase !important; + } + &-abc { + text-transform: Lowercase !important; + } + &-del, + &-line { + text-decoration: line-through !important; + } + &-bottomline { + text-decoration: underline !important; + } + &-italic { + font-style: italic !important; + } + &-style-none { + text-decoration: none !important; + } + &-break { + word-break: break-word !important; + overflow-wrap: break-word !important; + } + &-reset { + color: inherit !important; + } + &-price::before { + content: '¥'; + font-size: 80%; + margin-right: 4rpx; + } + &-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/theme/_dark.scss b/yudao-mall-uniapp-master/sheep/scss/theme/_dark.scss new file mode 100644 index 0000000..8caad17 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/theme/_dark.scss @@ -0,0 +1,39 @@ +// 核心主题样式文件 +@mixin theme-dark { + // 背景色 + --ui-BG: #393939; + --ui-BG-1: #333333; + --ui-BG-2: #2c2c2c; + --ui-BG-3: #292929; + --ui-BG-4: #222222; + + // 文本色 + --ui-TC: #ffffff; + --ui-TC-1: #d4d4d4; + --ui-TC-2: #919191; + --ui-TC-3: #6a6a6a; + --ui-TC-4: #474747; + + // 模糊 + --ui-Blur: rgba(38, 38, 38, 0.98); + --ui-Blur-1: rgba(38, 38, 38, 0.75); + --ui-Blur-2: rgba(38, 38, 38, 0.25); + --ui-Blur-3: rgba(38, 38, 38, 0.05); + + // 边框 + --ui-Border: rgba(119, 119, 119, 0.25); + --ui-Outline: rgba(255, 255, 255, 0.1); + --ui-Line: rgba(119, 119, 119, 0.25); + + // 透明与阴影 + --ui-Shadow: 0 0.5em 1em rgba(0, 0, 0, 0.45); + --ui-Shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.475); + --ui-Shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.475); + --ui-Shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.475); + + --ui-Shadow-opacity: 0.55; + --ui-Shadow-opacity-sm: 0.175; + --ui-Shadow-opacity-lg: 0.75; + + --ui-BG-opacity: 0.1; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/theme/_light.scss b/yudao-mall-uniapp-master/sheep/scss/theme/_light.scss new file mode 100644 index 0000000..af5f245 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/theme/_light.scss @@ -0,0 +1,39 @@ +// 核心主题样式文件 +@mixin theme-light { + // 背景色 + --ui-BG: #ffffff; + --ui-BG-1: #f6f6f6; + --ui-BG-2: #f1f1f1; + --ui-BG-3: #e8e8e8; + --ui-BG-4: #e0e0e0; + + // 文本色 + --ui-TC: #303030; + --ui-TC-1: #525252; + --ui-TC-2: #777777; + --ui-TC-3: #9e9e9e; + --ui-TC-4: #c6c6c6; + + // 模糊 + --ui-Blur: rgba(255, 255, 255, 0.98); + --ui-Blur-1: rgba(255, 255, 255, 0.75); + --ui-Blur-2: rgba(255, 255, 255, 0.25); + --ui-Blur-3: rgba(255, 255, 255, 0.05); + + // 边框 + --ui-Border: rgba(119, 119, 119, 0.25); + --ui-Outline: rgba(0, 0, 0, 0.1); + --ui-Line: rgba(119, 119, 119, 0.25); + + // 透明与阴影 + --ui-Shadow: 0 0.5em 1em rgba(0, 0, 0, 0.15); + --ui-Shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.075); + --ui-Shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.175); + --ui-Shadow-inset: inset 0 0.1em 0.2em rgba(0, 0, 0, 0.075); + + --ui-Shadow-opacity: 0.45; + --ui-Shadow-opacity-sm: 0.075; + --ui-Shadow-opacity-lg: 0.65; + + --ui-BG-opacity: 0.1; +} diff --git a/yudao-mall-uniapp-master/sheep/scss/theme/_style.scss b/yudao-mall-uniapp-master/sheep/scss/theme/_style.scss new file mode 100644 index 0000000..1eef587 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/theme/_style.scss @@ -0,0 +1,68 @@ +@import './light'; //浅蓝主题 +@import './dark'; //深蓝主题 +// 多主题 +.theme-light { + @include theme-light; +} +.theme-dark { + @include theme-dark; +} +.theme-auto { + @include theme-light; +} +@media (prefers-color-scheme: dark) { + .theme-auto { + @include theme-dark; + } +} + +@each $value in ('', '-1', '-2', '-3', '-4') { + // 背景色 + 文字色 : 白色 + 默认色; + .ui-BG#{$value} { + background-color: var(--ui-BG#{$value}) !important; + color: var(--ui-TC); + } + // 文字颜色 + .ui-TC#{$value} { + color: var(--ui-TC#{$value}) !important; + } + // 主题色背景 + .ui-BG-Main#{$value} { + background-color: var(--ui-BG-Main#{$value}) !important; + color: var(--ui-BG-Main-TC) !important; + } + // 主题色渐变,横向 + .ui-BG-Main-Gradient { + background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)) !important; + color: var(--ui-BG-Main-TC) !important; + } + // 主题色文字 + .ui-TC-Main#{$value} { + color: var(--ui-BG-Main#{$value}) !important; + } + // 主题色阴影 + .ui-Shadow-Main { + box-shadow: var(--ui-Main-box-shadow) !important; + } + .ui-BG-Main-light { + background: var(----ui-BG-Main-light) !important; + color: var(--ui-BG-Main#{$value}) !important; + } +} + +@each $color, $value in $colors { + .main-#{$color} { + --ui-BG-Main: #{$value}; + --ui-BG-Main-tag: #{rgba($value, 0.05)}; + --ui-BG-Main-gradient: #{rgba($value, 0.6)}; + --ui-BG-Main-light: #{rgba($value, 0.2)}; + --ui-BG-Main-opacity-1: #{rgba($value, 0.1)}; + --ui-BG-Main-opacity-4: #{rgba($value, 0.4)}; + --ui-Main-box-shadow: 0 0.2em 0.5em #{rgba($value, var(--ui-Shadow-opacity))}; + --ui-BG-Main-1: #{mix(rgba(255, 255, 255, 0.7), desaturate($value, 20%), 10%)}; + --ui-BG-Main-2: #{mix(rgba(255, 255, 255, 0.6), desaturate($value, 40%), 20%)}; + --ui-BG-Main-3: #{mix(rgba(119, 119, 119, 0.2), desaturate($value, 40%), 40%)}; + --ui-BG-Main-4: #{mix(rgba(119, 119, 119, 0.1), desaturate($value, 40%), 60%)}; + --ui-BG-Main-TC: #ffffff !important; + } +} diff --git a/yudao-mall-uniapp-master/sheep/scss/ui.scss b/yudao-mall-uniapp-master/sheep/scss/ui.scss new file mode 100644 index 0000000..b9b7381 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/scss/ui.scss @@ -0,0 +1,19 @@ +@import './theme/style'; //系统主题 +@import './main'; //主样式* + +@import './style/background'; //背景 +@import './style/grid'; //列 +@import './style/flex'; //布局 +@import './style/border'; //边框 +@import './style/text'; //文本 +@import './style/shadow'; //阴影 +@import './icon/style'; //图标 +@import './style/tag'; //标签 +@import './style/button'; //按钮 +@import './style/avatar'; //头像 +@import './style/table'; //表格 +@import './style/code'; //代码片段 +@import './style/form'; //表单 +@import './style/menu'; //表单 +@import './style/markdown'; //表单 +@import './style/card'; //表单 diff --git a/yudao-mall-uniapp-master/sheep/store/app.js b/yudao-mall-uniapp-master/sheep/store/app.js new file mode 100644 index 0000000..573c237 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/app.js @@ -0,0 +1,139 @@ +import DiyApi from '@/sheep/api/promotion/diy'; +import { defineStore } from 'pinia'; +import $platform from '@/sheep/platform'; +import $router from '@/sheep/router'; +import user from './user'; +import sys from './sys'; + +const app = defineStore({ + id: 'app', + state: () => ({ + info: { + // 应用信息 + name: '', // 商城名称 + logo: '', // logo + version: '', // 版本号 + copyright: '', // 版权信息 I + copytime: '', // 版权信息 II + + cdnurl: '', // 云存储域名 + filesystem: '', // 云存储平台 + }, + platform: { + share: { + methods: [], // 支持的分享方式 + forwardInfo: {}, // 默认转发信息 + posterInfo: {}, // 海报信息 + linkAddress: '', // 复制链接地址 + }, + bind_mobile: 0, // 登陆后绑定手机号提醒 (弱提醒,可手动关闭) + }, + chat: {}, + template: { + // 店铺装修模板 + basic: {}, // 基本信息 + home: { + // 首页模板 + style: {}, + data: [], + }, + user: { + // 个人中心模板 + style: {}, + data: [], + }, + }, + shareInfo: {}, // 全局分享信息 + has_wechat_trade_managed: 0 // 小程序发货信息管理 0 没有 || 1 有 + }), + actions: { + // 获取Shopro应用配置和模板 + async init(templateId = null) { + // 检查网络 + const networkStatus = await $platform.checkNetwork(); + if (!networkStatus) { + $router.error('NetworkError'); + } + + // 加载装修配置 + await adaptTemplate(this.template, templateId) + + // TODO 芋艿:未来支持管理后台可配;对应 https://api.shopro.sheepjs.com/shop/api/init + if (true) { + this.info = { + name: '芋道商城', + logo: 'https://static.iocoder.cn/ruoyi-vue-pro-logo.png', + version: '1.1.13', + copyright: '全部开源,个人与企业可 100% 免费使用', + copytime: 'Copyright© 2018-2024', + + cdnurl: 'https://file.sheepjs.com', // 云存储域名 + filesystem: 'qcloud', // 云存储平台 + }; + this.platform = { + share: { + methods: ["poster", "link"], + linkAddress: "https://shopro.sheepjs.com/#/", + posterInfo: { + "user_bg": "/static/img/shop/config/user-poster-bg.png", + "goods_bg": "/static/img/shop/config/goods-poster-bg.png", + "groupon_bg": "/static/img/shop/config/groupon-poster-bg.png" + } + }, + bind_mobile: 0 + }; + this.chat = { + chat_domain: "https://api.shopro.sheepjs.com/chat", + room_id: "admin" + } + this.has_wechat_trade_managed = 0; + + // 加载主题 + const sysStore = sys(); + sysStore.setTheme(); + + // 模拟用户登录 + const userStore = user(); + if (userStore.isLogin) { + userStore.loginAfter(); + } + return Promise.resolve(true); + } else { + $router.error('InitError', res.msg || '加载失败'); + } + }, + }, + persist: { + enabled: true, + strategies: [ + { + key: 'app-store', + }, + ], + }, +}); + +// todo: @owen 先做数据适配,后期重构 +const adaptTemplate = async (appTemplate, templateId) => { + const { data: diyTemplate } = templateId + // 查询指定模板,一般是预览时使用 + ? await DiyApi.getDiyTemplate(templateId) + : await DiyApi.getUsedDiyTemplate(); + // 模板不存在 + if (!diyTemplate) { + $router.error('TemplateError'); + return + } + + const tabBar = diyTemplate?.property?.tabBar; + if (tabBar) { + appTemplate.basic.tabbar = tabBar + if (tabBar?.theme) { + appTemplate.basic.theme = tabBar?.theme; + } + } + appTemplate.home = diyTemplate?.home; + appTemplate.user = diyTemplate?.user; +} + +export default app; diff --git a/yudao-mall-uniapp-master/sheep/store/cart.js b/yudao-mall-uniapp-master/sheep/store/cart.js new file mode 100644 index 0000000..7ea7019 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/cart.js @@ -0,0 +1,106 @@ +import { defineStore } from 'pinia'; +import CartApi from '@/sheep/api/trade/cart'; + +const cart = defineStore({ + id: 'cart', + state: () => ({ + list: [], // 购物车列表 + selectedIds: [], // 已选列表 + isAllSelected: false, // 是否全选 + totalPriceSelected: 0, // 选中项总金额 + }), + actions: { + // 获取购物车列表 + async getList() { + const { data, code } = await CartApi.getCartList(); + if (code === 0) { + this.list = data.validList; + + // 计算各种关联属性 + this.selectedIds = []; + this.isAllSelected = true; + this.totalPriceSelected = 0; + this.list.forEach((item) => { + if (item.selected) { + this.selectedIds.push(item.id); + this.totalPriceSelected += item.count * item.sku.price; + } else { + this.isAllSelected = false; + } + }); + } + }, + + // 添加购物车 + async add(goodsInfo) { + // 添加购物项 + const { code } = await CartApi.addCart({ + skuId: goodsInfo.id, + count: goodsInfo.goods_num, + }); + // 刷新购物车列表 + if (code === 0) { + await this.getList(); + } + }, + + // 更新购物车 + async update(goodsInfo) { + const { code } = await CartApi.updateCartCount({ + id: goodsInfo.goods_id, + count: goodsInfo.goods_num, + }); + if (code === 0) { + await this.getList(); + } + }, + + // 移除购物车 + async delete(ids) { + const { code } = await CartApi.deleteCart(ids.join(',')); + if (code === 0) { + await this.getList(); + } + }, + + // 单选购物车商品 + async selectSingle(goodsId) { + const { code } = await CartApi.updateCartSelected({ + ids: [goodsId], + selected: !this.selectedIds.includes(goodsId), // 取反 + }); + if (code === 0) { + await this.getList(); + } + }, + + // 全选购物车商品 + async selectAll(flag) { + const { code } = await CartApi.updateCartSelected({ + ids: this.list.map((item) => item.id), + selected: flag + }); + if (code === 0) { + await this.getList(); + } + }, + + // 清空购物车。注意,仅用于用户退出时,重置数据 + emptyList() { + this.list = []; + this.selectedIds = []; + this.isAllSelected = true; + this.totalPriceSelected = 0; + }, + }, + persist: { + enabled: true, + strategies: [ + { + key: 'cart-store', + }, + ], + }, +}); + +export default cart; diff --git a/yudao-mall-uniapp-master/sheep/store/index.js b/yudao-mall-uniapp-master/sheep/store/index.js new file mode 100644 index 0000000..3d06698 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/index.js @@ -0,0 +1,20 @@ +import { createPinia } from 'pinia'; +import piniaPersist from 'pinia-plugin-persist-uni'; + +// 自动注入所有pinia模块 +const files = import.meta.glob('./*.js', { eager: true }); +const modules = {}; +Object.keys(files).forEach((key) => { + modules[key.replace(/(.*\/)*([^.]+).*/gi, '$2')] = files[key].default; +}); + +export const setupPinia = (app) => { + const pinia = createPinia(); + pinia.use(piniaPersist); + + app.use(pinia); +}; + +export default (name) => { + return modules[name](); +}; diff --git a/yudao-mall-uniapp-master/sheep/store/modal.js b/yudao-mall-uniapp-master/sheep/store/modal.js new file mode 100644 index 0000000..bde9e0a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/modal.js @@ -0,0 +1,29 @@ +import { defineStore } from 'pinia'; + +const modal = defineStore({ + id: 'modal', + state: () => ({ + auth: '', // 授权弹框 accountLogin|smsLogin|resetPassword|changeMobile|changePassword|changeUsername + share: false, // 分享弹框 + menu: false, // 快捷菜单弹框 + advHistory: [], // 广告弹框记录 + lastTimer: { + // 短信验证码计时器,为了防止刷新请求做了持久化 + smsLogin: 0, + changeMobile: 0, + resetPassword: 0, + changePassword: 0, + } + }), + persist: { + enabled: true, + strategies: [ + { + key: 'modal-store', + paths: ['lastTimer', 'advHistory'], + }, + ], + }, +}); + +export default modal; diff --git a/yudao-mall-uniapp-master/sheep/store/sys.js b/yudao-mall-uniapp-master/sheep/store/sys.js new file mode 100644 index 0000000..f7151e0 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/sys.js @@ -0,0 +1,32 @@ +import { defineStore } from 'pinia'; +import app from './app'; + +const sys = defineStore({ + id: 'sys', + state: () => ({ + theme: '', // 主题, + mode: 'light', // 明亮模式、暗黑模式(暂未支持) + modeAuto: false, // 跟随系统 + fontSize: 1, // 设置默认字号等级(0-4) + }), + getters: {}, + actions: { + setTheme(theme = '') { + if (theme === '') { + this.theme = app().template?.basic.theme || 'orange'; + } else { + this.theme = theme; + } + }, + }, + persist: { + enabled: true, + strategies: [ + { + key: 'sys-store', + }, + ], + }, +}); + +export default sys; diff --git a/yudao-mall-uniapp-master/sheep/store/user.js b/yudao-mall-uniapp-master/sheep/store/user.js new file mode 100644 index 0000000..195dade --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/store/user.js @@ -0,0 +1,180 @@ +import { defineStore } from 'pinia'; +import $share from '@/sheep/platform/share'; +import { clone, cloneDeep } from 'lodash'; +import cart from './cart'; +import app from './app'; +import { showAuthModal } from '@/sheep/hooks/useModal'; +import UserApi from '@/sheep/api/member/user'; +import PayWalletApi from '@/sheep/api/pay/wallet'; +import OrderApi from '@/sheep/api/trade/order'; +import CouponApi from '@/sheep/api/promotion/coupon'; + +// 默认用户信息 +const defaultUserInfo = { + avatar: '', // 头像 + nickname: '', // 昵称 + gender: 0, // 性别 + mobile: '', // 手机号 + point: 0, // 积分 +}; + +// 默认钱包信息 +const defaultUserWallet = { + balance: 0, // 余额 +}; + +// 默认订单、优惠券等其他资产信息 +const defaultNumData = { + unusedCouponCount: 0, + orderCount: { + allCount: 0, + unpaidCount: 0, + undeliveredCount: 0, + deliveredCount: 0, + uncommentedCount: 0, + afterSaleCount: 0, + }, +}; + +const user = defineStore({ + id: 'user', + state: () => ({ + userInfo: clone(defaultUserInfo), // 用户信息 + userWallet: clone(defaultUserWallet), // 用户钱包信息 + isLogin: !!uni.getStorageSync('token'), // 登录状态 + numData: cloneDeep(defaultNumData), // 用户其他数据 + lastUpdateTime: 0, // 上次更新时间 + }), + + actions: { + // 获取用户信息 + async getInfo() { + const { code, data } = await UserApi.getUserInfo(); + if (code !== 0) { + return; + } + this.userInfo = data; + return Promise.resolve(data); + }, + + // 获得用户钱包 + async getWallet() { + const { code, data } = await PayWalletApi.getPayWallet(); + if (code !== 0) { + return; + } + this.userWallet = data; + }, + + // 获取订单、优惠券等其他资产信息 + getNumData() { + OrderApi.getOrderCount().then(res => { + if (res.code === 0) { + this.numData.orderCount = res.data; + } + }); + CouponApi.getUnusedCouponCount().then(res => { + if (res.code === 0) { + this.numData.unusedCouponCount = res.data; + } + }); + }, + + // 添加分享记录 + // TODO 芋艿:整理下; + // async addShareLog(params) { + // const { + // error + // } = await userApi.addShareLog(params); + // if (error === 0) uni.removeStorageSync('shareLog'); + // }, + + // 设置 token + setToken(token = '', refreshToken = '') { + if (token === '') { + this.isLogin = false; + uni.removeStorageSync('token'); + uni.removeStorageSync('refresh-token'); + } else { + this.isLogin = true; + uni.setStorageSync('token', token); + uni.setStorageSync('refresh-token', refreshToken); + this.loginAfter(); + } + return this.isLogin; + }, + + // 更新用户相关信息 (手动限流,5 秒之内不刷新) + async updateUserData() { + if (!this.isLogin) { + this.resetUserData(); + return; + } + // 防抖,5 秒之内不刷新 + const nowTime = new Date().getTime(); + if (this.lastUpdateTime + 5000 > nowTime) { + return; + } + this.lastUpdateTime = nowTime; + + // 获取最新信息 + await this.getInfo(); + this.getWallet(); + this.getNumData(); + return this.userInfo; + }, + + // 重置用户默认数据 + resetUserData() { + // 清空 token + this.setToken(); + // 清空用户相关的缓存 + this.userInfo = clone(defaultUserInfo); + this.userWallet = clone(defaultUserWallet); + this.numData = cloneDeep(defaultNumData); + // 清空购物车的缓存 + cart().emptyList(); + }, + + // 登录后,加载各种信息 + // TODO 芋艿:整理下; + async loginAfter() { + await this.updateUserData(); + + // 加载购物车 + cart().getList(); + // 登录后设置全局分享参数 + $share.getShareInfo(); + + // 提醒绑定手机号 + if (app().platform.bind_mobile && !this.userInfo.mobile) { + showAuthModal('changeMobile'); + } + + // 绑定推广员 + $share.bindBrokerageUser() + // 添加分享记录 + // TODO 芋艿:整理下; + // const shareLog = uni.getStorageSync('shareLog'); + // if (!isEmpty(shareLog)) { + // this.addShareLog({ + // ...shareLog, + // }); + // } + }, + + // 登出系统 + async logout() { + this.resetUserData(); + return !this.isLogin; + } + }, + persist: { + enabled: true, + strategies: [{ + key: 'user-store', + }] + }, +}); + +export default user; diff --git a/yudao-mall-uniapp-master/sheep/ui/su-coupon/su-coupon.vue b/yudao-mall-uniapp-master/sheep/ui/su-coupon/su-coupon.vue new file mode 100644 index 0000000..472d17f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-coupon/su-coupon.vue @@ -0,0 +1,319 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-data-checkbox/su-data-checkbox.vue b/yudao-mall-uniapp-master/sheep/ui/su-data-checkbox/su-data-checkbox.vue new file mode 100644 index 0000000..537ead5 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-data-checkbox/su-data-checkbox.vue @@ -0,0 +1,894 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-dialog/su-dialog.vue b/yudao-mall-uniapp-master/sheep/ui/su-dialog/su-dialog.vue new file mode 100644 index 0000000..b53e9ce --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-dialog/su-dialog.vue @@ -0,0 +1,269 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-fixed/su-fixed.vue b/yudao-mall-uniapp-master/sheep/ui/su-fixed/su-fixed.vue new file mode 100644 index 0000000..e2a9808 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-fixed/su-fixed.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-image/su-image.vue b/yudao-mall-uniapp-master/sheep/ui/su-image/su-image.vue new file mode 100644 index 0000000..35f8410 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-image/su-image.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-inner-navbar/su-inner-navbar.vue b/yudao-mall-uniapp-master/sheep/ui/su-inner-navbar/su-inner-navbar.vue new file mode 100644 index 0000000..9fc102d --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-inner-navbar/su-inner-navbar.vue @@ -0,0 +1,365 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-navbar/su-navbar.vue b/yudao-mall-uniapp-master/sheep/ui/su-navbar/su-navbar.vue new file mode 100644 index 0000000..af96f24 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-navbar/su-navbar.vue @@ -0,0 +1,483 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-notice-bar/su-notice-bar.vue b/yudao-mall-uniapp-master/sheep/ui/su-notice-bar/su-notice-bar.vue new file mode 100644 index 0000000..fc5075a --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-notice-bar/su-notice-bar.vue @@ -0,0 +1,473 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-number-box/su-number-box.vue b/yudao-mall-uniapp-master/sheep/ui/su-number-box/su-number-box.vue new file mode 100644 index 0000000..6b662cd --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-number-box/su-number-box.vue @@ -0,0 +1,225 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-popover/su-popover.vue b/yudao-mall-uniapp-master/sheep/ui/su-popover/su-popover.vue new file mode 100644 index 0000000..adff127 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-popover/su-popover.vue @@ -0,0 +1,314 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-popup/keypress.js b/yudao-mall-uniapp-master/sheep/ui/su-popup/keypress.js new file mode 100644 index 0000000..6141c4c --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-popup/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false, + }, + }, + mounted() { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'], + }; + const listener = ($event) => { + if (this.disable) { + return; + } + const keyName = Object.keys(keyNames).find((key) => { + const keyName = $event.key; + const value = keyNames[key]; + return value === keyName || (Array.isArray(value) && value.includes(keyName)); + }); + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}); + }, 0); + } + }; + document.addEventListener('keyup', listener); + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {}, +}; +// #endif diff --git a/yudao-mall-uniapp-master/sheep/ui/su-popup/su-popup.vue b/yudao-mall-uniapp-master/sheep/ui/su-popup/su-popup.vue new file mode 100644 index 0000000..b55b007 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-popup/su-popup.vue @@ -0,0 +1,589 @@ + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-progress/su-progress.vue b/yudao-mall-uniapp-master/sheep/ui/su-progress/su-progress.vue new file mode 100644 index 0000000..4612705 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-progress/su-progress.vue @@ -0,0 +1,203 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-radio/su-radio.vue b/yudao-mall-uniapp-master/sheep/ui/su-radio/su-radio.vue new file mode 100644 index 0000000..6fc4f74 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-radio/su-radio.vue @@ -0,0 +1,301 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-region-picker/su-region-picker.vue b/yudao-mall-uniapp-master/sheep/ui/su-region-picker/su-region-picker.vue new file mode 100644 index 0000000..958fd11 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-region-picker/su-region-picker.vue @@ -0,0 +1,247 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-status-bar/su-status-bar.vue b/yudao-mall-uniapp-master/sheep/ui/su-status-bar/su-status-bar.vue new file mode 100644 index 0000000..9af07f9 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-status-bar/su-status-bar.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-sticky/su-sticky.vue b/yudao-mall-uniapp-master/sheep/ui/su-sticky/su-sticky.vue new file mode 100644 index 0000000..a8831a2 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-sticky/su-sticky.vue @@ -0,0 +1,264 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-subline/su-subline.vue b/yudao-mall-uniapp-master/sheep/ui/su-subline/su-subline.vue new file mode 100644 index 0000000..c11d176 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-subline/su-subline.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-swiper/su-swiper.vue b/yudao-mall-uniapp-master/sheep/ui/su-swiper/su-swiper.vue new file mode 100644 index 0000000..cff1c4b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-swiper/su-swiper.vue @@ -0,0 +1,502 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-switch/su-switch.vue b/yudao-mall-uniapp-master/sheep/ui/su-switch/su-switch.vue new file mode 100644 index 0000000..d63e800 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-switch/su-switch.vue @@ -0,0 +1,100 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tab-item/su-tab-item.vue b/yudao-mall-uniapp-master/sheep/ui/su-tab-item/su-tab-item.vue new file mode 100644 index 0000000..615df2f --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tab-item/su-tab-item.vue @@ -0,0 +1,169 @@ + + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tab/su-tab.vue b/yudao-mall-uniapp-master/sheep/ui/su-tab/su-tab.vue new file mode 100644 index 0000000..17a7983 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tab/su-tab.vue @@ -0,0 +1,474 @@ + + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tabbar-item/su-tabbar-item.vue b/yudao-mall-uniapp-master/sheep/ui/su-tabbar-item/su-tabbar-item.vue new file mode 100644 index 0000000..cc55ac1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tabbar-item/su-tabbar-item.vue @@ -0,0 +1,234 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tabbar/su-tabbar.vue b/yudao-mall-uniapp-master/sheep/ui/su-tabbar/su-tabbar.vue new file mode 100644 index 0000000..92e0352 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tabbar/su-tabbar.vue @@ -0,0 +1,227 @@ + + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/props.js b/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/props.js new file mode 100644 index 0000000..3908c36 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/props.js @@ -0,0 +1,3 @@ +export default { + props: {}, +}; diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/su-tabs-item.vue b/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/su-tabs-item.vue new file mode 100644 index 0000000..7139684 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tabs-item/su-tabs-item.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-tabs/su-tabs.vue b/yudao-mall-uniapp-master/sheep/ui/su-tabs/su-tabs.vue new file mode 100644 index 0000000..05d7dcb --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-tabs/su-tabs.vue @@ -0,0 +1,434 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-time-line/su-time-line.vue b/yudao-mall-uniapp-master/sheep/ui/su-time-line/su-time-line.vue new file mode 100644 index 0000000..9c3f8c1 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-time-line/su-time-line.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-timeline-item/su-timeline-item.vue b/yudao-mall-uniapp-master/sheep/ui/su-timeline-item/su-timeline-item.vue new file mode 100644 index 0000000..ddf7a0b --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-timeline-item/su-timeline-item.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-toolbar/su-toolbar.vue b/yudao-mall-uniapp-master/sheep/ui/su-toolbar/su-toolbar.vue new file mode 100644 index 0000000..17351ec --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-toolbar/su-toolbar.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/yudao-mall-uniapp-master/sheep/ui/su-video/su-video.vue b/yudao-mall-uniapp-master/sheep/ui/su-video/su-video.vue new file mode 100644 index 0000000..a75a79c --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/ui/su-video/su-video.vue @@ -0,0 +1,199 @@ + + + diff --git a/yudao-mall-uniapp-master/sheep/url/index.js b/yudao-mall-uniapp-master/sheep/url/index.js new file mode 100644 index 0000000..d216f83 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/url/index.js @@ -0,0 +1,199 @@ +import $store from '@/sheep/store'; +import { staticUrl } from '@/sheep/config'; + +const cdn = (url = '', cdnurl = '') => { + if (!url) return ''; + if (url.indexOf('http') === 0) { + return url; + } + if (cdnurl === '') { + cdnurl = $store('app').info.cdnurl; + } + return cdnurl + url; +}; +export default { + // 添加cdn域名前缀 + cdn, + // 对象存储自动剪裁缩略图 + thumb: (url = '', params) => { + url = cdn(url); + return append_thumbnail_params(url, params); + }, + // 静态资源地址 + static: (url = '', staticurl = '') => { + if (staticurl === '') { + staticurl = staticUrl; + } + if (staticurl !== 'local') { + url = cdn(url, staticurl); + } + return url; + }, + // css背景图片地址 + css: (url = '', staticurl = '') => { + if (staticurl === '') { + staticurl = staticUrl; + } + if (staticurl !== 'local') { + url = cdn(url, staticurl); + } + // #ifdef APP-PLUS + if (staticurl === 'local') { + url = plus.io.convertLocalFileSystemURL(url); + } + // #endif + return `url(${url})`; + }, +}; + +/** + * 追加对象存储自动裁剪/压缩参数 + * + * @return string + */ +function append_thumbnail_params(url, params) { + const filesystem = $store('app').info.filesystem; + if (filesystem === 'public') { + return url; + } + let width = params.width || '200'; // 宽度 + let height = params.height || '200'; // 高度 + let mode = params.mode || 'lfit'; // 缩放模式 + let quality = params.quality || 90; // 压缩质量 + let gravity = params.gravity || 'center'; // 剪裁质量 + let suffix = ''; + let crop_str = ''; + let quality_str = ''; + let size = width + 'x' + height; + switch (filesystem) { + case 'aliyun': + // 裁剪 + if (!gravity && gravity != 'center') { + // 指定了裁剪区域 + mode = 'mfit'; + crop_str = '/crop,g_' + gravityFormatMap('aliyun', gravity) + ',w_' + width + ',h_' + height; + } + + // 质量压缩 + if (quality > 0 && quality < 100) { + quality_str = '/quality,q_' + quality; + } + + // 缩放参数 + suffix = 'x-oss-process=image/resize,m_' + mode + ',w_' + width + ',h_' + height; + + // 拼接裁剪和质量压缩 + suffix += crop_str + quality_str; + break; + case 'qcloud': + let mode_str = 'thumbnail'; + if (mode == 'fill' || (!gravity && gravity != 'center')) { + // 指定了裁剪区域 + mode_str = 'crop'; + mode = 'fill'; + crop_str = '/gravity/' + gravityFormatMap('qcloud', gravity); + } + + // 质量压缩 + if (quality > 0 && quality < 100) { + quality_str = '/rquality/' + quality; + } + + switch (mode) { + case 'lfit': + size = '' + size + '>'; + break; + case 'mfit': + size = '!' + size + 'r'; + case 'fill': + break; + case 'pad': + size = size + '/pad/1'; + break; + case 'fixed': + size = size + '!'; + break; + } + + suffix = 'imageMogr2/' + mode_str + '/' + size + crop_str + quality_str; + break; + case 'qiniu': + if (mode == 'fill' || (!gravity && gravity != 'center')) { + // 指定了裁剪区域,全部转为 mfit + mode = 'mfit'; + crop_str = '/gravity/' + gravityFormatMap('qiniu', gravity) + '/crop/' + size; + } + // 质量压缩 + if (quality > 0 && quality < 100) { + quality_str = '/quality/' + quality; + } + + switch (mode) { + case 'lfit': + case 'pad': // 七牛不支持在缩放之后,尺寸不足时,填充背景色,所以这里和 lfit 模式一样 + size = size + '>'; + break; + case 'mfit': + size = '!' + size + 'r'; + break; + case 'fill': + // 会被转为 mfit + break; + case 'fixed': + size = size + '!'; + break; + } + + suffix = 'imageMogr2/thumbnail/' + size + crop_str + quality_str; + break; + } + return url + '?' + suffix; +} + +/** + * 裁剪区域格式转换 + * + * @param string $type aliyun|qcloud|qiniu + * @param string $gravity 统一的裁剪区域字符 + * + * @return string + */ +function gravityFormatMap(type, gravity) { + let gravityFormat = { + aliyun: { + north_west: 'nw', // 左上 + north: 'north', // 中上 + north_east: 'ne', // 右上 + west: 'west', // 左中 + center: 'center', // 中部 + east: 'east', // 右中 + south_west: 'sw', // 左下 + south: 'south', // 中下 + south_east: 'se', // 右下 + }, + qcloud: { + northwest: 'nw', // 左上 + north: 'north', // 中上 + northeast: 'ne', // 右上 + west: 'west', // 左中 + center: 'center', // 中部 + east: 'east', // 右中 + southwest: 'sw', // 左下 + south: 'south', // 中下 + southeast: 'se', // 右下 + }, + qiniu: { + NorthWest: 'nw', // 左上 + North: 'north', // 中上 + NorthEast: 'ne', // 右上 + West: 'west', // 左中 + Center: 'center', // 中部 + East: 'east', // 右中 + SouthWest: 'sw', // 左下 + South: 'south', // 中下 + SouthEast: 'se', // 右下 + }, + }; + + return gravityFormat[type][gravity]; +} diff --git a/yudao-mall-uniapp-master/sheep/util/const.js b/yudao-mall-uniapp-master/sheep/util/const.js new file mode 100644 index 0000000..e5eba0c --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/util/const.js @@ -0,0 +1,68 @@ +// ========== MALL - 营销模块 ========== + +import dayjs from "dayjs"; + +/** + * 优惠类型枚举 + */ +export const PromotionDiscountTypeEnum = { + PRICE: { + type: 1, + name: '满减' + }, + PERCENT: { + type: 2, + name: '折扣' + } +} + +/** + * 优惠劵模板的有限期类型的枚举 + */ +export const CouponTemplateValidityTypeEnum = { + DATE: { + type: 1, + name: '固定日期可用' + }, + TERM: { + type: 2, + name: '领取之后可用' + } +} + +/** + * 营销的商品范围枚举 + */ +export const PromotionProductScopeEnum = { + ALL: { + scope: 1, + name: '通用劵' + }, + SPU: { + scope: 2, + name: '商品劵' + }, + CATEGORY: { + scope: 3, + name: '品类劵' + } +} + + +// 时间段的状态枚举 +export const TimeStatusEnum = { + WAIT_START: '即将开始', + STARTED: '进行中', + END: '已结束', +} + +export const getTimeStatusEnum = (startTime, endTime) => { + const now = dayjs(); + if (now.isBefore(startTime)) { + return TimeStatusEnum.WAIT_START; + } else if (now.isAfter(endTime)) { + return TimeStatusEnum.END; + } else { + return TimeStatusEnum.STARTED; + } +} diff --git a/yudao-mall-uniapp-master/sheep/util/index.js b/yudao-mall-uniapp-master/sheep/util/index.js new file mode 100644 index 0000000..9b355e8 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/util/index.js @@ -0,0 +1,115 @@ +import dayjs from "dayjs"; + +/** + * 将一个整数转换为分数保留两位小数 + * @param {number | string | undefined} num 整数 + * @return {number} 分数 + */ +export const formatToFraction = (num) => { + if (typeof num === 'undefined') return 0 + const parsedNumber = typeof num === 'string' ? parseFloat(num) : num + return parseFloat((parsedNumber / 100).toFixed(2)) +} + +/** + * 将一个数转换为 1.00 这样 + * 数据呈现的时候使用 + * + * @param {number | string | undefined} num 整数 + * @return {string} 分数 + */ +export const floatToFixed2 = (num) => { + let str = '0.00' + if (typeof num === 'undefined') { + return str + } + const f = formatToFraction(num) + const decimalPart = f.toString().split('.')[1] + const len = decimalPart ? decimalPart.length : 0 + switch (len) { + case 0: + str = f.toString() + '.00' + break + case 1: + str = f.toString() + '.0' + break + case 2: + str = f.toString() + break + } + return str +} + +/** + * 将一个分数转换为整数 + * + * @param {number | string | undefined} num 分数 + * @return {number} 整数 + */ +export const convertToInteger = (num) => { + if (typeof num === 'undefined') return 0 + const parsedNumber = typeof num === 'string' ? parseFloat(num) : num + // TODO 分转元后还有小数则四舍五入 + return Math.round(parsedNumber * 100) +} + +/** + * 时间日期转换 + * @param {dayjs.ConfigType} date 当前时间,new Date() 格式 + * @param {string} format 需要转换的时间格式字符串 + * @description format 字符串随意,如 `YYYY-mm、YYYY-mm-dd` + * @description format 季度:"YYYY-mm-dd HH:MM:SS QQQQ" + * @description format 星期:"YYYY-mm-dd HH:MM:SS WWW" + * @description format 几周:"YYYY-mm-dd HH:MM:SS ZZZ" + * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ" + * @returns {string} 返回拼接后的时间字符串 + */ +export function formatDate(date, format) { + // 日期不存在,则返回空 + if (!date) { + return '' + } + // 日期存在,则进行格式化 + if (format === undefined) { + format = 'YYYY-MM-DD HH:mm:ss' + } + return dayjs(date).format(format) +} + +/** + * 构造树型结构数据 + * + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + * @param {*} rootId 根Id 默认 0 + */ +export function handleTree(data, id = 'id', parentId = 'parentId', children = 'children', rootId = 0) { + // 对源数据深度克隆 + const cloneData = JSON.parse(JSON.stringify(data)) + // 循环所有项 + const treeData = cloneData.filter(father => { + let branchArr = cloneData.filter(child => { + //返回每一项的子级数组 + return father[id] === child[parentId] + }); + branchArr.length > 0 ? father.children = branchArr : ''; + //返回第一层 + return father[parentId] === rootId; + }); + return treeData !== '' ? treeData : data; +} + +/** + * 重置分页对象 + * + * TODO 芋艿:需要处理其它页面 + * + * @param pagination 分页对象 + */ +export function resetPagination(pagination) { + pagination.list = []; + pagination.total = 0; + pagination.pageNo = 1; +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/sheep/validate/form.js b/yudao-mall-uniapp-master/sheep/validate/form.js new file mode 100644 index 0000000..07b5725 --- /dev/null +++ b/yudao-mall-uniapp-master/sheep/validate/form.js @@ -0,0 +1,164 @@ +/** + * Validate v1.0.0 通用验证 + * @description 项目中用到的表单验证规则 + */ +import test from '@/sheep/helper/test.js'; + +// 手机号 +export const mobile = { + rules: [ + { + required: true, + errorMessage: '请输入手机号', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!test.mobile(value)) { + callback('手机号码格式不正确'); + } + return true; + }, + }, + ], +}; + +// 密码 +export const password = { + rules: [ + { + required: true, + errorMessage: '请输入密码', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]+\S{5,12}$/.test(value)) { + callback('需包含字母和数字,长度在6-12之间'); + } + return true; + }, + }, + ], +}; + +// 短信验证码 +export const code = { + rules: [ + { + required: true, + errorMessage: '请输入验证码', + }, + ], +}; + +// 真实姓名 +export const realName = { + rules: [ + { + required: true, + errorMessage: '请输入姓名', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!test.chinese(value)) { + callback('请输入汉字'); + } + return true; + }, + }, + ], +}; + +export const taxName = { + rules: [ + { + required: true, + errorMessage: '请输入发票抬头名称', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!test.chinese(value)) { + callback('请输入汉字'); + } + return true; + }, + }, + ], +}; + +// 税号 +export const taxNo = { + rules: [ + { + required: true, + errorMessage: '请输入税号', + }, + ], +}; + +// 开户行 +export const bankName = { + rules: [ + { + required: true, + errorMessage: '请输入开户行', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!test.chinese(value)) { + callback('请输入汉字'); + } + return true; + }, + }, + ], +}; +// 银行卡号 +export const bankCode = { + rules: [ + { + required: true, + errorMessage: '请输入银行卡号', + }, + { + validateFunction: function (rule, value, data, callback) { + if (!test.number(value)) { + callback('请输入正确账号'); + } + return true; + }, + }, + ], +}; + +// 支付宝账号 +export const alipayAccount = { + rules: [ + { + required: true, + errorMessage: '请输入支付宝账号', + }, + { + validateFunction: function (rule, value, data, callback) { + let isEmail = test.email(value); + let isMobile = test.mobile(value); + + if (!isEmail && !isMobile) { + callback('请输入正确账号'); + } + return true; + }, + }, + ], +}; + +export default { + mobile, + alipayAccount, + bankCode, + bankName, + realName, + password, + code, + taxNo, + taxName, +}; diff --git a/yudao-mall-uniapp-master/static/activity-left.png b/yudao-mall-uniapp-master/static/activity-left.png new file mode 100644 index 0000000..62e3b83 Binary files /dev/null and b/yudao-mall-uniapp-master/static/activity-left.png differ diff --git a/yudao-mall-uniapp-master/static/activity-right.png b/yudao-mall-uniapp-master/static/activity-right.png new file mode 100644 index 0000000..e18a96c Binary files /dev/null and b/yudao-mall-uniapp-master/static/activity-right.png differ diff --git a/yudao-mall-uniapp-master/static/cart-empty.png b/yudao-mall-uniapp-master/static/cart-empty.png new file mode 100644 index 0000000..355d182 Binary files /dev/null and b/yudao-mall-uniapp-master/static/cart-empty.png differ diff --git a/yudao-mall-uniapp-master/static/collect-empty.png b/yudao-mall-uniapp-master/static/collect-empty.png new file mode 100644 index 0000000..300bd21 Binary files /dev/null and b/yudao-mall-uniapp-master/static/collect-empty.png differ diff --git a/yudao-mall-uniapp-master/static/comment-empty.png b/yudao-mall-uniapp-master/static/comment-empty.png new file mode 100644 index 0000000..810a3b1 Binary files /dev/null and b/yudao-mall-uniapp-master/static/comment-empty.png differ diff --git a/yudao-mall-uniapp-master/static/coupon-empty.png b/yudao-mall-uniapp-master/static/coupon-empty.png new file mode 100644 index 0000000..9e14d9d Binary files /dev/null and b/yudao-mall-uniapp-master/static/coupon-empty.png differ diff --git a/yudao-mall-uniapp-master/static/data-empty.png b/yudao-mall-uniapp-master/static/data-empty.png new file mode 100644 index 0000000..a682ff7 Binary files /dev/null and b/yudao-mall-uniapp-master/static/data-empty.png differ diff --git a/yudao-mall-uniapp-master/static/goods-empty.png b/yudao-mall-uniapp-master/static/goods-empty.png new file mode 100644 index 0000000..bd42eca Binary files /dev/null and b/yudao-mall-uniapp-master/static/goods-empty.png differ diff --git a/yudao-mall-uniapp-master/static/images/search.png b/yudao-mall-uniapp-master/static/images/search.png new file mode 100644 index 0000000..157be9d Binary files /dev/null and b/yudao-mall-uniapp-master/static/images/search.png differ diff --git a/yudao-mall-uniapp-master/static/images/sort1.png b/yudao-mall-uniapp-master/static/images/sort1.png new file mode 100644 index 0000000..2a88241 Binary files /dev/null and b/yudao-mall-uniapp-master/static/images/sort1.png differ diff --git a/yudao-mall-uniapp-master/static/images/sort2.png b/yudao-mall-uniapp-master/static/images/sort2.png new file mode 100644 index 0000000..74faf73 Binary files /dev/null and b/yudao-mall-uniapp-master/static/images/sort2.png differ diff --git a/yudao-mall-uniapp-master/static/images/sort3.png b/yudao-mall-uniapp-master/static/images/sort3.png new file mode 100644 index 0000000..c3ce7d4 Binary files /dev/null and b/yudao-mall-uniapp-master/static/images/sort3.png differ diff --git a/yudao-mall-uniapp-master/static/internet-empty.png b/yudao-mall-uniapp-master/static/internet-empty.png new file mode 100644 index 0000000..55ac2f6 Binary files /dev/null and b/yudao-mall-uniapp-master/static/internet-empty.png differ diff --git a/yudao-mall-uniapp-master/static/order-empty.png b/yudao-mall-uniapp-master/static/order-empty.png new file mode 100644 index 0000000..a7b46fe Binary files /dev/null and b/yudao-mall-uniapp-master/static/order-empty.png differ diff --git a/yudao-mall-uniapp-master/static/soldout-empty.png b/yudao-mall-uniapp-master/static/soldout-empty.png new file mode 100644 index 0000000..1761466 Binary files /dev/null and b/yudao-mall-uniapp-master/static/soldout-empty.png differ diff --git a/yudao-mall-uniapp-master/uni.scss b/yudao-mall-uniapp-master/uni.scss new file mode 100644 index 0000000..eadc5cd --- /dev/null +++ b/yudao-mall-uniapp-master/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ +@import '@/sheep/scss/_var.scss'; +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#e5e5e5; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/changelog.md b/yudao-mall-uniapp-master/uni_modules/lime-painter/changelog.md new file mode 100644 index 0000000..b988d35 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/changelog.md @@ -0,0 +1,223 @@ +## 1.9.6.5(2024-04-14) +- fix: 修复`nvue`无法生图的问题 +## 1.9.6.4(2024-03-10) +- fix: 修复代理ctx导致H5不能使用ctx.save +## 1.9.6.3(2024-03-08) +- fix: 修复支付宝真机无法使用的问题 +## 1.9.6.2(2024-02-22) +- fix: 修复使用render函数报错的问题 +## 1.9.6.1(2023-12-22) +- fix: 修复字节小程序非2d字体偏移 +- fix: 修复`canvasToTempFilePathSync`会触发两次的问题 +- fix: 修复`parser`图片没有宽度的问题 +## 1.9.6(2023-12-06) +- fix: 修复背景图受padding影响 +- fix: 修复因字节报错改了代理实现导致微信报错 +- 1.9.5.8(2023-11-16) +- fix: 修复margin问题 +- fix: 修复borderWidth问题 +- fix: 修复textBox问题 +- fix: 修复字节开发工具报`could not be cloned.`问题 +## 1.9.5.7(2023-07-27) +- fix: 去掉多余的方法 +- chore: 更新文档,增加自定义字体说明 +## 1.9.5.6(2023-07-21) +- feat: 有限的支持富文本 +- feat: H5和APP 增加 `hidpi` prop,主要用于大尺寸无法生成图片时用 +- fix: 修复 钉钉小程序 缺少 `measureText` 方法 +- chore: 由于微信小程序 pc 端的 canvas 2d 时不时抽风,故不使用canvas 2d +## 1.9.5.5(2023-06-27) +- fix: 修复把`emoji`表情字符拆分成多个字符的情况 +## 1.9.5.4(2023-06-05) +- fix: 修复因`canvasToTempFilePathSync`监听导致重复调用 +## 1.9.5.3(2023-05-23) +- fix: 因isPc错写成了isPC导致小程序PC不能生成图片 +## 1.9.5.2(2023-05-22) +- feat: 删除多余文件 +## 1.9.5.1(2023-05-22) +- fix: 修复 文字行数与`line-clamp`相同但不满一行时也加了省略号的问题 +## 1.9.5(2023-05-14) +- feat: 增加 `text-indent` 和 `calc` 方法 +- feat: 优化 布局时间 +## 1.9.4.4(2023-04-15) +- fix: 修复无法匹配负值 +- fix: 修复 Nvue IOS getImageInfo `useCORS` 为 undefined +## 1.9.4.3(2023-04-01) +- feat: 增加支持文字描边 `text-stroke: '5rpx #fff'` +## 1.9.4.2(2023-03-30) +- fix: 修复 支付宝小程序 isPC 在手机也为true的问题 +- feat: 由 微信开发工具 3060 版 无法获取图片尺寸,现 微信开发工具 3220 版 修复该问题,故还原上一版的获取图片方式。 +## 1.9.4.1(2023-03-28) +- fix: 修复固定高度不正确问题 +## 1.9.4(2023-03-17) +- fix: nvue ios getImageInfo缺少this报错 +- fix: pathType 非2d无效问题 +- fix: 修复 小米9se 可能会存在多次init 导致画面多次放大 +- fix: 修复 border 分开写 width style无效问题 +- fix: 修复 支付宝小程序IOS 再次进入不渲染的问题 +- fix: 修复 支付宝小程序安卓Zindex排序错乱问题 +- fix: 修复 微信开发工具 3060 版 无法获取图片的问题 +- feat: 把 for in 改为 forEach +- feat: 增加 hidden +- feat: 根节点 box-sizing 默认 `border-box` +- feat: 增加支持 `vw` `wh` +- chore: pathType 取消 默认值,因为字节开发工具不能显示 +- chore: 支付宝小程序开发工具不支持 生成图片 请以真机调试为准 +- bug: 企业微信 2.20.3无法使用 +## 1.9.3.5(2022-06-29) +- feat: justifyContent 增加 `space-around`、`space-between` +- feat: canvas 2d 也使用`getImageInfo` +- fix: 修复 `text`的 `text-decoration`错位 +## 1.9.3.4(2022-06-20) +- fix: 修复 因创建节点速度问题导致顺序出错。 +- fix: 修复 微信小程序 PC 无法显示本地图片 +- fix: 修复 flex-box 对齐问题 +- feat: 增加 `text-shadow` +- feat: 重写 `text` 对齐方式 +- chore: 更新文档 +## 1.9.3.3(2022-06-17) +- fix: 修复 支付宝小程序 canvas 2d 存在ctx.draw问题导致报错 +- fix: 修复 支付宝小程序 toDataURL 存在权限问题改用 `toTempFilePath` +- fix: 修复 支付宝小程序 image size 问题导致 `objectFit` 无效 +## 1.9.3.2(2022-06-14) +- fix: 修复 image 设置背景色不生效问题 +- fix: 修复 nvue 环境判断缺少参数问题 +## 1.9.3.1(2022-06-14) +- fix: 修复 bottom 定位不对问题 +- fix: 修复 因小数导致计算出错换行问题 +- feat: 增加 `useCORS` h5端图片跨域 在设置请求头无效果后试一下设置这个值 +- chore: 更新文档 +## 1.9.3(2022-06-13) +- feat: 增加 `zIndex` +- feat: 增加 `flex-box` 该功能处于原始阶段,非常简陋。 +- tips: QQ小程序 vue3 不支持, 为 uni 官方BUG +## 1.9.2.9(2022-06-10) +- fix: 修复`text-align`及`margin`居中问题 +## 1.9.2.8(2022-06-10) +- fix: 修复 Nvue `canvasToTempFilePathSync` 不生效问题 +## 1.9.2.7(2022-06-10) +- fix: 修复 margin及padding的bug +- fix: 修复 Nvue `isCanvasToTempFilePath` 不生效问题 +## 1.9.2.6(2022-06-09) +- fix: 修复 Nvue 不显示 +- feat: 增加支持字体渐变 +```html + +``` +## 1.9.2.5(2022-06-09) +- chore: 更变获取父级宽度的设定 +- chore: `pathType` 在canvas 2d 默认为 `url` +## 1.9.2.4(2022-06-08) +- fix: 修复 `pathType` 不生效问题 +## 1.9.2.3(2022-06-08) +- fix: 修复 `canvasToTempFilePath` 漏写 `success` 参数 +## 1.9.2.2(2022-06-07) +- chore: 更新文档 +## 1.9.2.1(2022-06-07) +- fix: 修复 vue3 赋值给this再传入导致image无法绘制 +- fix: 修复 `canvasToTempFilePathSync` 时机问题 +- feat: canvas 2d 更改图片生成方式 `toDataURL` +## 1.9.2(2022-05-30) +- fix: 修复 `canvasToTempFilePathSync` 在 vue3 下只生成一次 +## 1.9.1.7(2022-05-28) +- fix: 修复 `qrcode`显示不全问题 +## 1.9.1.6(2022-05-28) +- fix: 修复 `canvasToTempFilePathSync` 会重复多次问题 +- fix: 修复 `view` css `backgroundImage` 图片下载失败导致 子节点不渲染 +## 1.9.1.5(2022-05-27) +- fix: 修正支付宝小程序 canvas 2d版本号 2.7.15 +## 1.9.1.4(2022-05-22) +- fix: 修复字节小程序无法使用xml方式 +- fix: 修复字节小程序无法使用base64(非2D情况下工具上无法显示) +- fix: 修复支付宝小程序 `canvasToTempFilePath` 报错 +## 1.9.1.3(2022-04-29) +- fix: 修复vue3打包后uni对象为空后的报错 +## 1.9.1.2(2022-04-25) +- fix: 删除多余文件 +## 1.9.1.1(2022-04-25) +- fix: 修复图片不显示问题 +## 1.9.1(2022-04-12) +- fix: 因四舍五入导致有些机型错位 +- fix: 修复无views报错 +- chore: nvue下因ios无法读取插件内static文件,改由下载方式 +## 1.9.0(2022-03-20) +- fix: 因无法固定尺寸导致生成图片不全 +- fix: 特定情况下text判断无效 +- chore: 本地化APP Nvue webview +## 1.8.9(2022-02-20) +- fix: 修复 小程序下载最多10次并发的问题 +- fix: 修复 APP端无法获取本地图片 +- fix: 修复 APP Nvue端不执行问题 +- chore: 增加图片缓存机制 +## 1.8.8.8(2022-01-27) +- fix: 修复 主动调用尺寸问题 +## 1.8.8.6(2022-01-26) +- fix: 修复 nvue 下无宽度时获取父级宽度 +- fix: 修复 ios app 无法渲染问题 +## 1.8.8(2022-01-23) +- fix: 修复 主动调用时无节点问题 +- fix: 修复 `box-shadow` 颜色问题 +- fix: 修复 `transform:rotate` 角度位置问题 +- feat: 增加 `overflow:hidden` +## 1.8.7(2022-01-07) +- fix: 修复 image 方向为 `right` 时原始宽高问题 +- feat: 支持 view 设置背景图 `background-image: url(xxx)` +- chore: 去掉可选链 +## 1.8.6(2021-11-28) +- feat: 支持`view`对`inline-block`的子集使用`text-align` +## 1.8.5.5(2021-08-17) +- chore: 更新文档,删除 replace +- fix: 修复 text 值为 number时报错 +## 1.8.5.4(2021-08-16) +- fix: 字节小程序兼容 +## 1.8.5.3(2021-08-15) +- fix: 修复线性渐变与css现实效果不一致的问题 +- chore: 更新文档 +## 1.8.5.2(2021-08-13) +- chore: 增加`background-image`、`background-repeat` 能力,主要用于背景纹理的绘制,并不是代替`image`。例如:大面积的重复平铺的水印 +- 注意:这个功能H5暂时无法使用,因为[官方的API有BUG](https://ask.dcloud.net.cn/question/128793),待官方修复!!! +## 1.8.5.1(2021-08-10) +- fix: 修复因`margin`报错问题 +## 1.8.5(2021-08-09) +- chore: 增加margin支持`auto`,以达到居中效果 +## 1.8.4(2021-08-06) +- chore: 增加判断缓存文件条件 +- fix: 修复css 多余空格报错问题 +## 1.8.3(2021-08-04) +- tips: 1.6.x 以下的版本升级到1.8.x后要为每个元素都加上定位:position: 'absolute' +- fix: 修复只有一个view子元素时不计算高度的问题 +## 1.8.2(2021-08-03) +- fix: 修复 path-type 为 `url` 无效问题 +- fix: 修复 qrcode `text` 为空时报错问题 +- fix: 修复 image `src` 动态设置时不生效问题 +- feat: 增加 css 属性 `min-width` `max-width` +## 1.8.1(2021-08-02) +- fix: 修复无法加载本地图片 +## 1.8.0(2021-08-02) +- chore 文档更新 +- 使用旧版的同学不要升级! +## 1.8.0-beta(2021-07-30) +- ## 全新布局方式 不兼容旧版! +- chore: 布局方式变更 +- tips: 微信canvas 2d 不支持真机调试 +## 1.6.6(2021-07-09) +- chore: 统一命名规范,无须主动引入组件 +## 1.6.5(2021-06-08) +- chore: 去掉console +## 1.6.4(2021-06-07) +- fix: 修复 数字 为纯字符串时不转换的BUG +## 1.6.3(2021-06-06) +- fix: 修复 PC 端放大的BUG +## 1.6.2(2021-05-31) +- fix: 修复 报`adaptor is not a function`错误 +- fix: 修复 text 多行高度 +- fix: 优化 默认文字的基准线 +- feat: `@progress`事件,监听绘制进度 +## 1.6.1(2021-02-28) +- 删除多余节点 +## 1.6.0(2021-02-26) +- 调整为uni_modules目录规范 +- 修复:transform的rotate不能为负数问题 +- 新增:`pathType` 指定生成图片返回的路径类型,可选值有 `base64`、`url` diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/common/relation.js b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/common/relation.js new file mode 100644 index 0000000..6ed37e8 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/common/relation.js @@ -0,0 +1,150 @@ +const styles = (v ='') => v.split(';').filter(v => v && !/^[\n\s]+$/.test(v)).map(v => { + const key = v.slice(0, v.indexOf(':')) + const value = v.slice(v.indexOf(':')+1) + return { + [key + .replace(/-([a-z])/g, function() { return arguments[1].toUpperCase()}) + .replace(/\s+/g, '') + ]: value.replace(/^\s+/, '').replace(/\s+$/, '') || '' + } + }) +export function parent(parent) { + return { + provide() { + return { + [parent]: this + } + }, + data() { + return { + el: { + id: null, + css: {}, + views: [] + }, + } + }, + watch: { + css: { + handler(v) { + if(this.canvasId) { + this.el.css = (typeof v == 'object' ? v : v && Object.assign(...styles(v))) || {} + this.canvasWidth = this.el.css && this.el.css.width || this.canvasWidth + this.canvasHeight = this.el.css && this.el.css.height || this.canvasHeight + } + }, + immediate: true + } + } + } +} +export function children(parent, options = {}) { + const indexKey = options.indexKey || 'index' + return { + inject: { + [parent]: { + default: null + } + }, + watch: { + el: { + handler(v, o) { + if(JSON.stringify(v) != JSON.stringify(o)) + this.bindRelation() + }, + deep: true, + immediate: true + }, + src: { + handler(v, o) { + if(v != o) + this.bindRelation() + }, + immediate: true + }, + text: { + handler(v, o) { + if(v != o) this.bindRelation() + }, + immediate: true + }, + css: { + handler(v, o) { + if(v != o) + this.el.css = (typeof v == 'object' ? v : v && Object.assign(...styles(v))) || {} + }, + immediate: true + }, + replace: { + handler(v, o) { + if(JSON.stringify(v) != JSON.stringify(o)) + this.bindRelation() + }, + deep: true, + immediate: true + } + }, + created() { + if(!this._uid) { + this._uid = this._.uid + } + Object.defineProperty(this, 'parent', { + get: () => this[parent] || [], + }) + Object.defineProperty(this, 'index', { + get: () => { + this.bindRelation(); + const {parent: {el: {views=[]}={}}={}} = this + return views.indexOf(this.el) + }, + }); + this.el.type = this.type + if(this.uid) { + this.el.uid = this.uid + } + this.bindRelation() + }, + // #ifdef VUE3 + beforeUnmount() { + this.removeEl() + }, + // #endif + // #ifdef VUE2 + beforeDestroy() { + this.removeEl() + }, + // #endif + methods: { + removeEl() { + if (this.parent) { + this.parent.el.views = this.parent.el.views.filter( + (item) => item._uid !== this._uid + ); + } + }, + bindRelation() { + if(!this.el._uid) { + this.el._uid = this._uid + } + if(['text','qrcode'].includes(this.type)) { + this.el.text = this.$slots && this.$slots.default && this.$slots.default[0].text || `${this.text || ''}`.replace(/\\n/g, '\n') + } + if(this.type == 'image') { + this.el.src = this.src + } + if (!this.parent) { + return; + } + let views = this.parent.el.views || []; + if(views.indexOf(this.el) !== -1) { + this.parent.el.views = views.map(v => v._uid == this._uid ? this.el : v) + } else { + this.parent.el.views = [...views, this.el]; + } + } + }, + mounted() { + // this.bindRelation() + }, + } +} \ No newline at end of file diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-image/l-painter-image.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-image/l-painter-image.vue new file mode 100644 index 0000000..e24e3aa --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-image/l-painter-image.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue new file mode 100644 index 0000000..a73e5ed --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-text/l-painter-text.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-text/l-painter-text.vue new file mode 100644 index 0000000..b332b02 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-text/l-painter-text.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-view/l-painter-view.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-view/l-painter-view.vue new file mode 100644 index 0000000..94596e5 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter-view/l-painter-view.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/l-painter.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/l-painter.vue new file mode 100644 index 0000000..83926fd --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/l-painter.vue @@ -0,0 +1,461 @@ + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/nvue.js b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/nvue.js new file mode 100644 index 0000000..25645fb --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/nvue.js @@ -0,0 +1,214 @@ +// #ifdef APP-NVUE +import { + sleep, + getImageInfo, + isBase64, + networkReg +} from './utils'; +const dom = weex.requireModule('dom') +import { + version +} from '../../package.json' + +export default { + data() { + return { + tempFilePath: [], + isInitFile: false, + osName: uni.getSystemInfoSync().osName + } + }, + methods: { + getParentWeith() { + return new Promise(resolve => { + dom.getComponentRect(this.$refs.limepainter, (res) => { + this.parentWidth = Math.ceil(res.size.width) + this.canvasWidth = this.canvasWidth || this.parentWidth || 300 + this.canvasHeight = res.size.height || this.canvasHeight || 150 + resolve(res.size) + }) + }) + }, + onPageFinish() { + this.webview = this.$refs.webview + this.webview.evalJS(`init(${this.dpr})`) + }, + onMessage(e) { + const res = e.detail.data[0] || null; + if (res.event) { + if (res.event == 'inited') { + this.inited = true + } + if (res.event == 'fail') { + this.$emit('fail', res) + } + if (res.event == 'layoutChange') { + const data = typeof res.data == 'string' ? JSON.parse(res.data) : res.data + this.canvasWidth = Math.ceil(data.width); + this.canvasHeight = Math.ceil(data.height); + } + if (res.event == 'progressChange') { + this.progress = res.data * 1 + } + if (res.event == 'file') { + this.tempFilePath.push(res.data) + if (this.tempFilePath.length > 7) { + this.tempFilePath.shift() + } + return + } + if (res.event == 'success') { + if (res.data) { + this.tempFilePath.push(res.data) + if (this.tempFilePath.length > 8) { + this.tempFilePath.shift() + } + if (this.isCanvasToTempFilePath) { + this.setFilePath(this.tempFilePath.join(''), { + isEmit: true + }) + } + } else { + this.$emit('fail', 'canvas no data') + } + return + } + this.$emit(res.event, JSON.parse(res.data)); + } else if (res.file) { + this.file = res.data; + } else { + console.info(res[0]) + } + }, + getWebViewInited() { + if (this.inited) return Promise.resolve(this.inited); + return new Promise((resolve) => { + this.$watch( + 'inited', + async val => { + if (val) { + resolve(val) + } + }, { + immediate: true + } + ); + }) + }, + getTempFilePath() { + if (this.tempFilePath.length == 8) return Promise.resolve(this.tempFilePath) + return new Promise((resolve) => { + this.$watch( + 'tempFilePath', + async val => { + if (val.length == 8) { + resolve(val.join('')) + } + }, { + deep: true + } + ); + }) + }, + getWebViewDone() { + if (this.progress == 1) return Promise.resolve(this.progress); + return new Promise((resolve) => { + this.$watch( + 'progress', + async val => { + if (val == 1) { + this.$emit('done') + this.done = true + this.runTask() + resolve(val) + } + }, { + immediate: true + } + ); + }) + }, + async render(args) { + try { + await this.getSize(args) + const { + width + } = args.css || args + if (!width && this.parentWidth) { + Object.assign(args, { + width: this.parentWidth + }) + } + const newNode = await this.calcImage(args); + await this.getWebViewInited() + this.webview.evalJS(`source(${JSON.stringify(newNode)})`) + await this.getWebViewDone() + await sleep(this.afterDelay) + if (this.isCanvasToTempFilePath) { + const params = { + fileType: this.fileType, + quality: this.quality + } + this.webview.evalJS(`save(${JSON.stringify(params)})`) + } + return Promise.resolve() + } catch (e) { + this.$emit('fail', e) + } + }, + async calcImage(args) { + let node = JSON.parse(JSON.stringify(args)) + const urlReg = /url\((.+)\)/ + const { + backgroundImage + } = node.css || {} + const isBG = backgroundImage && urlReg.exec(backgroundImage)[1] + const url = node.url || node.src || isBG + if (['text', 'qrcode'].includes(node.type)) { + return node + } + if ((node.type === "image" || isBG) && url && !isBase64(url) && (this.osName == 'ios' || !networkReg + .test(url))) { + let { + path + } = await getImageInfo(url, true) + if (isBG) { + node.css.backgroundImage = `url(${path})` + } else { + node.src = path + } + } else if (node.views && node.views.length) { + for (let i = 0; i < node.views.length; i++) { + node.views[i] = await this.calcImage(node.views[i]) + } + } + return node + }, + async canvasToTempFilePath(args = {}) { + if (!this.inited) { + return this.$emit('fail', 'no init') + } + this.tempFilePath = [] + if (args.fileType == 'jpg') { + args.fileType = 'jpeg' + } + + this.webview.evalJS(`save(${JSON.stringify(args)})`) + try { + let tempFilePath = await this.getTempFilePath() + + tempFilePath = await this.setFilePath(tempFilePath, args) + args.success({ + errMsg: "canvasToTempFilePath:ok", + tempFilePath + }) + } catch (e) { + console.log('e', e) + args.fail({ + error: e + }) + } + } + } +} +// #endif \ No newline at end of file diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/painter.js b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/painter.js new file mode 100644 index 0000000..bd42fc9 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/l-painter/painter.js @@ -0,0 +1 @@ +var t=function(){return t=Object.assign||function(t){for(var e,i=1,n=arguments.length;i0&&r[r.length-1])||6!==o[0]&&2!==o[0])){s=0;continue}if(3===o[0]&&(!r||o[1]>r[0]&&o[1]=360&&(s-=360);s<0&&(s+=360);if(0===(s=Math.round(s)))return{x0:Math.round(e/2)+n,y0:i+r,x1:Math.round(e/2)+n,y1:r};if(180===s)return{x0:Math.round(e/2)+n,y0:r,x1:Math.round(e/2)+n,y1:i+r};if(90===s)return{x0:n,y0:Math.round(i/2)+r,x1:e+n,y1:Math.round(i/2)+r};if(270===s)return{x0:e+n,y0:Math.round(i/2)+r,x1:n,y1:Math.round(i/2)+r};var a=Math.round(180*Math.asin(e/Math.sqrt(Math.pow(e,2)+Math.pow(i,2)))/Math.PI);if(s===a)return{x0:n,y0:i+r,x1:e+n,y1:r};if(s===180-a)return{x0:n,y0:r,x1:e+n,y1:i+r};if(s===180+a)return{x0:e+n,y0:r,x1:n,y1:i+r};if(s===360-a)return{x0:e+n,y0:i+r,x1:n,y1:r};var h=0,c=0,f=0,l=0;if(s180-a&&s<180||s>180&&s<180+a||s>360-a){var d=s*Math.PI/180,u=s360-a?i/2:-i/2,p=Math.tan(d)*u,g=s180-a&&s<180?e/2-p:-e/2-p;h=-(f=p+(v=Math.pow(Math.sin(d),2)*g)),c=-(l=u+v/Math.tan(d))}if(s>a&&s<90||s>90&&s<90+a||s>180+a&&s<270||s>270&&s<360-a){var v;d=(90-s)*Math.PI/180,p=s>a&&s<90||s>90&&s<90+a?e/2:-e/2,u=Math.tan(d)*p,g=s>a&&s<90||s>270&&s<360-a?i/2-u:-i/2-u;h=-(f=p+(v=Math.pow(Math.sin(d),2)*g)/Math.tan(d)),c=-(l=u+v)}return h=Math.round(h+e/2)+n,c=Math.round(i/2-c)+r,f=Math.round(f+e/2)+n,l=Math.round(i/2-l)+r,{x0:h,y0:c,x1:f,y1:l}}(r,t,e,i,n),a=s.x0,h=s.y0,c=s.x1,f=s.y1,l=o.createLinearGradient(a,h,c,f),d=r.match(/linear-gradient\((.+)\)/)[1],u=L(d.substring(d.indexOf(",")+1)),p=0;pt.length)&&(e=t.length);for(var i=0,n=new Array(e);i=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function C(t){return"number"==typeof t}function H(t){return"auto"===t||null===t}function D(t){return/%$/.test(t)}var Y=p,$=u,U=d,N=g,X=y,_=w,q=m;function G(t){return t.replace(/-([a-z])/g,(function(t,e){return e.toUpperCase()}))}function V(t,e){var i,n,o=function(t){var e=t.match(/([a-z]+)/)[1];return[e,G(t.split(e)[1])]}(t),s=o[0],a=o[1],h=e.split(" ");if(a)return(i={})[s+a]=e,i;if(h.length&&!a){var c=h[0],f=h[1],l=h[2],d=h[3];return(n={})[s+r[0]]=c,n[s+r[1]]=f||c,n[s+r[2]]=l||c,n[s+r[3]]=d||f||c,n}}function J(t){t=t.trim();for(var e=new Array,i="+",n="",r=t.length,o=0;o0;)"("===t[a+=1]&&(s+=1),")"===t[a]&&(s-=1);n="".concat(J(t.slice(o+1,a))),o=a}if(isNaN(Number(t[o]))&&"."!==t[o]||o===r-1){var h=parseFloat(n);switch(i){case"+":e.push(h);break;case"-":e.push(-h);break;case"*":e.push(e.pop()*h);break;case"/":e.push(e.pop()/h)}i=t[o],n=""}}for(var c=0;e.length;)c+=e.pop();return c}var Q,Z=0,K=function(){function t(){R(this,"elements",[]),R(this,"afterElements",[]),R(this,"beforeElements",[]),R(this,"ids",[]),R(this,"width",0),R(this,"height",0),R(this,"top",0),R(this,"left",0),R(this,"pre",null),R(this,"offsetX",0),R(this,"offsetY",0),Z++,this.id=Z}var e=t.prototype;return e.fixedBind=function(t,e){void 0===e&&(e=0),this.container=e?t.parent:t.root,this.container.fixedLine=this,this.fixedAdd(t)},e.fixedAdd=function(t){if(!this.ids.includes(t.id)){this.ids.push(t.id),this.elements.push(t);var e=t.computedStyle.zIndex;(void 0===e?0:e)>=0?this.afterElements.push(t):this.beforeElements.push(t),this.refreshLayout()}},e.bind=function(t){this.container=t.parent,this.container.line=null,this.container.lines?(this.container.lines.push(this),this.pre=this.getPreLine(),this.top=this.pre.top+this.pre.height,this.left=this.container.contentSize.left):(this.top=this.container.contentSize.top,this.left=this.container.contentSize.left,this.container.lines=[this]),this.isInline=t.isInline(),this.container.line=this,this.outerWidth=t.parent&&t.parent.contentSize.width?t.parent.contentSize.width:1/0,this.add(t)},e.getPreLine=function(){return this.container.lines[this.container.lines.length-2]},e.canIEnter=function(t){return!((100*t.offsetSize.width+100*this.width)/100>this.outerWidth)||(this.closeLine(),!1)},e.closeLine=function(){delete this.container.line},e.add=function(t){this.ids.includes(t.id)||(this.ids.push(t.id),this.elements.push(t),this.refreshWidthHeight(t))},e.refreshWidthHeight=function(t){t.offsetSize.height>this.height&&(this.height=t.offsetSize.height),this.width+=t.offsetSize.width||0,(this.container.lineMaxWidth||0)this[this.key.height]&&(this.container[this.key.lineMaxHeight]=this[this.key.height]=i),this[this.key.width]+=this.getWidth(t.offsetSize);var n=Math.min(this.getWidth(this),!this.getWidth(this.container.contentSize)&&1/0);(this.container[this.key.lineMaxWidth]||0)1)return 0;var e=t.style.alignSelf,i=this.getHeight(this.container.contentSize),n=i-this.getHeight(t.offsetSize);return"flex-end"===e?n:"center"===e?n/2:"stretch"===e?(n&&t.name==d&&(t.style[this.key.width]=this.getWidth(t.offsetSize),t.style[this.key.height]=i,delete t.line,delete t.lines,t.getBoxWidthHeight()),0):0},r.layout=function(t,e){var i=this;this.refreshXAlign(),this.pre?(this.top=this.pre.top+this.pre.height+this.offsetY,this.left=e+this.offsetX):(this.top=Math.max(this.top,this.container.contentSize.top,t)+this.offsetY,this.left=Math.max(this.left,this.container.contentSize.left,e)+this.offsetX),this.elements.forEach((function(t,e){i.setIndent(t);var n=i.elements[e-1],r=i.getOffsetY(t);t.style[i.key.top]=i[i.key.top]+r,t.style[i.key.left]=n?n.offsetSize[i.key.left]+i.getWidth(n.offsetSize):i[i.key.left],t.getBoxPosition()}))},n}(K),nt=p,rt=u,ot=d,st=v,at=y,ht=b,ct=w,ft=m,lt=0,dt={left:null,top:null,width:null,height:null},ut=new Map,pt=function(){function t(t,e,i,n){var o=this;R(this,"id",lt++),R(this,"style",{left:null,top:null,width:null,height:null}),R(this,"computedStyle",{}),R(this,"originStyle",{}),R(this,"children",{}),R(this,"layoutBox",F({},dt)),R(this,"contentSize",F({},dt)),R(this,"clientSize",F({},dt)),R(this,"borderSize",F({},dt)),R(this,"offsetSize",F({},dt)),this.ctx=n,this.root=i,e&&(this.parent=e),this.name=t.type||t.name,this.attributes=this.getAttributes(t);var s=function(t,e){var i,n=["color","fontSize","lineHeight","verticalAlign","fontWeight","textAlign"],o=t.type,s=void 0===o?U:o,a=t.styles,h=void 0===a?{}:a,c=(e||{}).computedStyle,f=Object.assign({},S);if([$,Y,N].includes(s)&&!h.display&&(f.display=X),c)for(var l=0;l=0&&l<0,Y=c>=0&&u<0;return i==a[0]&&(this[i].left=t.left+s+v+E+(D?2*-l:0),this[i].top=t.top+c+x+W+(Y?2*-u:0),this[i].width=t.width+(this[i].widthAdd?0:C),this[i].height=t.height+(this[i].heightAdd?0:H),this[i].widthAdd=C,this[i].heightAdd=H),i==a[1]&&(this[i].left=t.left+s+E+(D<0?-l:0),this[i].top=t.top+c+W+(Y?-u:0),this[i].width=t.width+v+w,this[i].height=t.height+x+S),i==a[2]&&(this[i].left=t.left+s+E/2+(D<0?-l:0),this[i].top=t.top+c+W/2+(Y?-u:0),this[i].width=t.width+v+w+E/2+F/2,this[i].height=t.height+x+S+T/2+W/2),i==a[3]&&(this[i].left=t.left+(D<0?-l:0),this[i].top=t.top+(Y?-u:0),this[i].width=t.width+v+w+E+F+s+l,this[i].height=t.height+x+S+T+W+u+c),this[i]},e.layoutBoxUpdate=function(t,e,i,n){var r=this;if(void 0===i&&(i=-1),"border-box"==e.boxSizing){var o=e||{},s=o.border,h=(s=void 0===s?{}:s).borderWidth,c=void 0===h?0:h,f=o.borderTop,l=(f=void 0===f?{}:f).borderTopWidth,d=void 0===l?c:l,u=o.borderBottom,p=(u=void 0===u?{}:u).borderBottomWidth,g=void 0===p?c:p,v=o.borderRight,y=(v=void 0===v?{}:v).borderRightWidth,x=void 0===y?c:y,b=o.borderLeft,w=(b=void 0===b?{}:b).borderLeftWidth,m=void 0===w?c:w,S=o.padding,z=(S=void 0===S?{}:S).paddingTop,I=void 0===z?0:z,M=S.paddingRight,k=void 0===M?0:M,B=S.paddingBottom,W=void 0===B?0:B,P=S.paddingLeft,O=void 0===P?0:P;i||(t.width-=O+k+x+m),1!==i||n||(t.height-=I+W+d+g)}this.layoutBox&&(a.forEach((function(i){return r.layoutBox[i]=r.getOffsetSize(t,e,i)})),this.layoutBox=Object.assign({},this.layoutBox,this.layoutBox.borderSize))},e.getBoxPosition=function(){var t=this.computedStyle,e=this.fixedLine,i=this.lines,n=t.left,r=void 0===n?0:n,o=t.top,s=void 0===o?0:o,a=F({},this.contentSize,{left:r,top:s}),h=this.contentSize.top-this.offsetSize.top,c=this.contentSize.left-this.offsetSize.left;if(this.root.fixedLine&&!this.root.isDone){this.root.isDone=!0;for(var f,l=E(this.root.fixedLine.elements);!(f=l()).done;){var d=f.value;d.setPosition(d,this.root.offsetSize),d.getBoxPosition()}}if(e)for(var u,p=E(e.elements);!(u=p()).done;){var g=u.value,v=F({},this.borderSize,{left:r,top:s});g.setPosition(g,v);var y=this.borderSize.top-this.offsetSize.top,x=this.borderSize.left-this.offsetSize.left;g.style.left+=r+x,g.style.top+=s+y,g.getBoxPosition()}if(i)for(var b,w=E(i);!(b=w()).done;){b.value.layout(a.top+h,a.left+c)}return this.layoutBoxUpdate(a,t),this.layoutBox},e.getBoxState=function(t,e){return this.isBlock(t)||this.isBlock(e)},e.isBlock=function(t){return void 0===t&&(t=this),t&&t.style.display==st},e.isFlex=function(t){return void 0===t&&(t=this),t&&t.style.display==ht},e.isInFlow=function(){return!(this.isAbsolute||this.isFixed)},e.inFlexBox=function(t){return void 0===t&&(t=this),!!t.isInFlow()&&(!!t.parent&&(!(!t.parent||t.parent.style.display!==ht)||void 0))},e.isInline=function(t){return void 0===t&&(t=this),t&&t.style.display==at},e.contrastSize=function(t,e,i){var n=t;return i&&(n=Math.min(n,i)),e&&(n=Math.max(n,e)),n},e.measureText=function(t,e){var i=this.ctx.measureText(t),n=i.width,r=i.actualBoundingBoxAscent,o=i.actualBoundingBoxDescent;return{ascent:r,descent:o,width:n,fontHeight:r+o||.7*e+1}},e.getParentSize=function(t,e){if(void 0===t&&(t=this),void 0===e&&(e=!1),t&&t.parent){if(t.parent.contentSize.width)return t.parent.contentSize;if(e)return this.getParentSize(t.parent,e)}return null},e.getBoxWidthHeight=function(){var t=this,e=this.name,i=this.computedStyle,n=this.attributes,r=this.parent,o=void 0===r?{}:r,s=this.ctx,a=this.getChildren(),h=i.left,c=void 0===h?0:h,f=i.top,l=void 0===f?0:f,d=i.bottom,u=i.right,p=i.width,g=void 0===p?0:p,v=i.minWidth,y=i.maxWidth,x=i.minHeight,b=i.maxHeight,w=i.height,m=void 0===w?0:w,S=i.fontSize,z=i.fontWeight,I=i.fontFamily,M=i.fontStyle,k=i.position;i.textIndent;var B=i.lineClamp,P=i.lineHeight,O=i.padding,T=void 0===O?{}:O,L=i.margin,R=void 0===L?{}:L,F=i.border,A=(F=void 0===F?{}:F).borderWidth,j=void 0===A?0:A,E=i.borderRight,C=(E=void 0===E?{}:E).borderRightWidth,Y=void 0===C?j:C,$=i.borderLeft,U=($=void 0===$?{}:$).borderLeftWidth,N=void 0===U?j:U,X=o.contentSize&&o.contentSize.width,_=o.contentSize&&o.contentSize.height;if(D(g)&&X&&(g=W(g,X)),D(g)&&!X&&(g=null),D(m)&&_&&(m=W(m,_)),D(m)&&!_&&(m=null),D(v)&&X&&(v=W(v,X)),D(y)&&X&&(y=W(y,X)),D(x)&&_&&(x=W(x,_)),D(b)&&_&&(b=W(b,_)),i.padding&&X)for(var q in i.padding)Object.hasOwnProperty.call(T,q)&&(T[q]=W(T[q],X));var G=T.paddingRight,V=void 0===G?0:G,J=T.paddingLeft,Q=void 0===J?0:J;if(i.margin&&[R.marginLeft,R.marginRight].includes("auto"))if(g){var Z=X&&X-g-V-Q-N-Y||0;R.marginLeft==R.marginRight?R.marginLeft=R.marginRight=Z/2:H(R.marginLeft)?R.marginLeft=Z:R.marginRight=Z}else R.marginLeft=R.marginRight=0;var tt=R.marginRight,et=void 0===tt?0:tt,st=R.marginLeft,at={width:g,height:m,left:0,top:0},ht=Q+V+N+Y+(void 0===st?0:st)+et;if(this.offsetWidth=ht,e==rt&&!this.attributes.widths){var ft=n.text||"";s.save(),s.setFonts({fontFamily:I,fontSize:S,fontWeight:z,fontStyle:M}),ft.length,"\n"==ft&&(ft="",this.isBr=!0),(""+ft).split("\n").map((function(e){var i=Array.from(e).map((function(e){var i=""+(/^[\u4e00-\u9fa5]+$/.test(e)?"cn":e)+I+S+z+M,n=ut.get(i);if(n)return{width:n,text:e};var r=t.measureText(e,S).width;return ut.set(i,r),{width:r,text:e}})),n=t.measureText(e,S),r=n.fontHeight,o=n.ascent,s=n.descent;t.attributes.fontHeight=r,t.attributes.ascent=o,t.attributes.descent=s,t.attributes.widths||(t.attributes.widths=[]),t.attributes.widths.push({widths:i,total:i.reduce((function(t,e){return t+e.width}),0)})})),s.restore()}if(e==nt&&null==g){var lt=n.width,dt=n.height;at.width=this.contrastSize(Math.round(lt*m/dt)||0,v,y),this.layoutBoxUpdate(at,i,0)}if(e==rt&&null==g){var pt=this.attributes.widths,gt=Math.max.apply(Math,pt.map((function(t){return t.total})));if(o&&X>0&&(gt>X||this.isBlock(this))&&!this.isAbsolute&&!this.isFixed)gt=X;at.width=this.contrastSize(gt,v,y),this.layoutBoxUpdate(at,i,0)}if(e==rt&&(o.style.flex||!this.attributes.lines)){var vt=this.attributes.widths.length;this.attributes.widths.forEach((function(t){return t.widths.reduce((function(t,e,i){return t+e.width>at.width?(vt++,e.width):t+e.width}),0)})),vt=B&&vt>B?B:vt,this.attributes.lines=vt}if(e==nt&&null==m){var yt=n.width,xt=n.height;n.text,at.height=this.contrastSize(W(at.width*xt/yt)||0,x,b),this.layoutBoxUpdate(at,i,1)}e==rt&&null==m&&(P=W(P,S),at.height=this.contrastSize(W(this.attributes.lines*P),x,b),this.layoutBoxUpdate(at,i,1,!0)),!g&&o&&o.children&&X&&(!this.isFlex(o)||o.isFlexCalc)&&([ot,rt].includes(e)&&this.isFlex()||e==ot&&this.isBlock(this)&&this.isInFlow())&&(at.width=this.contrastSize(X-(o.isFlexCalc?0:ht),v,y),this.layoutBoxUpdate(at,i)),g&&!D(g)&&(at.width=this.contrastSize(g,v,y),this.layoutBoxUpdate(at,i,0)),m&&!D(m)&&(at.height=this.contrastSize(at.height,x,b),this.layoutBoxUpdate(at,i,1));var bt=0;if(a.length){var wt=null,mt=!1;a.forEach((function(e,n){e.getBoxWidthHeight();var r=a[n+1];if(r&&r.isInFlow()&&(e.next=r),!t.line||!t.line.ids.includes(e.id))if(e.isInFlow()&&!e.inFlexBox()){var o=t.getBoxState(wt,e);if(e.isBr)return mt=!0;t.line&&t.line.canIEnter(e)&&!o&&!mt?t.line.add(e):(mt=!1,(new K).bind(e)),wt=e}else e.inFlexBox()?t.line&&(t.line.canIEnter(e)||"nowrap"==i.flexWrap)?t.line.add(e):(new it).bind(e):e.isFixed?t.root.fixedLine?t.root.fixedLine.fixedAdd(e):(new K).fixedBind(e):t.fixedLine?t.fixedLine.fixedAdd(e):(new K).fixedBind(e,1)})),this.lines&&(bt=this.lines.reduce((function(t,e){return t+e.height}),0))}var St=0,zt=0;if(!g&&(this.isAbsolute||this.isFixed)&&X){var It=k==ct?X:this.root.width,Mt=It-(D(c)?W(c,It):c)-(D(u)?W(u,It):u);St=i.left?Mt:this.lineMaxWidth}if(!m&&(null!=l?l:this.isAbsolute||this.isFixed&&_)){var kt=k==ct?_:this.root.height,Bt=kt-(D(l)?W(l,kt):l)-(D(d)?W(d,kt):d);zt=i.top?Bt:0}if(g&&!D(g)||at.width||(at.width=St||this.contrastSize((this.isBlock(this)&&!this.isInFlow()?X||o.lineMaxWidth:this.lineMaxWidth)||this.lineMaxWidth,v,y),this.layoutBoxUpdate(at,i,0)),m||!bt&&!zt||(at.height=zt||this.contrastSize(bt,x,b),this.layoutBoxUpdate(at,i)),i.borderRadius&&this.borderSize&&this.borderSize.width)for(var q in i.borderRadius)Object.hasOwnProperty.call(i.borderRadius,q)&&(i.borderRadius[q]=W(i.borderRadius[q],this.borderSize.width));return this.layoutBox},e.layout=function(){return this.getBoxWidthHeight(),this.root.offsetSize=this.offsetSize,this.root.contentSize=this.contentSize,this.getBoxPosition(),this.offsetSize},t}(),gt=function(){var t,e,i,n,r,o,s=[0,11,15,19,23,27,31,16,18,20,22,24,26,28,20,22,24,24,26,28,28,22,24,24,26,26,28,28,24,24,26,26,26,28,28,24,26,26,26,28,28],a=[3220,1468,2713,1235,3062,1890,2119,1549,2344,2936,1117,2583,1330,2470,1667,2249,2028,3780,481,4011,142,3098,831,3445,592,2517,1776,2234,1951,2827,1070,2660,1345,3177],h=[30660,29427,32170,30877,26159,25368,27713,26998,21522,20773,24188,23371,17913,16590,20375,19104,13663,12392,16177,14854,9396,8579,11994,11245,5769,5054,7399,6608,1890,597,3340,2107],c=[1,0,19,7,1,0,16,10,1,0,13,13,1,0,9,17,1,0,34,10,1,0,28,16,1,0,22,22,1,0,16,28,1,0,55,15,1,0,44,26,2,0,17,18,2,0,13,22,1,0,80,20,2,0,32,18,2,0,24,26,4,0,9,16,1,0,108,26,2,0,43,24,2,2,15,18,2,2,11,22,2,0,68,18,4,0,27,16,4,0,19,24,4,0,15,28,2,0,78,20,4,0,31,18,2,4,14,18,4,1,13,26,2,0,97,24,2,2,38,22,4,2,18,22,4,2,14,26,2,0,116,30,3,2,36,22,4,4,16,20,4,4,12,24,2,2,68,18,4,1,43,26,6,2,19,24,6,2,15,28,4,0,81,20,1,4,50,30,4,4,22,28,3,8,12,24,2,2,92,24,6,2,36,22,4,6,20,26,7,4,14,28,4,0,107,26,8,1,37,22,8,4,20,24,12,4,11,22,3,1,115,30,4,5,40,24,11,5,16,20,11,5,12,24,5,1,87,22,5,5,41,24,5,7,24,30,11,7,12,24,5,1,98,24,7,3,45,28,15,2,19,24,3,13,15,30,1,5,107,28,10,1,46,28,1,15,22,28,2,17,14,28,5,1,120,30,9,4,43,26,17,1,22,28,2,19,14,28,3,4,113,28,3,11,44,26,17,4,21,26,9,16,13,26,3,5,107,28,3,13,41,26,15,5,24,30,15,10,15,28,4,4,116,28,17,0,42,26,17,6,22,28,19,6,16,30,2,7,111,28,17,0,46,28,7,16,24,30,34,0,13,24,4,5,121,30,4,14,47,28,11,14,24,30,16,14,15,30,6,4,117,30,6,14,45,28,11,16,24,30,30,2,16,30,8,4,106,26,8,13,47,28,7,22,24,30,22,13,15,30,10,2,114,28,19,4,46,28,28,6,22,28,33,4,16,30,8,4,122,30,22,3,45,28,8,26,23,30,12,28,15,30,3,10,117,30,3,23,45,28,4,31,24,30,11,31,15,30,7,7,116,30,21,7,45,28,1,37,23,30,19,26,15,30,5,10,115,30,19,10,47,28,15,25,24,30,23,25,15,30,13,3,115,30,2,29,46,28,42,1,24,30,23,28,15,30,17,0,115,30,10,23,46,28,10,35,24,30,19,35,15,30,17,1,115,30,14,21,46,28,29,19,24,30,11,46,15,30,13,6,115,30,14,23,46,28,44,7,24,30,59,1,16,30,12,7,121,30,12,26,47,28,39,14,24,30,22,41,15,30,6,14,121,30,6,34,47,28,46,10,24,30,2,64,15,30,17,4,122,30,29,14,46,28,49,10,24,30,24,46,15,30,4,18,122,30,13,32,46,28,48,14,24,30,42,32,15,30,20,4,117,30,40,7,47,28,43,22,24,30,10,67,15,30,19,6,118,30,18,31,47,28,34,34,24,30,20,61,15,30],f=[255,0,1,25,2,50,26,198,3,223,51,238,27,104,199,75,4,100,224,14,52,141,239,129,28,193,105,248,200,8,76,113,5,138,101,47,225,36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,201,154,9,120,77,228,114,166,6,191,139,98,102,221,48,253,226,152,37,179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,243,167,87,7,112,192,247,140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175],l=[1,2,4,8,16,32,64,128,29,58,116,232,205,135,19,38,76,152,45,90,180,117,234,201,143,3,6,12,24,48,96,192,157,39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,140,5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141,7,14,28,56,112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,69,138,9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,88,176,125,250,233,207,131,27,54,108,216,173,71,142,0],d=[],u=[],p=[],g=[],v=[],y=2;function x(t,e){var i;t>e&&(i=t,t=e,e=i),i=e,i*=e,i+=e,i>>=1,g[i+=t]=1}function b(t,i){var n;for(p[t+e*i]=1,n=-2;n<2;n++)p[t+n+e*(i-2)]=1,p[t-2+e*(i+n+1)]=1,p[t+2+e*(i+n)]=1,p[t+n+1+e*(i+2)]=1;for(n=0;n<2;n++)x(t-1,i+n),x(t+1,i-n),x(t-n,i-1),x(t+n,i+1)}function w(t){for(;t>=255;)t=((t-=255)>>8)+(255&t);return t}var m=[];function S(t,e,i,n){var r,o,s;for(r=0;re&&(i=t,t=e,e=i),i=e,i+=e*e,i>>=1,g[i+=t]}function I(t){var i,n,r,o;switch(t){case 0:for(n=0;n>1&1,i=0;i=5&&(i+=3+v[e]-5);for(e=3;et||3*v[e-3]>=4*v[e]||3*v[e+3]>=4*v[e])&&(i+=40);return i}function k(){var t,i,n,r,o,s=0,a=0;for(i=0;ie*e;)h-=e*e,c++;for(s+=10*c,t=0;t1)for(P=s[t],B=e-7;;){for(M=e-7;M>P-3&&(b(M,B),!(M6)for(P=a[t-7],W=17,M=0;M<6;M++)for(B=0;B<3;B++,W--)1&(W>11?t>>W-12:P>>W)?(p[5-M+e*(2-B+e-11)]=1,p[2-B+e-11+e*(5-M)]=1):(x(5-M,2-B+e-11),x(2-B+e-11,5-M));for(B=0;B=(M=r*(i+n)+n)-2&&(O=M-2,t>9&&O--),T=O,t>9){for(d[T+2]=0,d[T+3]=0;T--;)P=d[T],d[T+3]|=255&P<<4,d[T+2]=P>>4;d[2]|=255&O<<4,d[1]=O>>4,d[0]=64|O>>12}else{for(d[T+1]=0,d[T+2]=0;T--;)P=d[T],d[T+2]|=255&P<<4,d[T+1]=P>>4;d[1]|=255&O<<4,d[0]=64|O>>4}for(T=O+3-(t<10);T0;L--)m[L]=m[L]?m[L-1]^l[w(f[m[L]]+T)]:m[L-1];m[0]=l[w(f[m[0]]+T)]}for(T=0;T<=o;T++)m[T]=f[m[T]];for(W=M,B=0,T=0;T>=1)1&B&&(p[e-1-W+8*e]=1,W<6?p[8+e*W]=1:p[8+e*(W+1)]=1);for(W=0;W<7;W++,B>>=1)1&B&&(p[8+e*(e-7+W)]=1,W?p[6-W+8*e]=1:p[7+8*e]=1);return p}(v)},utf16to8:function(t){var e,i,n,r;for(e="",n=t.length,i=0;i=1&&r<=127?e+=t.charAt(i):r>2047?(e+=String.fromCharCode(224|r>>12&15),e+=String.fromCharCode(128|r>>6&63),e+=String.fromCharCode(128|r>>0&63)):(e+=String.fromCharCode(192|r>>6&31),e+=String.fromCharCode(128|r>>0&63));return e},draw:function(t,i,n,r,o){i.drawView(n,r);var s=i.ctx,a=n.contentSize,h=a.width,c=a.height,f=a.left,l=a.top;r.borderRadius,r.backgroundColor;var d=r.color,u=void 0===d?"#000000":d;r.border,n.contentSize.left,n.borderSize.left,n.contentSize.top,n.borderSize.top;if(y=o||y,s){s.save(),i.setOpacity(r),i.setTransform(n,r);var p=Math.min(h,c);t=this.utf16to8(t);var g=this.getFrame(t),v=p/e;s.setFillStyle(u);for(var x=0;x=s||n==c&&o=s)&&(a=e.width/i.width);var f=i.width*a,l=i.height*a,d=r||[],u=d[0],p=d[1],g=B(u)?W(u,e.width):(e.width-f)*(P(u)?W(u,1):{left:0,center:.5,right:1}[u||"center"]),v=B(p)?W(p,e.height):(e.height-l)*(P(p)?W(p,1):{top:0,center:.5,bottom:1}[p||"center"]),y=function(t,e){return[(t-g)/a,(e-v)/a]},x=y(0,0),b=x[0],w=x[1],m=y(e.width,e.height),S=m[0],z=m[1],I=Math.max,M=Math.min;return{sx:I(b,0),sy:I(w,0),sw:M(S-b,i.width),sh:M(z-w,i.height),dx:I(g,0),dy:I(v,0),dw:M(f,e.width),dh:M(l,e.height)}}({objectFit:u,objectPosition:v},r.contentSize,t),o=i.sx,s=i.sy,a=i.sh,h=i.sw,c=i.dx,f=i.dy,l=i.dh,d=i.dw;I==n.MP_BAIDU?e.drawImage(t.src,c+m,f+S,d,l,o,s,h,a):e.drawImage(t.src,o,s,h,a,c+m,f+S,d,l)}else e.drawImage(t.src,m,S,b,w)},O=function(){e.restore(),L.drawView(r,o,!1,!0,!1),h(1)},T=function(t){k(t),O()},T(t),[2]}))}))}))];case 1:return h.sent(),[2]}}))}))},r.prototype.drawText=function(t,e,i,n){var r=this,o=this.ctx,s=e.borderSize,a=e.contentSize,h=e.left,c=e.top,f=a.width,l=a.height,d=a.left-s.left||0,u=a.top-s.top||0,p=i.color,g=i.lineHeight,v=i.fontSize,y=i.fontWeight,x=i.fontFamily,b=i.fontStyle,w=i.textIndent,m=void 0===w?0:w,S=i.textAlign,z=i.textStroke,I=i.verticalAlign,M=void 0===I?mt:I,k=i.backgroundColor,P=i.lineClamp,O=i.backgroundClip,T=i.textShadow,L=i.textDecoration;if(m=B(m)?m:0,this.drawView(e,i,O!=yt),g=W(g,v),t){o.save(),h+=d,c+=u;var R=n.fontHeight,F=n.descent,A=void 0===F?0:F,j=n.ascent,E=A+(void 0===j?0:j);switch(o.setFonts({fontFamily:x,fontSize:v,fontWeight:y,fontStyle:b}),o.setTextBaseline(mt),o.setTextAlign(S),O?this.setBackground(k,f,l,h,c):o.setFillStyle(p),S){case zt:break;case It:h+=.5*f;break;case Mt:h+=f}var C=n.lines*g,H=Math.ceil((l-C)/2);switch(H<0&&(H=0),M){case wt:break;case mt:c+=H;break;case St:c+=2*H}var D=(g-R)/2,Y=g/2,$=function(t){var e=o.measureText(t),i=e.actualBoundingBoxDescent,n=void 0===i?0:i,r=e.actualBoundingBoxAscent;return M==wt?{fix:E?void 0===r?0:r:Y-D/2,lineY:E?0:D-D/2}:M==mt?{fix:E?Y+n/4:Y,lineY:E?0:D}:M==St?{fix:E?g-n:Y+D/2,lineY:E?2*D:D+D/2}:{fix:0,height:0,lineY:0}},U=function(t,e,i){var r=t;switch(S){case zt:r+=i;break;case It:r=(t-=i/2)+i;break;case Mt:r=t,t-=i}if(L){o.setLineWidth(v/13),o.beginPath();var s=.1*n.fontHeight;/\bunderline\b/.test(L)&&(o.moveTo(t,e+n.fontHeight+s),o.lineTo(r,e+n.fontHeight+s)),/\boverline\b/.test(L)&&(o.moveTo(t,e-s),o.lineTo(r,e-s)),/\bline-through\b/.test(L)&&(o.moveTo(t,e+.5*n.fontHeight),o.lineTo(r,e+.5*n.fontHeight)),o.closePath(),o.setStrokeStyle(p),o.stroke()}},N=function(t,e,i){var n=function(){o.setLineWidth(z.width),o.setStrokeStyle(z.color),o.strokeText(t,e,i)},s="outset";z&&z.type!==s?(o.save(),r.setShadow({boxShadow:T}),o.fillText(t,e,i),o.restore(),n()):z&&z.type==s?(o.save(),r.setShadow({boxShadow:T}),n(),o.restore(),o.save(),o.fillText(t,e,i),o.restore()):(r.setShadow({boxShadow:T}),o.fillText(t,e,i))};if(!n.widths||1==n.widths.length&&n.widths[0].total+m<=a.width){var X=$(t),_=X.fix,q=void 0===_?0:_,G=X.lineY;return N(t,h+m,c+q),U(h+m,c+G,n&&n.widths&&n.widths[0].total||n.text),c+=g,o.restore(),void this.setBorder(e,i)}for(var V=c,J=h,Q="",Z=0,K=o.measureText("...").width,tt=n.widths,et=0;eta.width){Z>=P&&(Q+="…"),Z++,nt=0;var ct=$(Q);q=ct.fix,G=ct.lineY;N(Q,J,c+q),U(J,c+G,nt),c+=g,Q=""}else if(rt==it.length-1){et!=tt.length-1&&Z==P&&K+ntV+l||Z>P)break}}o.restore()}},r.prototype.source=function(t){return e(this,void 0,void 0,(function(){var e,n,r,o,s=this;return i(this,(function(i){switch(i.label){case 0:if(this.node=null,e=+new Date,"{}"==JSON.stringify(t))return[2];if(t.styles=t.styles||t.css||{},!t.type)for(n in t.type=bt,t)["views","children","type","css","styles"].includes(n)||(t.styles[n]=t[n],delete t[n]);return t.styles.boxSizing||(t.styles.boxSizing="border-box"),[4,this.create(t)];case 1:return(r=i.sent())?(o=r.layout()||{},this.size=o,this.node=r,this.onEffectFinished().then((function(t){return s.lifecycle("onEffectSuccess",t)})).catch((function(t){return s.lifecycle("onEffectFail",t)})),this.performance&&console.log("布局用时:"+(+new Date-e)+"ms"),[2,this.size]):[2,console.warn("no node")]}}))}))},r.prototype.getImageInfo=function(t){return this.imageBus[t]||(this.imageBus[t]=this.createImage(t,this.useCORS)),this.imageBus[t]},r.prototype.create=function(n,r){return e(this,void 0,void 0,(function(){function e(i,n,r){void 0===n&&(n={}),void 0===r&&(r=!0);var o=[];return i.forEach((function(i){var s=i.styles,a=void 0===s?{}:s,h=i.css,c=void 0===h?{}:h,f=i.children,l=void 0===f?[]:f,d=i.views,u=void 0===d?[]:d,p=i.text,g=void 0===p?"":p,v=i.type,y=void 0===v?"":v;!l&&u&&(i.children=l=u);var x={};x=t(t(r?t({},n):{},a),c);var b={},w={},m={};Object.keys(x).map((function(t){if(t.includes("padding")||t.includes("margin")){var e=V(t,x[t]);Object.keys(e).map((function(t){t.includes("Left")?w[t]=e[t]:t.includes("Right")?m[t]=e[t]:b[t]=e[t]}))}}));if(x.textIndent&&(w.textIndent=x.textIndent,delete n.textIndent),""!==g){var S=Array.from(g);S.forEach((function(t,e){var i=Object.assign({},x,b);0===e?Object.assign(i,w):e==S.length-1&&Object.assign(i,m),delete i.padding,delete i.margin,o.push({type:"text",text:t,styles:i})}))}if(y==vt||y==xt)o.push(i);else if("block"===a.display&&l.length>0){var z=e(l,x,!1);i.children=z,i.flattened=!0,o.push(i)}else if(l.length>0){z=e(l,x,r);o=o.concat(z)}})),o}var o,s,a,h,c,f,l,d,u,p,g,v,y,b,w,m,S,z,I,M,k,B,W,P;return i(this,(function(i){switch(i.label){case 0:if(!n)return[2];if(n.styles||(n.styles=n.css||{}),o=n.type,s=n.show,a=void 0===s||s,h=o==vt,c=[yt,xt].includes(o),f="textBox"==o,l=n.styles||{},d=l.backgroundImage,u=l.display,h&&!n.src&&!n.url)return[2];if(u==x||!a)return[2];if(c||f){if(p=n.children,g=n.views,!p&&g&&(n.children=p=g),!n.text&&(!p||p&&!p.length))return[2];p&&p.length&&!n.flattened&&(v=e(n.children||n.views),n.type="view",n.children=v)}if(!(h||n.type==bt&&d))return[3,4];y=h?n.src:"",b=/url\(['"]?(.*?)['"]?\)/.exec(d),d&&b&&b[1]&&(y=b[1]||""),i.label=1;case 1:return i.trys.push([1,3,,4]),[4,this.getImageInfo(y)];case 2:return w=i.sent(),m=w.width,S=w.height,!(z=w.path)&&h?[2]:(z&&(n.attributes=Object.assign(n.attributes||{},{width:m,height:S,path:z,src:z,naturalSrc:y})),[3,4]);case 3:return I=i.sent(),n.type!=bt?[2]:(this.lifecycle("onEffectFail",t(t({},I),{src:y})),[3,4]);case 4:if(this.count+=1,M=new pt(n,r,this.root,this.ctx),!(k=n.children||n.views))return[3,8];B=0,i.label=5;case 5:return B0&&r[r.length-1])||6!==o[0]&&2!==o[0])){s=0;continue}if(3===o[0]&&(!r||o[1]>r[0]&&o[1]=360&&(s-=360);s<0&&(s+=360);if(0===(s=Math.round(s)))return{x0:Math.round(e/2)+n,y0:i+r,x1:Math.round(e/2)+n,y1:r};if(180===s)return{x0:Math.round(e/2)+n,y0:r,x1:Math.round(e/2)+n,y1:i+r};if(90===s)return{x0:n,y0:Math.round(i/2)+r,x1:e+n,y1:Math.round(i/2)+r};if(270===s)return{x0:e+n,y0:Math.round(i/2)+r,x1:n,y1:Math.round(i/2)+r};var h=Math.round(180*Math.asin(e/Math.sqrt(Math.pow(e,2)+Math.pow(i,2)))/Math.PI);if(s===h)return{x0:n,y0:i+r,x1:e+n,y1:r};if(s===180-h)return{x0:n,y0:r,x1:e+n,y1:i+r};if(s===180+h)return{x0:e+n,y0:r,x1:n,y1:i+r};if(s===360-h)return{x0:e+n,y0:i+r,x1:n,y1:r};var a=0,l=0,d=0,c=0;if(s180-h&&s<180||s>180&&s<180+h||s>360-h){var f=s*Math.PI/180,u=s360-h?i/2:-i/2,p=Math.tan(f)*u,g=s180-h&&s<180?e/2-p:-e/2-p;a=-(d=p+(v=Math.pow(Math.sin(f),2)*g)),l=-(c=u+v/Math.tan(f))}if(s>h&&s<90||s>90&&s<90+h||s>180+h&&s<270||s>270&&s<360-h){var v;f=(90-s)*Math.PI/180,p=s>h&&s<90||s>90&&s<90+h?e/2:-e/2,u=Math.tan(f)*p,g=s>h&&s<90||s>270&&s<360-h?i/2-u:-i/2-u;a=-(d=p+(v=Math.pow(Math.sin(f),2)*g)/Math.tan(f)),l=-(c=u+v)}return a=Math.round(a+e/2)+n,l=Math.round(i/2-l)+r,d=Math.round(d+e/2)+n,c=Math.round(i/2-c)+r,{x0:a,y0:l,x1:d,y1:c}}(r,t,e,i,n),h=s.x0,a=s.y0,l=s.x1,d=s.y1,c=o.createLinearGradient(h,a,l,d),f=r.match(/linear-gradient\((.+)\)/)[1],u=L(f.substring(f.indexOf(",")+1)),p=0;pt.length)&&(e=t.length);for(var i=0,n=new Array(e);i=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function H(t){return"number"==typeof t}function C(t){return"auto"===t||null===t}function D(t){return/%$/.test(t)}var Y=p,$=u,U=f,N=g,X=y,_=w,q=m;function G(t){return t.replace(/-([a-z])/g,(function(t,e){return e.toUpperCase()}))}function V(t,e){var i,n,o=function(t){var e=t.match(/([a-z]+)/)[1];return[e,G(t.split(e)[1])]}(t),s=o[0],h=o[1],a=e.split(" ");if(h)return(i={})[s+h]=e,i;if(a.length&&!h){var l=a[0],d=a[1],c=a[2],f=a[3];return(n={})[s+r[0]]=l,n[s+r[1]]=d||l,n[s+r[2]]=c||l,n[s+r[3]]=f||d||l,n}}function J(t){t=t.trim();for(var e=new Array,i="+",n="",r=t.length,o=0;o0;)"("===t[h+=1]&&(s+=1),")"===t[h]&&(s-=1);n="".concat(J(t.slice(o+1,h))),o=h}if(isNaN(Number(t[o]))&&"."!==t[o]||o===r-1){var a=parseFloat(n);switch(i){case"+":e.push(a);break;case"-":e.push(-a);break;case"*":e.push(e.pop()*a);break;case"/":e.push(e.pop()/a)}i=t[o],n=""}}for(var l=0;e.length;)l+=e.pop();return l}var Q,Z=0,K=function(){function t(){R(this,"elements",[]),R(this,"afterElements",[]),R(this,"beforeElements",[]),R(this,"ids",[]),R(this,"width",0),R(this,"height",0),R(this,"top",0),R(this,"left",0),R(this,"pre",null),R(this,"offsetX",0),R(this,"offsetY",0),Z++,this.id=Z}var e=t.prototype;return e.fixedBind=function(t,e){void 0===e&&(e=0),this.container=e?t.parent:t.root,this.container.fixedLine=this,this.fixedAdd(t)},e.fixedAdd=function(t){if(!this.ids.includes(t.id)){this.ids.push(t.id),this.elements.push(t);var e=t.computedStyle.zIndex;(void 0===e?0:e)>=0?this.afterElements.push(t):this.beforeElements.push(t),this.refreshLayout()}},e.bind=function(t){this.container=t.parent,this.container.line=null,this.container.lines?(this.container.lines.push(this),this.pre=this.getPreLine(),this.top=this.pre.top+this.pre.height,this.left=this.container.contentSize.left):(this.top=this.container.contentSize.top,this.left=this.container.contentSize.left,this.container.lines=[this]),this.isInline=t.isInline(),this.container.line=this,this.outerWidth=t.parent&&t.parent.contentSize.width?t.parent.contentSize.width:1/0,this.add(t)},e.getPreLine=function(){return this.container.lines[this.container.lines.length-2]},e.canIEnter=function(t){return!((100*t.offsetSize.width+100*this.width)/100>this.outerWidth)||(this.closeLine(),!1)},e.closeLine=function(){delete this.container.line},e.add=function(t){this.ids.includes(t.id)||(this.ids.push(t.id),this.elements.push(t),this.refreshWidthHeight(t))},e.refreshWidthHeight=function(t){t.offsetSize.height>this.height&&(this.height=t.offsetSize.height),this.width+=t.offsetSize.width||0,(this.container.lineMaxWidth||0)this[this.key.height]&&(this.container[this.key.lineMaxHeight]=this[this.key.height]=i),this[this.key.width]+=this.getWidth(t.offsetSize);var n=Math.min(this.getWidth(this),!this.getWidth(this.container.contentSize)&&1/0);(this.container[this.key.lineMaxWidth]||0)1)return 0;var e=t.style.alignSelf,i=this.getHeight(this.container.contentSize),n=i-this.getHeight(t.offsetSize);return"flex-end"===e?n:"center"===e?n/2:"stretch"===e?(n&&t.name==f&&(t.style[this.key.width]=this.getWidth(t.offsetSize),t.style[this.key.height]=i,delete t.line,delete t.lines,t.getBoxWidthHeight()),0):0},r.layout=function(t,e){var i=this;this.refreshXAlign(),this.pre?(this.top=this.pre.top+this.pre.height+this.offsetY,this.left=e+this.offsetX):(this.top=Math.max(this.top,this.container.contentSize.top,t)+this.offsetY,this.left=Math.max(this.left,this.container.contentSize.left,e)+this.offsetX),this.elements.forEach((function(t,e){i.setIndent(t);var n=i.elements[e-1],r=i.getOffsetY(t);t.style[i.key.top]=i[i.key.top]+r,t.style[i.key.left]=n?n.offsetSize[i.key.left]+i.getWidth(n.offsetSize):i[i.key.left],t.getBoxPosition()}))},n}(K),nt=p,rt=u,ot=f,st=v,ht=y,at=b,lt=w,dt=m,ct=0,ft={left:null,top:null,width:null,height:null},ut=new Map,pt=function(){function t(t,e,i,n){var o=this;R(this,"id",ct++),R(this,"style",{left:null,top:null,width:null,height:null}),R(this,"computedStyle",{}),R(this,"originStyle",{}),R(this,"children",{}),R(this,"layoutBox",F({},ft)),R(this,"contentSize",F({},ft)),R(this,"clientSize",F({},ft)),R(this,"borderSize",F({},ft)),R(this,"offsetSize",F({},ft)),this.ctx=n,this.root=i,e&&(this.parent=e),this.name=t.type||t.name,this.attributes=this.getAttributes(t);var s=function(t,e){var i,n=["color","fontSize","lineHeight","verticalAlign","fontWeight","textAlign"],o=t.type,s=void 0===o?U:o,h=t.styles,a=void 0===h?{}:h,l=(e||{}).computedStyle,d=Object.assign({},S);if([$,Y,N].includes(s)&&!a.display&&(d.display=X),l)for(var c=0;c=0&&c<0,Y=l>=0&&u<0;return i==h[0]&&(this[i].left=t.left+s+v+E+(D?2*-c:0),this[i].top=t.top+l+x+k+(Y?2*-u:0),this[i].width=t.width+(this[i].widthAdd?0:H),this[i].height=t.height+(this[i].heightAdd?0:C),this[i].widthAdd=H,this[i].heightAdd=C),i==h[1]&&(this[i].left=t.left+s+E+(D<0?-c:0),this[i].top=t.top+l+k+(Y?-u:0),this[i].width=t.width+v+w,this[i].height=t.height+x+S),i==h[2]&&(this[i].left=t.left+s+E/2+(D<0?-c:0),this[i].top=t.top+l+k/2+(Y?-u:0),this[i].width=t.width+v+w+E/2+F/2,this[i].height=t.height+x+S+T/2+k/2),i==h[3]&&(this[i].left=t.left+(D<0?-c:0),this[i].top=t.top+(Y?-u:0),this[i].width=t.width+v+w+E+F+s+c,this[i].height=t.height+x+S+T+k+u+l),this[i]},e.layoutBoxUpdate=function(t,e,i,n){var r=this;if(void 0===i&&(i=-1),"border-box"==e.boxSizing){var o=e||{},s=o.border,a=(s=void 0===s?{}:s).borderWidth,l=void 0===a?0:a,d=o.borderTop,c=(d=void 0===d?{}:d).borderTopWidth,f=void 0===c?l:c,u=o.borderBottom,p=(u=void 0===u?{}:u).borderBottomWidth,g=void 0===p?l:p,v=o.borderRight,y=(v=void 0===v?{}:v).borderRightWidth,x=void 0===y?l:y,b=o.borderLeft,w=(b=void 0===b?{}:b).borderLeftWidth,m=void 0===w?l:w,S=o.padding,z=(S=void 0===S?{}:S).paddingTop,I=void 0===z?0:z,M=S.paddingRight,B=void 0===M?0:M,W=S.paddingBottom,k=void 0===W?0:W,P=S.paddingLeft,O=void 0===P?0:P;i||(t.width-=O+B+x+m),1!==i||n||(t.height-=I+k+f+g)}this.layoutBox&&(h.forEach((function(i){return r.layoutBox[i]=r.getOffsetSize(t,e,i)})),this.layoutBox=Object.assign({},this.layoutBox,this.layoutBox.borderSize))},e.getBoxPosition=function(){var t=this.computedStyle,e=this.fixedLine,i=this.lines,n=t.left,r=void 0===n?0:n,o=t.top,s=void 0===o?0:o,h=F({},this.contentSize,{left:r,top:s}),a=this.contentSize.top-this.offsetSize.top,l=this.contentSize.left-this.offsetSize.left;if(this.root.fixedLine&&!this.root.isDone){this.root.isDone=!0;for(var d,c=E(this.root.fixedLine.elements);!(d=c()).done;){var f=d.value;f.setPosition(f,this.root.offsetSize),f.getBoxPosition()}}if(e)for(var u,p=E(e.elements);!(u=p()).done;){var g=u.value,v=F({},this.borderSize,{left:r,top:s});g.setPosition(g,v);var y=this.borderSize.top-this.offsetSize.top,x=this.borderSize.left-this.offsetSize.left;g.style.left+=r+x,g.style.top+=s+y,g.getBoxPosition()}if(i)for(var b,w=E(i);!(b=w()).done;){b.value.layout(h.top+a,h.left+l)}return this.layoutBoxUpdate(h,t),this.layoutBox},e.getBoxState=function(t,e){return this.isBlock(t)||this.isBlock(e)},e.isBlock=function(t){return void 0===t&&(t=this),t&&t.style.display==st},e.isFlex=function(t){return void 0===t&&(t=this),t&&t.style.display==at},e.isInFlow=function(){return!(this.isAbsolute||this.isFixed)},e.inFlexBox=function(t){return void 0===t&&(t=this),!!t.isInFlow()&&(!!t.parent&&(!(!t.parent||t.parent.style.display!==at)||void 0))},e.isInline=function(t){return void 0===t&&(t=this),t&&t.style.display==ht},e.contrastSize=function(t,e,i){var n=t;return i&&(n=Math.min(n,i)),e&&(n=Math.max(n,e)),n},e.measureText=function(t,e){var i=this.ctx.measureText(t),n=i.width,r=i.actualBoundingBoxAscent,o=i.actualBoundingBoxDescent;return{ascent:r,descent:o,width:n,fontHeight:r+o||.7*e+1}},e.getParentSize=function(t,e){if(void 0===t&&(t=this),void 0===e&&(e=!1),t&&t.parent){if(t.parent.contentSize.width)return t.parent.contentSize;if(e)return this.getParentSize(t.parent,e)}return null},e.getBoxWidthHeight=function(){var t=this,e=this.name,i=this.computedStyle,n=this.attributes,r=this.parent,o=void 0===r?{}:r,s=this.ctx,h=this.getChildren(),a=i.left,l=void 0===a?0:a,d=i.top,c=void 0===d?0:d,f=i.bottom,u=i.right,p=i.width,g=void 0===p?0:p,v=i.minWidth,y=i.maxWidth,x=i.minHeight,b=i.maxHeight,w=i.height,m=void 0===w?0:w,S=i.fontSize,z=i.fontWeight,I=i.fontFamily,M=i.fontStyle,B=i.position;i.textIndent;var W=i.lineClamp,P=i.lineHeight,O=i.padding,T=void 0===O?{}:O,L=i.margin,R=void 0===L?{}:L,F=i.border,A=(F=void 0===F?{}:F).borderWidth,j=void 0===A?0:A,E=i.borderRight,H=(E=void 0===E?{}:E).borderRightWidth,Y=void 0===H?j:H,$=i.borderLeft,U=($=void 0===$?{}:$).borderLeftWidth,N=void 0===U?j:U,X=o.contentSize&&o.contentSize.width,_=o.contentSize&&o.contentSize.height;if(D(g)&&X&&(g=k(g,X)),D(g)&&!X&&(g=null),D(m)&&_&&(m=k(m,_)),D(m)&&!_&&(m=null),D(v)&&X&&(v=k(v,X)),D(y)&&X&&(y=k(y,X)),D(x)&&_&&(x=k(x,_)),D(b)&&_&&(b=k(b,_)),i.padding&&X)for(var q in i.padding)Object.hasOwnProperty.call(T,q)&&(T[q]=k(T[q],X));var G=T.paddingRight,V=void 0===G?0:G,J=T.paddingLeft,Q=void 0===J?0:J;if(i.margin&&[R.marginLeft,R.marginRight].includes("auto"))if(g){var Z=X&&X-g-V-Q-N-Y||0;R.marginLeft==R.marginRight?R.marginLeft=R.marginRight=Z/2:C(R.marginLeft)?R.marginLeft=Z:R.marginRight=Z}else R.marginLeft=R.marginRight=0;var tt=R.marginRight,et=void 0===tt?0:tt,st=R.marginLeft,ht={width:g,height:m,left:0,top:0},at=Q+V+N+Y+(void 0===st?0:st)+et;if(this.offsetWidth=at,e==rt&&!this.attributes.widths){var dt=n.text||"";s.save(),s.setFonts({fontFamily:I,fontSize:S,fontWeight:z,fontStyle:M}),dt.length,"\n"==dt&&(dt="",this.isBr=!0),(""+dt).split("\n").map((function(e){var i=Array.from(e).map((function(e){var i=""+(/^[\u4e00-\u9fa5]+$/.test(e)?"cn":e)+I+S+z+M,n=ut.get(i);if(n)return{width:n,text:e};var r=t.measureText(e,S).width;return ut.set(i,r),{width:r,text:e}})),n=t.measureText(e,S),r=n.fontHeight,o=n.ascent,s=n.descent;t.attributes.fontHeight=r,t.attributes.ascent=o,t.attributes.descent=s,t.attributes.widths||(t.attributes.widths=[]),t.attributes.widths.push({widths:i,total:i.reduce((function(t,e){return t+e.width}),0)})})),s.restore()}if(e==nt&&null==g){var ct=n.width,ft=n.height;ht.width=this.contrastSize(Math.round(ct*m/ft)||0,v,y),this.layoutBoxUpdate(ht,i,0)}if(e==rt&&null==g){var pt=this.attributes.widths,gt=Math.max.apply(Math,pt.map((function(t){return t.total})));if(o&&X>0&&(gt>X||this.isBlock(this))&&!this.isAbsolute&&!this.isFixed)gt=X;ht.width=this.contrastSize(gt,v,y),this.layoutBoxUpdate(ht,i,0)}if(e==rt&&(o.style.flex||!this.attributes.lines)){var vt=this.attributes.widths.length;this.attributes.widths.forEach((function(t){return t.widths.reduce((function(t,e,i){return t+e.width>ht.width?(vt++,e.width):t+e.width}),0)})),vt=W&&vt>W?W:vt,this.attributes.lines=vt}if(e==nt&&null==m){var yt=n.width,xt=n.height;n.text,ht.height=this.contrastSize(k(ht.width*xt/yt)||0,x,b),this.layoutBoxUpdate(ht,i,1)}e==rt&&null==m&&(P=k(P,S),ht.height=this.contrastSize(k(this.attributes.lines*P),x,b),this.layoutBoxUpdate(ht,i,1,!0)),!g&&o&&o.children&&X&&(!this.isFlex(o)||o.isFlexCalc)&&([ot,rt].includes(e)&&this.isFlex()||e==ot&&this.isBlock(this)&&this.isInFlow())&&(ht.width=this.contrastSize(X-(o.isFlexCalc?0:at),v,y),this.layoutBoxUpdate(ht,i)),g&&!D(g)&&(ht.width=this.contrastSize(g,v,y),this.layoutBoxUpdate(ht,i,0)),m&&!D(m)&&(ht.height=this.contrastSize(ht.height,x,b),this.layoutBoxUpdate(ht,i,1));var bt=0;if(h.length){var wt=null,mt=!1;h.forEach((function(e,n){e.getBoxWidthHeight();var r=h[n+1];if(r&&r.isInFlow()&&(e.next=r),!t.line||!t.line.ids.includes(e.id))if(e.isInFlow()&&!e.inFlexBox()){var o=t.getBoxState(wt,e);if(e.isBr)return mt=!0;t.line&&t.line.canIEnter(e)&&!o&&!mt?t.line.add(e):(mt=!1,(new K).bind(e)),wt=e}else e.inFlexBox()?t.line&&(t.line.canIEnter(e)||"nowrap"==i.flexWrap)?t.line.add(e):(new it).bind(e):e.isFixed?t.root.fixedLine?t.root.fixedLine.fixedAdd(e):(new K).fixedBind(e):t.fixedLine?t.fixedLine.fixedAdd(e):(new K).fixedBind(e,1)})),this.lines&&(bt=this.lines.reduce((function(t,e){return t+e.height}),0))}var St=0,zt=0;if(!g&&(this.isAbsolute||this.isFixed)&&X){var It=B==lt?X:this.root.width,Mt=It-(D(l)?k(l,It):l)-(D(u)?k(u,It):u);St=i.left?Mt:this.lineMaxWidth}if(!m&&(null!=c?c:this.isAbsolute||this.isFixed&&_)){var Bt=B==lt?_:this.root.height,Wt=Bt-(D(c)?k(c,Bt):c)-(D(f)?k(f,Bt):f);zt=i.top?Wt:0}if(g&&!D(g)||ht.width||(ht.width=St||this.contrastSize((this.isBlock(this)&&!this.isInFlow()?X||o.lineMaxWidth:this.lineMaxWidth)||this.lineMaxWidth,v,y),this.layoutBoxUpdate(ht,i,0)),m||!bt&&!zt||(ht.height=zt||this.contrastSize(bt,x,b),this.layoutBoxUpdate(ht,i)),i.borderRadius&&this.borderSize&&this.borderSize.width)for(var q in i.borderRadius)Object.hasOwnProperty.call(i.borderRadius,q)&&(i.borderRadius[q]=k(i.borderRadius[q],this.borderSize.width));return this.layoutBox},e.layout=function(){return this.getBoxWidthHeight(),this.root.offsetSize=this.offsetSize,this.root.contentSize=this.contentSize,this.getBoxPosition(),this.offsetSize},t}(),gt=p,vt=u,yt=g,xt=f,bt=d.TOP,wt=d.MIDDLE,mt=d.BOTTOM,St=c.LEFT,zt=c.CENTER,It=c.RIGHT,Mt=function(){function r(t){var e,i,r=this;this.v="1.9.5.1",this.id=null,this.pixelRatio=1,this.width=0,this.height=0,this.sleep=1e3/30,this.count=0,this.isRate=!1,this.isDraw=!0,this.isCache=!0,this.fixed="",this.useCORS=!1,this.performance=!1,this.imageBus=[],this.createImage=function(t,e){return new Promise((function(i,n){var o=null;window||r.canvas.createImage?(o=r.canvas&&r.canvas.createImage?r.canvas.createImage():new Image,e&&o.setAttribute("crossOrigin","Anonymous"),o.src=t,o.onload=function(){i({width:o.naturalWidth||o.width,height:o.naturalHeight||o.height,path:o,src:this.src})},o.onerror=function(t){n(t)}):n({fail:"getImageInfo fail",src:t})}))},this.options=t,Object.assign(this,t),this.ctx=(e=t.context,i={get:function(t,i){if("setFonts"===i)return function(t){var i=t.fontFamily,r=void 0===i?"sans-serif":i,o=t.fontSize,s=void 0===o?14:o,h=t.fontWeight,a=void 0===h?"normal":h,l=t.fontStyle,d=void 0===l?"normal":l;I==n.MP_TOUTIAO&&(a="bold"==a?"bold":"",d="italic"==d?"italic":""),e.font="".concat(d," ").concat(a," ").concat(Math.round(s),"px ").concat(r)};if(!e.draw||!e.setFillStyle){if("setFillStyle"===i)return function(t){e.fillStyle=t};if("setStrokeStyle"===i)return function(t){e.strokeStyle=t};if("setLineWidth"===i)return function(t){e.lineWidth=t};if("setLineCap"===i)return function(t){e.lineCap=t};if("setFontSize"===i)return function(t){e.font="".concat(String(t),"px sans-serif")};if("setGlobalAlpha"===i)return function(t){e.globalAlpha=t};if("setLineJoin"===i)return function(t){e.lineJoin=t};if("setTextAlign"===i)return function(t){e.textAlign=t};if("setMiterLimit"===i)return function(t){e.miterLimit=t};if("setShadow"===i)return function(t,i,n,r){e.shadowOffsetX=t,e.shadowOffsetY=i,e.shadowBlur=n,e.shadowColor=r};if("setTextBaseline"===i)return function(t){e.textBaseline=t};if("createCircularGradient"===i)return function(){};if("draw"===i)return function(){};if("function"==typeof e[i])return function(){for(var t=[],n=0;n=s||n==l&&o=s)&&(h=e.width/i.width);var d=i.width*h,c=i.height*h,f=r||[],u=f[0],p=f[1],g=W(u)?k(u,e.width):(e.width-d)*(P(u)?k(u,1):{left:0,center:.5,right:1}[u||"center"]),v=W(p)?k(p,e.height):(e.height-c)*(P(p)?k(p,1):{top:0,center:.5,bottom:1}[p||"center"]),y=function(t,e){return[(t-g)/h,(e-v)/h]},x=y(0,0),b=x[0],w=x[1],m=y(e.width,e.height),S=m[0],z=m[1],I=Math.max,M=Math.min;return{sx:I(b,0),sy:I(w,0),sw:M(S-b,i.width),sh:M(z-w,i.height),dx:I(g,0),dy:I(v,0),dw:M(d,e.width),dh:M(c,e.height)}}({objectFit:u,objectPosition:v},r.contentSize,t),o=i.sx,s=i.sy,h=i.sh,a=i.sw,l=i.dx,d=i.dy,c=i.dh,f=i.dw;I==n.MP_BAIDU?e.drawImage(t.src,l+m,d+S,f,c,o,s,a,h):e.drawImage(t.src,o,s,a,h,l+m,d+S,f,c)}else e.drawImage(t.src,m,S,b,w)},O=function(){e.restore(),L.drawView(r,o,!1,!0,!1),a(1)},T=function(t){B(t),O()},T(t),[2]}))}))}))];case 1:return a.sent(),[2]}}))}))},r.prototype.drawText=function(t,e,i,n){var r=this,o=this.ctx,s=e.borderSize,h=e.contentSize,a=e.left,l=e.top,d=h.width,c=h.height,f=h.left-s.left||0,u=h.top-s.top||0,p=i.color,g=i.lineHeight,v=i.fontSize,y=i.fontWeight,x=i.fontFamily,b=i.fontStyle,w=i.textIndent,m=void 0===w?0:w,S=i.textAlign,z=i.textStroke,I=i.verticalAlign,M=void 0===I?wt:I,B=i.backgroundColor,P=i.lineClamp,O=i.backgroundClip,T=i.textShadow,L=i.textDecoration;if(m=W(m)?m:0,this.drawView(e,i,O!=vt),g=k(g,v),t){o.save(),a+=f,l+=u;var R=n.fontHeight,F=n.descent,A=void 0===F?0:F,j=n.ascent,E=A+(void 0===j?0:j);switch(o.setFonts({fontFamily:x,fontSize:v,fontWeight:y,fontStyle:b}),o.setTextBaseline(wt),o.setTextAlign(S),O?this.setBackground(B,d,c,a,l):o.setFillStyle(p),S){case St:break;case zt:a+=.5*d;break;case It:a+=d}var H=n.lines*g,C=Math.ceil((c-H)/2);switch(C<0&&(C=0),M){case bt:break;case wt:l+=C;break;case mt:l+=2*C}var D=(g-R)/2,Y=g/2,$=function(t){var e=o.measureText(t),i=e.actualBoundingBoxDescent,n=void 0===i?0:i,r=e.actualBoundingBoxAscent;return M==bt?{fix:E?void 0===r?0:r:Y-D/2,lineY:E?0:D-D/2}:M==wt?{fix:E?Y+n/4:Y,lineY:E?0:D}:M==mt?{fix:E?g-n:Y+D/2,lineY:E?2*D:D+D/2}:{fix:0,height:0,lineY:0}},U=function(t,e,i){var r=t;switch(S){case St:r+=i;break;case zt:r=(t-=i/2)+i;break;case It:r=t,t-=i}if(L){o.setLineWidth(v/13),o.beginPath();var s=.1*n.fontHeight;/\bunderline\b/.test(L)&&(o.moveTo(t,e+n.fontHeight+s),o.lineTo(r,e+n.fontHeight+s)),/\boverline\b/.test(L)&&(o.moveTo(t,e-s),o.lineTo(r,e-s)),/\bline-through\b/.test(L)&&(o.moveTo(t,e+.5*n.fontHeight),o.lineTo(r,e+.5*n.fontHeight)),o.closePath(),o.setStrokeStyle(p),o.stroke()}},N=function(t,e,i){var n=function(){o.setLineWidth(z.width),o.setStrokeStyle(z.color),o.strokeText(t,e,i)},s="outset";z&&z.type!==s?(o.save(),r.setShadow({boxShadow:T}),o.fillText(t,e,i),o.restore(),n()):z&&z.type==s?(o.save(),r.setShadow({boxShadow:T}),n(),o.restore(),o.save(),o.fillText(t,e,i),o.restore()):(r.setShadow({boxShadow:T}),o.fillText(t,e,i))};if(!n.widths||1==n.widths.length&&n.widths[0].total+m<=h.width){var X=$(t),_=X.fix,q=void 0===_?0:_,G=X.lineY;return N(t,a+m,l+q),U(a+m,l+G,n&&n.widths&&n.widths[0].total||n.text),l+=g,o.restore(),void this.setBorder(e,i)}for(var V=l,J=a,Q="",Z=0,K=o.measureText("...").width,tt=n.widths,et=0;eth.width){Z>=P&&(Q+="…"),Z++,nt=0;var lt=$(Q);q=lt.fix,G=lt.lineY;N(Q,J,l+q),U(J,l+G,nt),l+=g,Q=""}else if(rt==it.length-1){et!=tt.length-1&&Z==P&&K+ntV+c||Z>P)break}}o.restore()}},r.prototype.source=function(t){return e(this,void 0,void 0,(function(){var e,n,r,o,s=this;return i(this,(function(i){switch(i.label){case 0:if(this.node=null,e=+new Date,"{}"==JSON.stringify(t))return[2];if(!t.type)for(n in t.type=xt,t.styles=t.styles||t.css||{},t)["views","children","type","css","styles"].includes(n)||(t.styles[n]=t[n],delete t[n]);return t.styles.boxSizing||(t.styles.boxSizing="border-box"),[4,this.create(t)];case 1:return(r=i.sent())?(o=r.layout()||{},this.size=o,this.node=r,this.onEffectFinished().then((function(t){return s.lifecycle("onEffectSuccess",t)})).catch((function(t){return s.lifecycle("onEffectFail",t)})),this.performance&&console.log("布局用时:"+(+new Date-e)+"ms"),[2,this.size]):[2,console.warn("no node")]}}))}))},r.prototype.getImageInfo=function(t){return this.imageBus[t]||(this.imageBus[t]=this.createImage(t,this.useCORS)),this.imageBus[t]},r.prototype.create=function(n,r){return e(this,void 0,void 0,(function(){function e(i,n,r){void 0===n&&(n={}),void 0===r&&(r=!0);var o=[];return i.forEach((function(i){var s=i.styles,h=void 0===s?{}:s,a=i.children,l=void 0===a?[]:a,d=i.text,c=void 0===d?"":d,f=i.type,u=void 0===f?"":f,p={};p=t(r?t({},n):{},h);var g={},v={},y={};Object.keys(p).map((function(t){if(t.includes("padding")||t.includes("margin")){var e=V(t,p[t]);Object.keys(e).map((function(t){t.includes("Left")?v[t]=e[t]:t.includes("Right")?y[t]=e[t]:g[t]=e[t]}))}}));if(p.textIndent&&(v.textIndent=p.textIndent,delete n.textIndent),""!==c){var x=Array.from(c);x.forEach((function(t,e){var i=Object.assign({},p,g);0===e?Object.assign(i,v):e==x.length-1&&Object.assign(i,y),delete i.padding,delete i.margin,o.push({type:"text",text:t,styles:i})}))}if(u==gt||u==yt)o.push(i);else if("block"===h.display&&l.length>0){var b=e(l,p,!1);i.children=b,i.flattened=!0,o.push(i)}else if(l.length>0){b=e(l,p,r);o=o.concat(b)}})),o}var o,s,h,a,l,d,c,f,u,p,g,v,y,b,w,m,S,z,I,M,B;return i(this,(function(i){switch(i.label){case 0:if(!n)return[2];if(n.styles||(n.styles=n.css||{}),o=n.type,s=o==gt,h=[vt,yt].includes(o),a="textBox"==o,l=n.styles||{},d=l.backgroundImage,c=l.display,s&&!n.src&&!n.url)return[2];if(c==x)return[2];if(h||a){if(f=n.children,!n.text&&(!f||f&&!f.length))return[2];f&&f.length&&!n.flattened&&(u=e(n.children),n.type="view",n.children=u)}if(!(s||n.type==xt&&d))return[3,4];p=s?n.src:"",g=/url\(['"]?(.*?)['"]?\)/.exec(d),d&&g&&g[1]&&(p=g[1]||""),i.label=1;case 1:return i.trys.push([1,3,,4]),[4,this.getImageInfo(p)];case 2:return v=i.sent(),y=v.width,b=v.height,!(w=v.path)&&s?[2]:(w&&(n.attributes=Object.assign(n.attributes||{},{width:y,height:b,path:w,src:w,naturalSrc:p})),[3,4]);case 3:return m=i.sent(),n.type!=xt?[2]:(this.lifecycle("onEffectFail",t(t({},m),{src:p})),[3,4]);case 4:if(this.count+=1,S=new pt(n,r,this.root,this.ctx),!(z=n.views||n.children))return[3,8];I=0,i.label=5;case 5:return I /^data:image\/(\w+);base64/.test(path); +export function sleep(delay) { + return new Promise(resolve => setTimeout(resolve, delay)) +} +let {platform, SDKVersion} = uni.getSystemInfoSync() +export const isPC = /windows|mac/.test(platform) +// 缓存图片 +let cache = {} +export function isNumber(value) { + return /^-?\d+(\.\d+)?$/.test(value); +} +export function toPx(value, baseSize, isDecimal = false) { + // 如果是数字 + if (typeof value === 'number') { + return value + } + // 如果是字符串数字 + if (isNumber(value)) { + return value * 1 + } + // 如果有单位 + if (typeof value === 'string') { + const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g + const results = reg.exec(value); + if (!value || !results) { + return 0; + } + const unit = results[3]; + value = parseFloat(value); + let res = 0; + if (unit === 'rpx') { + res = uni.upx2px(value); + } else if (unit === 'px') { + res = value * 1; + } else if (unit === '%') { + res = value * toPx(baseSize) / 100; + } else if (unit === 'em') { + res = value * toPx(baseSize || 14); + } + return isDecimal ? res.toFixed(2) * 1 : Math.round(res); + } + return 0 +} + +// 计算版本 +export function compareVersion(v1, v2) { + v1 = v1.split('.') + v2 = v2.split('.') + const len = Math.max(v1.length, v2.length) + while (v1.length < len) { + v1.push('0') + } + while (v2.length < len) { + v2.push('0') + } + for (let i = 0; i < len; i++) { + const num1 = parseInt(v1[i], 10) + const num2 = parseInt(v2[i], 10) + + if (num1 > num2) { + return 1 + } else if (num1 < num2) { + return -1 + } + } + return 0 +} + +function gte(version) { + // #ifdef MP-ALIPAY + SDKVersion = my.SDKVersion + // #endif + return compareVersion(SDKVersion, version) >= 0; +} +export function canIUseCanvas2d() { + // #ifdef MP-WEIXIN + return gte('2.9.2'); + // #endif + // #ifdef MP-ALIPAY + return gte('2.7.15'); + // #endif + // #ifdef MP-TOUTIAO + return gte('1.78.0'); + // #endif + return false +} + +// #ifdef MP +export const prefix = () => { + // #ifdef MP-TOUTIAO + return tt + // #endif + // #ifdef MP-WEIXIN + return wx + // #endif + // #ifdef MP-BAIDU + return swan + // #endif + // #ifdef MP-ALIPAY + return my + // #endif + // #ifdef MP-QQ + return qq + // #endif + // #ifdef MP-360 + return qh + // #endif +} +// #endif + + + +/** + * base64转路径 + * @param {Object} base64 + */ +export function base64ToPath(base64) { + const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || []; + + return new Promise((resolve, reject) => { + // #ifdef MP + const fs = uni.getFileSystemManager() + //自定义文件名 + if (!format) { + reject(new Error('ERROR_BASE64SRC_PARSE')) + } + const time = new Date().getTime(); + let pre = prefix() + // #ifdef MP-TOUTIAO + const filePath = `${pre.getEnvInfoSync().common.USER_DATA_PATH}/${time}.${format}` + // #endif + // #ifndef MP-TOUTIAO + const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}` + // #endif + fs.writeFile({ + filePath, + data: base64.split(',')[1], + encoding: 'base64', + success() { + resolve(filePath) + }, + fail(err) { + console.error(err) + reject(err) + } + }) + // #endif + + // #ifdef H5 + // mime类型 + let mimeString = base64.split(',')[0].split(':')[1].split(';')[0]; + //base64 解码 + let byteString = atob(base64.split(',')[1]); + //创建缓冲数组 + let arrayBuffer = new ArrayBuffer(byteString.length); + //创建视图 + let intArray = new Uint8Array(arrayBuffer); + for (let i = 0; i < byteString.length; i++) { + intArray[i] = byteString.charCodeAt(i); + } + resolve(URL.createObjectURL(new Blob([intArray], { + type: mimeString + }))) + // #endif + + // #ifdef APP-PLUS + const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now()) + bitmap.loadBase64Data(base64, () => { + if (!format) { + reject(new Error('ERROR_BASE64SRC_PARSE')) + } + const time = new Date().getTime(); + const filePath = `_doc/uniapp_temp/${time}.${format}` + bitmap.save(filePath, {}, + () => { + bitmap.clear() + resolve(filePath) + }, + (error) => { + bitmap.clear() + reject(error) + }) + }, (error) => { + bitmap.clear() + reject(error) + }) + // #endif + }) +} + +/** + * 路径转base64 + * @param {Object} string + */ +export function pathToBase64(path) { + if (/^data:/.test(path)) return path + return new Promise((resolve, reject) => { + // #ifdef H5 + let image = new Image(); + image.setAttribute("crossOrigin", 'Anonymous'); + image.onload = function() { + let canvas = document.createElement('canvas'); + canvas.width = this.naturalWidth; + canvas.height = this.naturalHeight; + canvas.getContext('2d').drawImage(image, 0, 0); + let result = canvas.toDataURL('image/png') + resolve(result); + canvas.height = canvas.width = 0 + } + image.src = path + '?v=' + Math.random() + image.onerror = (error) => { + reject(error); + }; + // #endif + + // #ifdef MP + if (uni.canIUse('getFileSystemManager')) { + uni.getFileSystemManager().readFile({ + filePath: path, + encoding: 'base64', + success: (res) => { + resolve('data:image/png;base64,' + res.data) + }, + fail: (error) => { + console.error({error, path}) + reject(error) + } + }) + } + // #endif + + // #ifdef APP-PLUS + plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => { + entry.file((file) => { + const fileReader = new plus.io.FileReader() + fileReader.onload = (data) => { + resolve(data.target.result) + } + fileReader.onerror = (error) => { + reject(error) + } + fileReader.readAsDataURL(file) + }, reject) + }, reject) + // #endif + }) +} + + + +export function getImageInfo(path, useCORS) { + const isCanvas2D = this && this.canvas && this.canvas.createImage + return new Promise(async (resolve, reject) => { + // let time = +new Date() + let src = path.replace(/^@\//,'/') + if (cache[path] && cache[path].errMsg) { + resolve(cache[path]) + } else { + try { + // #ifdef MP || APP-PLUS + if (isBase64(path) && (isCanvas2D ? isPC : true)) { + src = await base64ToPath(path) + } + // #endif + // #ifdef H5 + if(useCORS) { + src = await pathToBase64(path) + } + // #endif + } catch (error) { + reject({ + ...error, + src + }) + } + // #ifndef APP-NVUE + if(isCanvas2D && !isPC) { + const img = this.canvas.createImage() + img.onload = function() { + const image = { + path: img, + width: img.width, + height: img.height + } + cache[path] = image + resolve(cache[path]) + } + img.onerror = function(err) { + reject({err,path}) + } + img.src = src + return + } + // #endif + uni.getImageInfo({ + src, + success: (image) => { + const localReg = /^\.|^\/(?=[^\/])/; + // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO + image.path = localReg.test(src) ? `/${image.path}` : image.path; + // #endif + if(isCanvas2D) { + const img = this.canvas.createImage() + img.onload = function() { + image.path = img + cache[path] = image + resolve(cache[path]) + } + img.onerror = function(err) { + reject({err,path}) + } + img.src = src + return + } + // #ifdef APP-PLUS + // console.log('getImageInfo', +new Date() - time) + // ios 比较严格 可能需要设置跨域 + if(uni.getSystemInfoSync().osName == 'ios' && useCORS) { + pathToBase64(image.path).then(base64 => { + image.path = base64 + cache[path] = image + resolve(cache[path]) + }).catch(err => { + console.error({err, path}) + reject({err,path}) + }) + return + } + // #endif + cache[path] = image + resolve(cache[path]) + }, + fail(err) { + console.error({err, path}) + reject({err,path}) + } + }) + } + }) +} + + +// #ifdef APP-PLUS +const getLocalFilePath = (path) => { + if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path + .indexOf('_downloads') === 0) { + return path + } + if (path.indexOf('file://') === 0) { + return path + } + if (path.indexOf('/storage/emulated/0/') === 0) { + return path + } + if (path.indexOf('/') === 0) { + const localFilePath = plus.io.convertAbsoluteFileSystem(path) + if (localFilePath !== path) { + return localFilePath + } else { + path = path.substr(1) + } + } + return '_www/' + path +} +// #endif + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/components/lime-painter/lime-painter.vue b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/lime-painter/lime-painter.vue new file mode 100644 index 0000000..5427e6a --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/components/lime-painter/lime-painter.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/index.html b/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/index.html new file mode 100644 index 0000000..fdf884e --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/index.html @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/painter.js b/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/painter.js new file mode 100644 index 0000000..fc3e2c2 --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/hybrid/html/painter.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Painter={})}(this,(function(t){"use strict";var e=function(){return e=Object.assign||function(t){for(var e,i=1,n=arguments.length;i0&&r[r.length-1])||6!==o[0]&&2!==o[0])){s=0;continue}if(3===o[0]&&(!r||o[1]>r[0]&&o[1]=360&&(s-=360);s<0&&(s+=360);if(0===(s=Math.round(s)))return{x0:Math.round(e/2)+n,y0:i+r,x1:Math.round(e/2)+n,y1:r};if(180===s)return{x0:Math.round(e/2)+n,y0:r,x1:Math.round(e/2)+n,y1:i+r};if(90===s)return{x0:n,y0:Math.round(i/2)+r,x1:e+n,y1:Math.round(i/2)+r};if(270===s)return{x0:e+n,y0:Math.round(i/2)+r,x1:n,y1:Math.round(i/2)+r};var a=Math.round(180*Math.asin(e/Math.sqrt(Math.pow(e,2)+Math.pow(i,2)))/Math.PI);if(s===a)return{x0:n,y0:i+r,x1:e+n,y1:r};if(s===180-a)return{x0:n,y0:r,x1:e+n,y1:i+r};if(s===180+a)return{x0:e+n,y0:r,x1:n,y1:i+r};if(s===360-a)return{x0:e+n,y0:i+r,x1:n,y1:r};var h=0,c=0,f=0,d=0;if(s180-a&&s<180||s>180&&s<180+a||s>360-a){var l=s*Math.PI/180,u=s360-a?i/2:-i/2,p=Math.tan(l)*u,g=s180-a&&s<180?e/2-p:-e/2-p;h=-(f=p+(v=Math.pow(Math.sin(l),2)*g)),c=-(d=u+v/Math.tan(l))}if(s>a&&s<90||s>90&&s<90+a||s>180+a&&s<270||s>270&&s<360-a){var v;l=(90-s)*Math.PI/180,p=s>a&&s<90||s>90&&s<90+a?e/2:-e/2,u=Math.tan(l)*p,g=s>a&&s<90||s>270&&s<360-a?i/2-u:-i/2-u;h=-(f=p+(v=Math.pow(Math.sin(l),2)*g)/Math.tan(l)),c=-(d=u+v)}return h=Math.round(h+e/2)+n,c=Math.round(i/2-c)+r,f=Math.round(f+e/2)+n,d=Math.round(i/2-d)+r,{x0:h,y0:c,x1:f,y1:d}}(r,t,e,i,n),a=s.x0,h=s.y0,c=s.x1,f=s.y1,d=o.createLinearGradient(a,h,c,f),l=r.match(/linear-gradient\((.+)\)/)[1],u=X(l.substring(l.indexOf(",")+1)),p=0;pt.length)&&(e=t.length);for(var i=0,n=new Array(e);i=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Z(t){return"number"==typeof t}function K(t){return"auto"===t||null===t}function et(t){return/%$/.test(t)}var it=I,nt=z,rt=S,ot=M,st=B,at=O,ht=T;function ct(t){return t.replace(/-([a-z])/g,(function(t,e){return e.toUpperCase()}))}function ft(t,e){var i,n,r=function(t){var e=t.match(/([a-z]+)/)[1];return[e,ct(t.split(e)[1])]}(t),o=r[0],s=r[1],a=e.split(" ");if(s)return(i={})[o+s]=e,i;if(a.length&&!s){var h=a[0],c=a[1],f=a[2],l=a[3];return(n={})[o+d[0]]=h,n[o+d[1]]=c||h,n[o+d[2]]=f||h,n[o+d[3]]=l||c||h,n}}function dt(t){t=t.trim();for(var e=new Array,i="+",n="",r=t.length,o=0;o0;)"("===t[a+=1]&&(s+=1),")"===t[a]&&(s-=1);n="".concat(dt(t.slice(o+1,a))),o=a}if(isNaN(Number(t[o]))&&"."!==t[o]||o===r-1){var h=parseFloat(n);switch(i){case"+":e.push(h);break;case"-":e.push(-h);break;case"*":e.push(e.pop()*h);break;case"/":e.push(e.pop()/h)}i=t[o],n=""}}for(var c=0;e.length;)c+=e.pop();return c}var lt,ut=0,pt=function(){function t(){q(this,"elements",[]),q(this,"afterElements",[]),q(this,"beforeElements",[]),q(this,"ids",[]),q(this,"width",0),q(this,"height",0),q(this,"top",0),q(this,"left",0),q(this,"pre",null),q(this,"offsetX",0),q(this,"offsetY",0),ut++,this.id=ut}var e=t.prototype;return e.fixedBind=function(t,e){void 0===e&&(e=0),this.container=e?t.parent:t.root,this.container.fixedLine=this,this.fixedAdd(t)},e.fixedAdd=function(t){if(!this.ids.includes(t.id)){this.ids.push(t.id),this.elements.push(t);var e=t.computedStyle.zIndex;(void 0===e?0:e)>=0?this.afterElements.push(t):this.beforeElements.push(t),this.refreshLayout()}},e.bind=function(t){this.container=t.parent,this.container.line=null,this.container.lines?(this.container.lines.push(this),this.pre=this.getPreLine(),this.top=this.pre.top+this.pre.height,this.left=this.container.contentSize.left):(this.top=this.container.contentSize.top,this.left=this.container.contentSize.left,this.container.lines=[this]),this.isInline=t.isInline(),this.container.line=this,this.outerWidth=t.parent&&t.parent.contentSize.width?t.parent.contentSize.width:1/0,this.add(t)},e.getPreLine=function(){return this.container.lines[this.container.lines.length-2]},e.canIEnter=function(t){return!((100*t.offsetSize.width+100*this.width)/100>this.outerWidth)||(this.closeLine(),!1)},e.closeLine=function(){delete this.container.line},e.add=function(t){this.ids.includes(t.id)||(this.ids.push(t.id),this.elements.push(t),this.refreshWidthHeight(t))},e.refreshWidthHeight=function(t){t.offsetSize.height>this.height&&(this.height=t.offsetSize.height),this.width+=t.offsetSize.width||0,(this.container.lineMaxWidth||0)this[this.key.height]&&(this.container[this.key.lineMaxHeight]=this[this.key.height]=i),this[this.key.width]+=this.getWidth(t.offsetSize);var n=Math.min(this.getWidth(this),!this.getWidth(this.container.contentSize)&&1/0);(this.container[this.key.lineMaxWidth]||0)1)return 0;var e=t.style.alignSelf,i=this.getHeight(this.container.contentSize),n=i-this.getHeight(t.offsetSize);return e===f?n:e===h?n/2:"stretch"===e?(n&&t.name==S&&(t.style[this.key.width]=this.getWidth(t.offsetSize),t.style[this.key.height]=i,delete t.line,delete t.lines,t.getBoxWidthHeight()),0):0},r.layout=function(t,e){var i=this;this.refreshXAlign(),this.pre?(this.top=this.pre.top+this.pre.height+this.offsetY,this.left=e+this.offsetX):(this.top=Math.max(this.top,this.container.contentSize.top,t)+this.offsetY,this.left=Math.max(this.left,this.container.contentSize.left,e)+this.offsetX),this.elements.forEach((function(t,e){i.setIndent(t);var n=i.elements[e-1],r=i.getOffsetY(t);t.style[i.key.top]=i[i.key.top]+r,t.style[i.key.left]=n?n.offsetSize[i.key.left]+i.getWidth(n.offsetSize):i[i.key.left],t.getBoxPosition()}))},n}(pt),xt=I,wt=z,mt=S,St=k,zt=B,It=P,Mt=O,kt=T,Bt=0,Wt={left:null,top:null,width:null,height:null},Pt=new Map,Ot=function(){function t(t,e,i,n){var r=this;q(this,"id",Bt++),q(this,"style",{left:null,top:null,width:null,height:null}),q(this,"computedStyle",{}),q(this,"originStyle",{}),q(this,"children",{}),q(this,"layoutBox",G({},Wt)),q(this,"contentSize",G({},Wt)),q(this,"clientSize",G({},Wt)),q(this,"borderSize",G({},Wt)),q(this,"offsetSize",G({},Wt)),this.ctx=n,this.root=i,e&&(this.parent=e),this.name=t.type||t.name,this.attributes=this.getAttributes(t);var o=function(t,e){var i,n=["color","fontSize","lineHeight","verticalAlign","fontWeight","textAlign"],r=t.type,o=void 0===r?rt:r,s=t.styles,h=void 0===s?{}:s,c=(e||{}).computedStyle,f=Object.assign({},F);if([nt,it,ot].includes(o)&&!h.display&&(f.display=st),c)for(var l=0;l=0&&f<0,Y=h>=0&&l<0;return i==y[0]&&(this[i].left=t.left+s+g+j+(D?2*-f:0),this[i].top=t.top+h+b+W+(Y?2*-l:0),this[i].width=t.width+(this[i].widthAdd?0:C),this[i].height=t.height+(this[i].heightAdd?0:H),this[i].widthAdd=C,this[i].heightAdd=H),i==y[1]&&(this[i].left=t.left+s+j+(D<0?-f:0),this[i].top=t.top+h+W+(Y?-l:0),this[i].width=t.width+g+w,this[i].height=t.height+b+S),i==y[2]&&(this[i].left=t.left+s+j/2+(D<0?-f:0),this[i].top=t.top+h+W/2+(Y?-l:0),this[i].width=t.width+g+w+j/2+F/2,this[i].height=t.height+b+S+T/2+W/2),i==y[3]&&(this[i].left=t.left+(D<0?-f:0),this[i].top=t.top+(Y?-l:0),this[i].width=t.width+g+w+j+F+s+f,this[i].height=t.height+b+S+T+W+l+h),this[i]},e.layoutBoxUpdate=function(t,e,i,n){var r=this;if(void 0===i&&(i=-1),"border-box"==e.boxSizing){var o=e||{},s=o.border,a=(s=void 0===s?{}:s).borderWidth,h=void 0===a?0:a,c=o.borderTop,f=(c=void 0===c?{}:c).borderTopWidth,d=void 0===f?h:f,l=o.borderBottom,u=(l=void 0===l?{}:l).borderBottomWidth,p=void 0===u?h:u,g=o.borderRight,v=(g=void 0===g?{}:g).borderRightWidth,b=void 0===v?h:v,x=o.borderLeft,w=(x=void 0===x?{}:x).borderLeftWidth,m=void 0===w?h:w,S=o.padding,z=(S=void 0===S?{}:S).paddingTop,I=void 0===z?0:z,M=S.paddingRight,k=void 0===M?0:M,B=S.paddingBottom,W=void 0===B?0:B,P=S.paddingLeft,O=void 0===P?0:P;i||(t.width-=O+k+b+m),1!==i||n||(t.height-=I+W+d+p)}this.layoutBox&&(y.forEach((function(i){return r.layoutBox[i]=r.getOffsetSize(t,e,i)})),this.layoutBox=Object.assign({},this.layoutBox,this.layoutBox.borderSize))},e.getBoxPosition=function(){var t=this.computedStyle,e=this.fixedLine,i=this.lines,n=t.left,r=void 0===n?0:n,o=t.top,s=void 0===o?0:o,a=G({},this.contentSize,{left:r,top:s}),h=this.contentSize.top-this.offsetSize.top,c=this.contentSize.left-this.offsetSize.left;if(this.root.fixedLine&&!this.root.isDone){this.root.isDone=!0;for(var f,d=Q(this.root.fixedLine.elements);!(f=d()).done;){var l=f.value;l.setPosition(l,this.root.offsetSize),l.getBoxPosition()}}if(e)for(var u,p=Q(e.elements);!(u=p()).done;){var g=u.value,v=G({},this.borderSize,{left:r,top:s});g.setPosition(g,v);var y=this.borderSize.top-this.offsetSize.top,b=this.borderSize.left-this.offsetSize.left;g.style.left+=r+b,g.style.top+=s+y,g.getBoxPosition()}if(i)for(var x,w=Q(i);!(x=w()).done;){x.value.layout(a.top+h,a.left+c)}return this.layoutBoxUpdate(a,t),this.layoutBox},e.getBoxState=function(t,e){return this.isBlock(t)||this.isBlock(e)},e.isBlock=function(t){return void 0===t&&(t=this),t&&t.style.display==St},e.isFlex=function(t){return void 0===t&&(t=this),t&&t.style.display==It},e.isInFlow=function(){return!(this.isAbsolute||this.isFixed)},e.inFlexBox=function(t){return void 0===t&&(t=this),!!t.isInFlow()&&(!!t.parent&&(!(!t.parent||t.parent.style.display!==It)||void 0))},e.isInline=function(t){return void 0===t&&(t=this),t&&t.style.display==zt},e.contrastSize=function(t,e,i){var n=t;return i&&(n=Math.min(n,i)),e&&(n=Math.max(n,e)),n},e.measureText=function(t,e){var i=this.ctx.measureText(t),n=i.width,r=i.actualBoundingBoxAscent,o=i.actualBoundingBoxDescent;return{ascent:r,descent:o,width:n,fontHeight:r+o||.7*e+1}},e.getParentSize=function(t,e){if(void 0===t&&(t=this),void 0===e&&(e=!1),t&&t.parent){if(t.parent.contentSize.width)return t.parent.contentSize;if(e)return this.getParentSize(t.parent,e)}return null},e.getBoxWidthHeight=function(){var t=this,e=this.name,i=this.computedStyle,n=this.attributes,r=this.parent,o=void 0===r?{}:r,s=this.ctx,a=this.getChildren(),h=i.left,c=void 0===h?0:h,f=i.top,d=void 0===f?0:f,l=i.bottom,u=i.right,p=i.width,g=void 0===p?0:p,v=i.minWidth,y=i.maxWidth,b=i.minHeight,x=i.maxHeight,w=i.height,m=void 0===w?0:w,S=i.fontSize,z=i.fontWeight,I=i.fontFamily,M=i.fontStyle,k=i.position;i.textIndent;var B=i.lineClamp,W=i.lineHeight,P=i.padding,O=void 0===P?{}:P,T=i.margin,L=void 0===T?{}:T,R=i.border,F=(R=void 0===R?{}:R).borderWidth,A=void 0===F?0:F,E=i.borderRight,j=(E=void 0===E?{}:E).borderRightWidth,C=void 0===j?A:j,H=i.borderLeft,D=(H=void 0===H?{}:H).borderLeftWidth,Y=void 0===D?A:D,U=o.contentSize&&o.contentSize.width,N=o.contentSize&&o.contentSize.height;if(et(g)&&U&&(g=$(g,U)),et(g)&&!U&&(g=null),et(m)&&N&&(m=$(m,N)),et(m)&&!N&&(m=null),et(v)&&U&&(v=$(v,U)),et(y)&&U&&(y=$(y,U)),et(b)&&N&&(b=$(b,N)),et(x)&&N&&(x=$(x,N)),i.padding&&U)for(var _ in i.padding)Object.hasOwnProperty.call(O,_)&&(O[_]=$(O[_],U));var X=O.paddingRight,q=void 0===X?0:X,G=O.paddingLeft,V=void 0===G?0:G;if(i.margin&&[L.marginLeft,L.marginRight].includes("auto"))if(g){var J=U&&U-g-q-V-Y-C||0;L.marginLeft==L.marginRight?L.marginLeft=L.marginRight=J/2:K(L.marginLeft)?L.marginLeft=J:L.marginRight=J}else L.marginLeft=L.marginRight=0;var Q=L.marginRight,Z=void 0===Q?0:Q,tt=L.marginLeft,it={width:g,height:m,left:0,top:0},nt=V+q+Y+C+(void 0===tt?0:tt)+Z;if(this.offsetWidth=nt,e==wt&&!this.attributes.widths){var rt=n.text||"";s.save(),s.setFonts({fontFamily:I,fontSize:S,fontWeight:z,fontStyle:M}),rt.length,"\n"==rt&&(rt="",this.isBr=!0),(""+rt).split("\n").map((function(e){var i=Array.from(e).map((function(e){var i=""+(/^[\u4e00-\u9fa5]+$/.test(e)?"cn":e)+I+S+z+M,n=Pt.get(i);if(n)return{width:n,text:e};var r=t.measureText(e,S).width;return Pt.set(i,r),{width:r,text:e}})),n=t.measureText(e,S),r=n.fontHeight,o=n.ascent,s=n.descent;t.attributes.fontHeight=r,t.attributes.ascent=o,t.attributes.descent=s,t.attributes.widths||(t.attributes.widths=[]),t.attributes.widths.push({widths:i,total:i.reduce((function(t,e){return t+e.width}),0)})})),s.restore()}if(e==xt&&null==g){var ot=n.width,st=n.height;it.width=this.contrastSize(Math.round(ot*m/st)||0,v,y),this.layoutBoxUpdate(it,i,0)}if(e==wt&&null==g){var at=this.attributes.widths,ht=Math.max.apply(Math,at.map((function(t){return t.total})));if(o&&U>0&&(ht>U||this.isBlock(this))&&!this.isAbsolute&&!this.isFixed)ht=U;it.width=this.contrastSize(ht,v,y),this.layoutBoxUpdate(it,i,0)}if(e==wt&&(o.style.flex||!this.attributes.lines)){var ct=this.attributes.widths.length;this.attributes.widths.forEach((function(t){return t.widths.reduce((function(t,e,i){return t+e.width>it.width?(ct++,e.width):t+e.width}),0)})),ct=B&&ct>B?B:ct,this.attributes.lines=ct}if(e==xt&&null==m){var ft=n.width,dt=n.height;n.text,it.height=this.contrastSize($(it.width*dt/ft)||0,b,x),this.layoutBoxUpdate(it,i,1)}e==wt&&null==m&&(W=$(W,S),it.height=this.contrastSize($(this.attributes.lines*W),b,x),this.layoutBoxUpdate(it,i,1,!0)),!g&&o&&o.children&&U&&(!this.isFlex(o)||o.isFlexCalc)&&([mt,wt].includes(e)&&this.isFlex()||e==mt&&this.isBlock(this)&&this.isInFlow())&&(it.width=this.contrastSize(U-(o.isFlexCalc?0:nt),v,y),this.layoutBoxUpdate(it,i)),g&&!et(g)&&(it.width=this.contrastSize(g,v,y),this.layoutBoxUpdate(it,i,0)),m&&!et(m)&&(it.height=this.contrastSize(it.height,b,x),this.layoutBoxUpdate(it,i,1));var lt=0;if(a.length){var ut=null,gt=!1;a.forEach((function(e,n){e.getBoxWidthHeight();var r=a[n+1];if(r&&r.isInFlow()&&(e.next=r),!t.line||!t.line.ids.includes(e.id))if(e.isInFlow()&&!e.inFlexBox()){var o=t.getBoxState(ut,e);if(e.isBr)return gt=!0;t.line&&t.line.canIEnter(e)&&!o&&!gt?t.line.add(e):(gt=!1,(new pt).bind(e)),ut=e}else e.inFlexBox()?t.line&&(t.line.canIEnter(e)||"nowrap"==i.flexWrap)?t.line.add(e):(new bt).bind(e):e.isFixed?t.root.fixedLine?t.root.fixedLine.fixedAdd(e):(new pt).fixedBind(e):t.fixedLine?t.fixedLine.fixedAdd(e):(new pt).fixedBind(e,1)})),this.lines&&(lt=this.lines.reduce((function(t,e){return t+e.height}),0))}var vt=0,yt=0;if(!g&&(this.isAbsolute||this.isFixed)&&U){var St=k==Mt?U:this.root.width,zt=St-(et(c)?$(c,St):c)-(et(u)?$(u,St):u);vt=i.left?zt:this.lineMaxWidth}if(!m&&(null!=d?d:this.isAbsolute||this.isFixed&&N)){var It=k==Mt?N:this.root.height,kt=It-(et(d)?$(d,It):d)-(et(l)?$(l,It):l);yt=i.top?kt:0}if(g&&!et(g)||it.width||(it.width=vt||this.contrastSize((this.isBlock(this)&&!this.isInFlow()?U||o.lineMaxWidth:this.lineMaxWidth)||this.lineMaxWidth,v,y),this.layoutBoxUpdate(it,i,0)),m||!lt&&!yt||(it.height=yt||this.contrastSize(lt,b,x),this.layoutBoxUpdate(it,i)),i.borderRadius&&this.borderSize&&this.borderSize.width)for(var _ in i.borderRadius)Object.hasOwnProperty.call(i.borderRadius,_)&&(i.borderRadius[_]=$(i.borderRadius[_],this.borderSize.width));return this.layoutBox},e.layout=function(){return this.getBoxWidthHeight(),this.root.offsetSize=this.offsetSize,this.root.contentSize=this.contentSize,this.getBoxPosition(),this.offsetSize},t}(),Tt=function(){var t,e,i,n,r,o,s=[0,11,15,19,23,27,31,16,18,20,22,24,26,28,20,22,24,24,26,28,28,22,24,24,26,26,28,28,24,24,26,26,26,28,28,24,26,26,26,28,28],a=[3220,1468,2713,1235,3062,1890,2119,1549,2344,2936,1117,2583,1330,2470,1667,2249,2028,3780,481,4011,142,3098,831,3445,592,2517,1776,2234,1951,2827,1070,2660,1345,3177],h=[30660,29427,32170,30877,26159,25368,27713,26998,21522,20773,24188,23371,17913,16590,20375,19104,13663,12392,16177,14854,9396,8579,11994,11245,5769,5054,7399,6608,1890,597,3340,2107],c=[1,0,19,7,1,0,16,10,1,0,13,13,1,0,9,17,1,0,34,10,1,0,28,16,1,0,22,22,1,0,16,28,1,0,55,15,1,0,44,26,2,0,17,18,2,0,13,22,1,0,80,20,2,0,32,18,2,0,24,26,4,0,9,16,1,0,108,26,2,0,43,24,2,2,15,18,2,2,11,22,2,0,68,18,4,0,27,16,4,0,19,24,4,0,15,28,2,0,78,20,4,0,31,18,2,4,14,18,4,1,13,26,2,0,97,24,2,2,38,22,4,2,18,22,4,2,14,26,2,0,116,30,3,2,36,22,4,4,16,20,4,4,12,24,2,2,68,18,4,1,43,26,6,2,19,24,6,2,15,28,4,0,81,20,1,4,50,30,4,4,22,28,3,8,12,24,2,2,92,24,6,2,36,22,4,6,20,26,7,4,14,28,4,0,107,26,8,1,37,22,8,4,20,24,12,4,11,22,3,1,115,30,4,5,40,24,11,5,16,20,11,5,12,24,5,1,87,22,5,5,41,24,5,7,24,30,11,7,12,24,5,1,98,24,7,3,45,28,15,2,19,24,3,13,15,30,1,5,107,28,10,1,46,28,1,15,22,28,2,17,14,28,5,1,120,30,9,4,43,26,17,1,22,28,2,19,14,28,3,4,113,28,3,11,44,26,17,4,21,26,9,16,13,26,3,5,107,28,3,13,41,26,15,5,24,30,15,10,15,28,4,4,116,28,17,0,42,26,17,6,22,28,19,6,16,30,2,7,111,28,17,0,46,28,7,16,24,30,34,0,13,24,4,5,121,30,4,14,47,28,11,14,24,30,16,14,15,30,6,4,117,30,6,14,45,28,11,16,24,30,30,2,16,30,8,4,106,26,8,13,47,28,7,22,24,30,22,13,15,30,10,2,114,28,19,4,46,28,28,6,22,28,33,4,16,30,8,4,122,30,22,3,45,28,8,26,23,30,12,28,15,30,3,10,117,30,3,23,45,28,4,31,24,30,11,31,15,30,7,7,116,30,21,7,45,28,1,37,23,30,19,26,15,30,5,10,115,30,19,10,47,28,15,25,24,30,23,25,15,30,13,3,115,30,2,29,46,28,42,1,24,30,23,28,15,30,17,0,115,30,10,23,46,28,10,35,24,30,19,35,15,30,17,1,115,30,14,21,46,28,29,19,24,30,11,46,15,30,13,6,115,30,14,23,46,28,44,7,24,30,59,1,16,30,12,7,121,30,12,26,47,28,39,14,24,30,22,41,15,30,6,14,121,30,6,34,47,28,46,10,24,30,2,64,15,30,17,4,122,30,29,14,46,28,49,10,24,30,24,46,15,30,4,18,122,30,13,32,46,28,48,14,24,30,42,32,15,30,20,4,117,30,40,7,47,28,43,22,24,30,10,67,15,30,19,6,118,30,18,31,47,28,34,34,24,30,20,61,15,30],f=[255,0,1,25,2,50,26,198,3,223,51,238,27,104,199,75,4,100,224,14,52,141,239,129,28,193,105,248,200,8,76,113,5,138,101,47,225,36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,201,154,9,120,77,228,114,166,6,191,139,98,102,221,48,253,226,152,37,179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,243,167,87,7,112,192,247,140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175],d=[1,2,4,8,16,32,64,128,29,58,116,232,205,135,19,38,76,152,45,90,180,117,234,201,143,3,6,12,24,48,96,192,157,39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,140,5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141,7,14,28,56,112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,69,138,9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,88,176,125,250,233,207,131,27,54,108,216,173,71,142,0],l=[],u=[],p=[],g=[],v=[],y=2;function b(t,e){var i;t>e&&(i=t,t=e,e=i),i=e,i*=e,i+=e,i>>=1,g[i+=t]=1}function x(t,i){var n;for(p[t+e*i]=1,n=-2;n<2;n++)p[t+n+e*(i-2)]=1,p[t-2+e*(i+n+1)]=1,p[t+2+e*(i+n)]=1,p[t+n+1+e*(i+2)]=1;for(n=0;n<2;n++)b(t-1,i+n),b(t+1,i-n),b(t-n,i-1),b(t+n,i+1)}function w(t){for(;t>=255;)t=((t-=255)>>8)+(255&t);return t}var m=[];function S(t,e,i,n){var r,o,s;for(r=0;re&&(i=t,t=e,e=i),i=e,i+=e*e,i>>=1,g[i+=t]}function I(t){var i,n,r,o;switch(t){case 0:for(n=0;n>1&1,i=0;i=5&&(i+=3+v[e]-5);for(e=3;et||3*v[e-3]>=4*v[e]||3*v[e+3]>=4*v[e])&&(i+=40);return i}function k(){var t,i,n,r,o,s=0,a=0;for(i=0;ie*e;)h-=e*e,c++;for(s+=10*c,t=0;t1)for(P=s[t],B=e-7;;){for(M=e-7;M>P-3&&(x(M,B),!(M6)for(P=a[t-7],W=17,M=0;M<6;M++)for(B=0;B<3;B++,W--)1&(W>11?t>>W-12:P>>W)?(p[5-M+e*(2-B+e-11)]=1,p[2-B+e-11+e*(5-M)]=1):(b(5-M,2-B+e-11),b(2-B+e-11,5-M));for(B=0;B=(M=r*(i+n)+n)-2&&(O=M-2,t>9&&O--),T=O,t>9){for(l[T+2]=0,l[T+3]=0;T--;)P=l[T],l[T+3]|=255&P<<4,l[T+2]=P>>4;l[2]|=255&O<<4,l[1]=O>>4,l[0]=64|O>>12}else{for(l[T+1]=0,l[T+2]=0;T--;)P=l[T],l[T+2]|=255&P<<4,l[T+1]=P>>4;l[1]|=255&O<<4,l[0]=64|O>>4}for(T=O+3-(t<10);T0;L--)m[L]=m[L]?m[L-1]^d[w(f[m[L]]+T)]:m[L-1];m[0]=d[w(f[m[0]]+T)]}for(T=0;T<=o;T++)m[T]=f[m[T]];for(W=M,B=0,T=0;T>=1)1&B&&(p[e-1-W+8*e]=1,W<6?p[8+e*W]=1:p[8+e*(W+1)]=1);for(W=0;W<7;W++,B>>=1)1&B&&(p[8+e*(e-7+W)]=1,W?p[6-W+8*e]=1:p[7+8*e]=1);return p}(v)},utf16to8:function(t){var e,i,n,r;for(e="",n=t.length,i=0;i=1&&r<=127?e+=t.charAt(i):r>2047?(e+=String.fromCharCode(224|r>>12&15),e+=String.fromCharCode(128|r>>6&63),e+=String.fromCharCode(128|r>>0&63)):(e+=String.fromCharCode(192|r>>6&31),e+=String.fromCharCode(128|r>>0&63));return e},draw:function(t,i,n,r,o){i.drawView(n,r);var s=i.ctx,a=n.contentSize,h=a.width,c=a.height,f=a.left,d=a.top;r.borderRadius,r.backgroundColor;var l=r.color,u=void 0===l?"#000000":l;r.border,n.contentSize.left,n.borderSize.left,n.contentSize.top,n.borderSize.top;if(y=o||y,s){s.save(),i.setOpacity(r),i.setTransform(n,r);var p=Math.min(h,c);t=this.utf16to8(t);var g=this.getFrame(t),v=p/e;s.setFillStyle(u);for(var b=0;b=s||n==c&&o=s)&&(a=e.width/i.width);var f=i.width*a,d=i.height*a,l=r||[],u=l[0],p=l[1],g=Y(u)?$(u,e.width):(e.width-f)*(U(u)?$(u,1):{left:0,center:.5,right:1}[u||"center"]),v=Y(p)?$(p,e.height):(e.height-d)*(U(p)?$(p,1):{top:0,center:.5,bottom:1}[p||"center"]),y=function(t,e){return[(t-g)/a,(e-v)/a]},b=y(0,0),x=b[0],w=b[1],m=y(e.width,e.height),S=m[0],z=m[1],I=Math.max,M=Math.min;return{sx:I(x,0),sy:I(w,0),sw:M(S-x,i.width),sh:M(z-w,i.height),dx:I(g,0),dy:I(v,0),dw:M(f,e.width),dh:M(d,e.height)}}({objectFit:u,objectPosition:v},e.contentSize,t),o=n.sx,s=n.sy,a=n.sh,h=n.sw,c=n.dx,f=n.dy,d=n.dh,l=n.dw;C==r.MP_BAIDU?i.drawImage(t.src,c+m,f+S,l,d,o,s,h,a):i.drawImage(t.src,o,s,h,a,c+m,f+S,l,d)}else i.drawImage(t.src,m,S,x,w)},k=function(){i.restore(),W.drawView(e,o,!1,!0,!1),h(1)},B=function(t){M(t),k()},B(t),[2]}))}))}))];case 1:return h.sent(),[2]}}))}))},t.prototype.drawText=function(t,e,i,n){var r=this,o=this.ctx,s=e.borderSize,a=e.contentSize,h=e.left,c=e.top,f=a.width,d=a.height,l=a.left-s.left||0,u=a.top-s.top||0,p=i.color,g=i.lineHeight,v=i.fontSize,y=i.fontWeight,b=i.fontFamily,x=i.fontStyle,w=i.textIndent,m=void 0===w?0:w,S=i.textAlign,z=i.textStroke,I=i.verticalAlign,M=void 0===I?jt:I,k=i.backgroundColor,B=i.lineClamp,W=i.backgroundClip,P=i.textShadow,O=i.textDecoration;if(m=Y(m)?m:0,this.drawView(e,i,W!=Rt),g=$(g,v),t){o.save(),h+=l,c+=u;var T=n.fontHeight,L=n.descent,R=void 0===L?0:L,F=n.ascent,A=R+(void 0===F?0:F);switch(o.setFonts({fontFamily:b,fontSize:v,fontWeight:y,fontStyle:x}),o.setTextBaseline(jt),o.setTextAlign(S),W?this.setBackground(k,f,d,h,c):o.setFillStyle(p),S){case Ht:break;case Dt:h+=.5*f;break;case Yt:h+=f}var E=n.lines*g,j=Math.ceil((d-E)/2);switch(j<0&&(j=0),M){case Et:break;case jt:c+=j;break;case Ct:c+=2*j}var C=(g-T)/2,H=g/2,D=function(t){var e=o.measureText(t),i=e.actualBoundingBoxDescent,n=void 0===i?0:i,r=e.actualBoundingBoxAscent;return M==Et?{fix:A?void 0===r?0:r:H-C/2,lineY:A?0:C-C/2}:M==jt?{fix:A?H+n/4:H,lineY:A?0:C}:M==Ct?{fix:A?g-n:H+C/2,lineY:A?2*C:C+C/2}:{fix:0,height:0,lineY:0}},U=function(t,e,i){var r=t;switch(S){case Ht:r+=i;break;case Dt:r=(t-=i/2)+i;break;case Yt:r=t,t-=i}if(O){o.setLineWidth(v/13),o.beginPath();var s=.1*n.fontHeight;/\bunderline\b/.test(O)&&(o.moveTo(t,e+n.fontHeight+s),o.lineTo(r,e+n.fontHeight+s)),/\boverline\b/.test(O)&&(o.moveTo(t,e-s),o.lineTo(r,e-s)),/\bline-through\b/.test(O)&&(o.moveTo(t,e+.5*n.fontHeight),o.lineTo(r,e+.5*n.fontHeight)),o.closePath(),o.setStrokeStyle(p),o.stroke()}},N=function(t,e,i){var n=function(){o.setLineWidth(z.width),o.setStrokeStyle(z.color),o.strokeText(t,e,i)},s="outset";z&&z.type!==s?(o.save(),r.setShadow({boxShadow:P}),o.fillText(t,e,i),o.restore(),n()):z&&z.type==s?(o.save(),r.setShadow({boxShadow:P}),n(),o.restore(),o.save(),o.fillText(t,e,i),o.restore()):(r.setShadow({boxShadow:P}),o.fillText(t,e,i))};if(!n.widths||1==n.widths.length&&n.widths[0].total+m<=a.width){var _=D(t),X=_.fix,q=void 0===X?0:X,G=_.lineY;return N(t,h+m,c+q),U(h+m,c+G,n&&n.widths&&n.widths[0].total||n.text),c+=g,o.restore(),void this.setBorder(e,i)}for(var V=c,J=h,Q="",Z=0,K=o.measureText("...").width,tt=n.widths,et=0;eta.width){Z>=B&&(Q+="…"),Z++,nt=0;var ct=D(Q);q=ct.fix,G=ct.lineY;N(Q,J,c+q),U(J,c+G,nt),c+=g,Q=""}else if(rt==it.length-1){et!=tt.length-1&&Z==B&&K+ntV+d||Z>B)break}}o.restore()}},t.prototype.source=function(t){return i(this,void 0,void 0,(function(){var e,i,r,o,s=this;return n(this,(function(n){switch(n.label){case 0:if(this.node=null,e=+new Date,"{}"==JSON.stringify(t))return[2];if(t.styles=t.styles||t.css||{},!t.type)for(i in t.type=At,t)["views","children","type","css","styles"].includes(i)||(t.styles[i]=t[i],delete t[i]);return t.styles.boxSizing||(t.styles.boxSizing="border-box"),[4,this.create(t)];case 1:return(r=n.sent())?(o=r.layout()||{},this.size=o,this.node=r,this.onEffectFinished().then((function(t){return s.lifecycle("onEffectSuccess",t)})).catch((function(t){return s.lifecycle("onEffectFail",t)})),this.performance&&console.log("布局用时:"+(+new Date-e)+"ms"),[2,this.size]):[2,console.warn("no node")]}}))}))},t.prototype.getImageInfo=function(t){return this.imageBus[t]||(this.imageBus[t]=this.createImage(t,this.useCORS)),this.imageBus[t]},t.prototype.create=function(t,r){return i(this,void 0,void 0,(function(){function i(t,n,r){void 0===n&&(n={}),void 0===r&&(r=!0);var o=[];return t.forEach((function(t){var s=t.styles,a=void 0===s?{}:s,h=t.css,c=void 0===h?{}:h,f=t.children,d=void 0===f?[]:f,l=t.views,u=void 0===l?[]:l,p=t.text,g=void 0===p?"":p,v=t.type,y=void 0===v?"":v;!d&&u&&(t.children=d=u);var b={};b=e(e(r?e({},n):{},a),c);var x={},w={},m={};Object.keys(b).map((function(t){if(t.includes("padding")||t.includes("margin")){var e=ft(t,b[t]);Object.keys(e).map((function(t){t.includes("Left")?w[t]=e[t]:t.includes("Right")?m[t]=e[t]:x[t]=e[t]}))}}));if(b.textIndent&&(w.textIndent=b.textIndent,delete n.textIndent),""!==g){var S=Array.from(g);S.forEach((function(t,e){var i=Object.assign({},b,x);0===e?Object.assign(i,w):e==S.length-1&&Object.assign(i,m),delete i.padding,delete i.margin,o.push({type:"text",text:t,styles:i})}))}if(y==Lt||y==Ft)o.push(t);else if("block"===a.display&&d.length>0){var z=i(d,b,!1);t.children=z,t.flattened=!0,o.push(t)}else if(d.length>0){z=i(d,b,r);o=o.concat(z)}})),o}var o,s,a,h,c,f,d,l,u,p,g,v,y,b,x,w,m,S,z,I,M,k,B,P;return n(this,(function(n){switch(n.label){case 0:if(!t)return[2];if(t.styles||(t.styles=t.css||{}),o=t.type,s=t.show,a=void 0===s||s,h=o==Lt,c=[Rt,Ft].includes(o),f="textBox"==o,d=t.styles||{},l=d.backgroundImage,u=d.display,h&&!t.src&&!t.url)return[2];if(u==W||!a)return[2];if(c||f){if(p=t.children,g=t.views,!p&&g&&(t.children=p=g),!t.text&&(!p||p&&!p.length))return[2];p&&p.length&&!t.flattened&&(v=i(t.children||t.views),t.type="view",t.children=v)}if(!(h||t.type==At&&l))return[3,4];y=h?t.src:"",b=/url\(['"]?(.*?)['"]?\)/.exec(l),l&&b&&b[1]&&(y=b[1]||""),n.label=1;case 1:return n.trys.push([1,3,,4]),[4,this.getImageInfo(y)];case 2:return x=n.sent(),w=x.width,m=x.height,!(S=x.path)&&h?[2]:(S&&(t.attributes=Object.assign(t.attributes||{},{width:w,height:m,path:S,src:S,naturalSrc:y})),[3,4]);case 3:return z=n.sent(),t.type!=At?[2]:(this.lifecycle("onEffectFail",e(e({},z),{src:y})),[3,4]);case 4:if(this.count+=1,I=new Ot(t,r,this.root,this.ctx),!(M=t.children||t.views))return[3,8];k=0,n.label=5;case 5:return k0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;r("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("redirectTo",{url:encodeURI(n)})},getEnv:function(e){o()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};r("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var v=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);for(var E,b=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},h=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(v)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y\s]+))?)*)\s*(\/?)>/; +var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; +var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5 + +var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5 +// fixed by xxx 将 ins 标签从块级名单中移除 + +var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5 + +var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open +// (and which close themselves) + +var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled" + +var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything) + +var special = makeMap('script,style'); +function HTMLParser(html, handler) { + var index; + var chars; + var match; + var stack = []; + var last = html; + + stack.last = function () { + return this[this.length - 1]; + }; + + while (html) { + chars = true; // Make sure we're not in a script or style element + + if (!stack.last() || !special[stack.last()]) { + // Comment + if (html.indexOf(''); + + if (index >= 0) { + if (handler.comment) { + handler.comment(html.substring(4, index)); + } + + html = html.substring(index + 3); + chars = false; + } // end tag + + } else if (html.indexOf(']*>'), function (all, text) { + text = text.replace(/|/g, '$1$2'); + + if (handler.chars) { + handler.chars(text); + } + + return ''; + }); + parseEndTag('', stack.last()); + } + + if (html == last) { + throw 'Parse Error: ' + html; + } + + last = html; + } // Clean up any remaining tags + + + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = tagName.toLowerCase(); + if (block[tagName]) { + while (stack.last() && inline[stack.last()]) { + parseEndTag('', stack.last()); + } + } + + if (closeSelf[tagName] && stack.last() == tagName) { + parseEndTag('', tagName); + } + + unary = empty[tagName] || !!unary; + + if (!unary) { + stack.push(tagName); + } + + if (handler.start) { + var attrs = []; + rest.replace(attr, function (match, name) { + var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : ''; + attrs.push({ + name: name, + value: value, + escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // " + + }); + }); + + if (handler.start) { + handler.start(tagName, attrs, unary); + } + } + } + + function parseEndTag(tag, tagName) { + // If no tag name is provided, clean shop + if (!tagName) { + var pos = 0; + } // Find the closest opened tag of the same type + else { + for (var pos = stack.length - 1; pos >= 0; pos--) { + if (stack[pos] == tagName) { + break; + } + } + } + + if (pos >= 0) { + // Close all the open elements, up the stack + for (var i = stack.length - 1; i >= pos; i--) { + if (handler.end) { + handler.end(stack[i]); + } + } // Remove the open elements from the stack + + + stack.length = pos; + } + } +} + +function makeMap(str) { + var obj = {}; + var items = str.split(','); + + for (var i = 0; i < items.length; i++) { + obj[items[i]] = true; + } + + return obj; +} + +function removeDOCTYPE(html) { + return html.replace(/<\?xml.*\?>\n/, '').replace(/\n/, '').replace(/\n/, ''); +} + +function parseAttrs(attrs) { + return attrs.reduce(function (pre, attr) { + var value = attr.value; + var name = attr.name; + if (pre[name]) { + pre[name] = pre[name] + " " + value; + } else { + pre[name] = value; + } + + return pre; + }, {}); +} +function convertStyleStringToJSON(styleString) { + var styles = styleString.split(";"); // 通过分号将样式字符串分割为多个样式声明 + var result = {}; + + styles.forEach(function(style) { + var styleParts = style.split(":"); // 通过冒号将样式声明分割为属性和值 + var property = styleParts[0].trim(); + var value = styleParts[1] && styleParts[1].trim(); + + if (property && value) { + result[property] = value; // 将属性和值添加到结果对象中 + } + }); + + return result; +} +function parseHtml(html) { + html = removeDOCTYPE(html); + var stacks = []; + var results = { + node: 'root', + children: [] + }; + HTMLParser(html, { + start: function start(tag, attrs, unary) { + var node = { + name: tag + }; + + if (attrs.length !== 0) { + node.attrs = parseAttrs(attrs); + node.styles = node.attrs.style ? convertStyleStringToJSON(node.attrs.style) : {} + } + + if(!node.type) { + if(inline[node.name] && node.name !== 'img' ) { + node.type = 'text'; + if(node.name == 'br') { + node.text = '\n' + } else if(node.name == 'strong'){ + node.styles.fontWeight = 'bold' + } + } else if(node.name == 'img'){ + node.type = 'image' + node.src = node.attrs.src + } else { + node.type = 'view' + if(['h1','h2','h3','h4','h5','h6'].includes(node.name)) { + node.styles.fontWeight = 'bold' + } + } + } + if (unary) { + var parent = stacks[0] || results; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } else { + stacks.unshift(node); + } + }, + end: function end(tag) { + var node = stacks.shift(); + if (node.name !== tag) console.error('invalid state: mismatch end tag'); + if (stacks.length === 0) { + results.children.push(node); + } else { + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + parent.children.push(node); + } + const isTextBox = node.children && node.children.length > 1 && node.children.every(child => { + return ['text','image'].includes(child.type) + }) + if(isTextBox) { + node.type = 'textBox' + } + }, + chars: function chars(text) { + var node = { + type: 'text', + text: text + }; + + if (stacks.length === 0) { + results.children.push(node); + } else { + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } + }, + comment: function comment(text) { + var node = { + node: 'comment', + text: text + }; + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } + }); + return results.children; +} + +export default parseHtml; \ No newline at end of file diff --git a/yudao-mall-uniapp-master/uni_modules/lime-painter/readme.md b/yudao-mall-uniapp-master/uni_modules/lime-painter/readme.md new file mode 100644 index 0000000..9cfdb6d --- /dev/null +++ b/yudao-mall-uniapp-master/uni_modules/lime-painter/readme.md @@ -0,0 +1,963 @@ +# Painter 画板 测试版 + +> uniapp 海报画板,更优雅的海报生成方案 +> [查看更多 站点 1](https://limeui.qcoon.cn/#/painter) +> [查看更多 站点 2](http://liangei.gitee.io/limeui/#/painter) +> Q 群:1169785031 + +## 平台兼容 + +| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | +| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | +| √ | √ | √ | 未测 | √ | √ | √ | + +## 安装 +在市场导入**[海报画板](https://ext.dcloud.net.cn/plugin?id=2389)uni_modules**版本的即可,无需`import` + +## 代码演示 + +### 插件demo +- lime-painter 为 demo +- 位于 uni_modules/lime-painter/components/lime-painter +- 导入插件后直接使用可查看demo +```vue + +``` + + +### 基本用法 + +- 插件提供 JSON 及 Template 的方式绘制海报 +- 参考 css 块状流布局模拟 css schema。 +- 另外flex布局还不是成完善,请谨慎使用,普通的流布局我觉得已经够用了。 + +#### 方式一 Template + +- 提供`l-painter-view`、`l-painter-text`、`l-painter-image`、`l-painter-qrcode`四种类型组件 +- 通过 `css` 属性绘制样式,与 style 使用方式保持一致。 +```html + + //如果使用Template出现顺序错乱,可使用`template` 等所有变量完成再显示 +